Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split loading and generating ECC private key c'tors #4437

Merged
merged 2 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/examples/ecc_raw_private_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ int main() {
const auto private_scalar_bytes =
Botan::hex_decode("D2AC61C35CAEE918E47B0BD5E61DA9B3A5C2964AB317647DEF6DFC042A06C829");

Botan::Null_RNG null_rng;
const auto domain = Botan::EC_Group::from_name(curve_name);
const auto private_scalar = Botan::BigInt(private_scalar_bytes);

// This loads the private scalar into an ECDH_PrivateKey. Creating an
// ECDSA_PrivateKey would work the same way.
const auto private_key = Botan::ECDH_PrivateKey(null_rng, domain, private_scalar);
const auto private_key = Botan::ECDH_PrivateKey(domain, private_scalar);
const auto public_key = private_key.public_key();

std::cout << "Private Key (PEM):\n\n" << Botan::PKCS8::PEM_encode(private_key) << '\n';
Expand Down
3 changes: 0 additions & 3 deletions src/lib/pubkey/ecc_key/ec_key_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ namespace Botan {
EC_PublicKey_Data::EC_PublicKey_Data(EC_Group group, std::span<const uint8_t> bytes) :
m_group(std::move(group)), m_point(m_group, bytes), m_legacy_point(m_point.to_legacy_point()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, RandomNumberGenerator& rng) :
m_group(std::move(group)), m_scalar(EC_Scalar::random(m_group, rng)), m_legacy_x(m_scalar.to_bigint()) {}

EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, const BigInt& x) :
m_group(std::move(group)), m_scalar(EC_Scalar::from_bigint(m_group, x)), m_legacy_x(m_scalar.to_bigint()) {}

Expand Down
2 changes: 0 additions & 2 deletions src/lib/pubkey/ecc_key/ec_key_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ class EC_PublicKey_Data final {

class EC_PrivateKey_Data final {
public:
EC_PrivateKey_Data(EC_Group group, RandomNumberGenerator& rng);

EC_PrivateKey_Data(EC_Group group, const BigInt& x);

EC_PrivateKey_Data(EC_Group group, EC_Scalar x);
Expand Down
18 changes: 11 additions & 7 deletions src/lib/pubkey/ecc_key/ecc_key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,22 +124,26 @@ EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng,
EC_Group ec_group,
const BigInt& x,
bool with_modular_inverse) {
if(x == 0) {
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), rng);
} else {
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), x);
}

auto scalar = (x.is_zero()) ? EC_Scalar::random(ec_group, rng) : EC_Scalar::from_bigint(ec_group, x);
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), std::move(scalar));
m_public_key = m_private_key->public_key(rng, with_modular_inverse);
m_domain_encoding = default_encoding_for(domain());
}

EC_PrivateKey::EC_PrivateKey(RandomNumberGenerator& rng, EC_Group ec_group, bool with_modular_inverse) {
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), rng);
auto scalar = EC_Scalar::random(ec_group, rng);
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), std::move(scalar));
m_public_key = m_private_key->public_key(rng, with_modular_inverse);
m_domain_encoding = default_encoding_for(domain());
}

EC_PrivateKey::EC_PrivateKey(EC_Group group, const BigInt& bn_scalar, bool with_modular_inverse) {
auto scalar = EC_Scalar::from_bigint(group, bn_scalar);
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(group), std::move(scalar));
m_public_key = m_private_key->public_key(with_modular_inverse);
m_domain_encoding = default_encoding_for(domain());
}

EC_PrivateKey::EC_PrivateKey(EC_Group ec_group, EC_Scalar x, bool with_modular_inverse) {
m_private_key = std::make_shared<EC_PrivateKey_Data>(std::move(ec_group), std::move(x));
m_public_key = m_private_key->public_key(with_modular_inverse);
Expand Down
12 changes: 12 additions & 0 deletions src/lib/pubkey/ecc_key/ecc_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ class BOTAN_PUBLIC_API(2, 0) EC_PrivateKey : public virtual EC_PublicKey,
* the base point with the modular inverse of
* x (as in ECGDSA and ECKCDSA), otherwise by
* multiplying directly with x (as in ECDSA).
*
* TODO: Remove, once the respective deprecated constructors of the
* concrete ECC algorithms is removed.
*/
EC_PrivateKey(RandomNumberGenerator& rng, EC_Group domain, const BigInt& x, bool with_modular_inverse = false);

Expand All @@ -185,6 +188,15 @@ class BOTAN_PUBLIC_API(2, 0) EC_PrivateKey : public virtual EC_PublicKey,
*/
EC_PrivateKey(RandomNumberGenerator& rng, EC_Group group, bool with_modular_inverse = false);

/**
* Load a EC private key from the secret scalar
*
* If @p with_modular_inverse is set, the public key will be calculated by
* multiplying the base point with the modular inverse of x (as in ECGDSA
* and ECKCDSA), otherwise by multiplying directly with x (as in ECDSA).
*/
EC_PrivateKey(EC_Group group, const BigInt& scalar, bool with_modular_inverse = false);

/**
* Load a EC private key from the secret scalar
*
Expand Down
17 changes: 16 additions & 1 deletion src/lib/pubkey/ecdh/ecdh.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,28 @@ class BOTAN_PUBLIC_API(2, 0) ECDH_PrivateKey final : public ECDH_PublicKey,
ECDH_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
EC_PrivateKey(alg_id, key_bits) {}

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
ECDH_PrivateKey(EC_Group domain, const BigInt& x) : EC_PrivateKey(std::move(domain), x) {}

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
ECDH_PrivateKey(RandomNumberGenerator& rng, EC_Group domain) : EC_PrivateKey(rng, std::move(domain)) {}

/**
* Generate a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key; if zero, a new random key is generated
*/
ECDH_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x = BigInt::zero()) :
BOTAN_DEPRECATED("Use one of the other constructors")
ECDH_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(rng, domain, x) {}

std::unique_ptr<Public_Key> public_key() const override;
Expand Down
17 changes: 16 additions & 1 deletion src/lib/pubkey/ecdsa/ecdsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,28 @@ class BOTAN_PUBLIC_API(2, 0) ECDSA_PrivateKey final : public ECDSA_PublicKey,
ECDSA_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
EC_PrivateKey(alg_id, key_bits) {}

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
ECDSA_PrivateKey(EC_Group domain, const BigInt& x) : EC_PrivateKey(std::move(domain), x) {}

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
ECDSA_PrivateKey(RandomNumberGenerator& rng, EC_Group domain) : EC_PrivateKey(rng, std::move(domain)) {}

/**
* Create a private key.
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key (if zero, generate a new random key)
*/
ECDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x = BigInt::zero()) :
BOTAN_DEPRECATED("Use one of the other constructors")
ECDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(rng, domain, x) {}

bool check_key(RandomNumberGenerator& rng, bool) const override;
Expand Down
18 changes: 17 additions & 1 deletion src/lib/pubkey/ecgdsa/ecgdsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,29 @@ class BOTAN_PUBLIC_API(2, 0) ECGDSA_PrivateKey final : public ECGDSA_PublicKey,
ECGDSA_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
EC_PrivateKey(alg_id, key_bits, true) {}

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
ECGDSA_PrivateKey(EC_Group domain, const BigInt& x) : EC_PrivateKey(std::move(domain), x, true) {}

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
ECGDSA_PrivateKey(RandomNumberGenerator& rng, EC_Group domain) :
EC_PrivateKey(rng, std::move(domain), BigInt::zero(), true) {}

/**
* Generate a new private key.
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key (if zero, generate a new random key)
*/
ECGDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x = BigInt::zero()) :
BOTAN_DEPRECATED("Use one of the other constructors")
ECGDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(rng, domain, x, true) {}

std::unique_ptr<Public_Key> public_key() const override;
Expand Down
18 changes: 17 additions & 1 deletion src/lib/pubkey/eckcdsa/eckcdsa.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,29 @@ class BOTAN_PUBLIC_API(2, 0) ECKCDSA_PrivateKey final : public ECKCDSA_PublicKey
ECKCDSA_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
EC_PrivateKey(alg_id, key_bits, true) {}

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
ECKCDSA_PrivateKey(EC_Group domain, const BigInt& x) : EC_PrivateKey(std::move(domain), x, true) {}

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
ECKCDSA_PrivateKey(RandomNumberGenerator& rng, EC_Group domain) :
EC_PrivateKey(rng, std::move(domain), BigInt::zero(), true) {}

/**
* Create a private key.
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key (if zero, generate a new random key)
*/
ECKCDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x = BigInt::zero()) :
BOTAN_DEPRECATED("Use one of the other constructors")
ECKCDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(rng, domain, x, true) {}

bool check_key(RandomNumberGenerator& rng, bool) const override;
Expand Down
34 changes: 21 additions & 13 deletions src/lib/pubkey/gost_3410/gost_3410.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@

namespace Botan {

namespace {

EC_Group check_domain(EC_Group domain) {
const size_t p_bits = domain.get_p_bits();
if(p_bits != 256 && p_bits != 512) {
throw Decoding_Error(fmt("GOST-34.10-2012 is not defined for parameters of size {}", p_bits));
}
return domain;
}

} // namespace

std::vector<uint8_t> GOST_3410_PublicKey::public_key_bits() const {
auto bits = public_point().xy_bytes();

Expand Down Expand Up @@ -60,17 +72,12 @@ GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, std:
// The parameters also includes hash and cipher OIDs
BER_Decoder(alg_id.parameters()).start_sequence().decode(ecc_param_id);

auto group = EC_Group::from_OID(ecc_param_id);

const size_t p_bits = group.get_p_bits();
if(p_bits != 256 && p_bits != 512) {
throw Decoding_Error(fmt("GOST-34.10-2012 is not defined for parameters of size {}", p_bits));
}
auto group = check_domain(EC_Group::from_OID(ecc_param_id));

std::vector<uint8_t> bits;
BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString);

if(bits.size() != 2 * (p_bits / 8)) {
if(bits.size() != 2 * (group.get_p_bits() / 8)) {
throw Decoding_Error("GOST-34.10-2012 invalid encoding of public key");
}

Expand All @@ -86,13 +93,14 @@ GOST_3410_PublicKey::GOST_3410_PublicKey(const AlgorithmIdentifier& alg_id, std:
m_public_key = std::make_shared<EC_PublicKey_Data>(std::move(group), encoding);
}

GOST_3410_PrivateKey::GOST_3410_PrivateKey(const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(check_domain(domain), EC_Scalar::from_bigint(domain, x)) {}

GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, EC_Group domain) :
EC_PrivateKey(rng, check_domain(std::move(domain))) {}

GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x) :
EC_PrivateKey(rng, domain, x) {
const size_t p_bits = domain.get_p_bits();
if(p_bits != 256 && p_bits != 512) {
throw Decoding_Error(fmt("GOST-34.10-2012 is not defined for parameters of size {}", p_bits));
}
}
EC_PrivateKey(rng, check_domain(domain), x) {}

std::unique_ptr<Public_Key> GOST_3410_PrivateKey::public_key() const {
return std::make_unique<GOST_3410_PublicKey>(domain(), public_point());
Expand Down
17 changes: 16 additions & 1 deletion src/lib/pubkey/gost_3410/gost_3410.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,28 @@ class BOTAN_PUBLIC_API(2, 0) GOST_3410_PrivateKey final : public GOST_3410_Publi
GOST_3410_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
EC_PrivateKey(alg_id, key_bits) {}

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
GOST_3410_PrivateKey(const EC_Group& domain, const BigInt& x);

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
GOST_3410_PrivateKey(RandomNumberGenerator& rng, EC_Group domain);

/**
* Generate a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key; if zero, a new random key is generated
*/
GOST_3410_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x = BigInt::zero());
BOTAN_DEPRECATED("Use one of the other constructors")
GOST_3410_PrivateKey(RandomNumberGenerator& rng, const EC_Group& domain, const BigInt& x);

std::unique_ptr<Public_Key> public_key() const override;

Expand Down
10 changes: 10 additions & 0 deletions src/lib/pubkey/sm2/sm2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ SM2_PrivateKey::SM2_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<cons
m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
m_da_inv_legacy(m_da_inv.to_bigint()) {}

SM2_PrivateKey::SM2_PrivateKey(EC_Group group, const BigInt& x) :
EC_PrivateKey(std::move(group), x),
m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
m_da_inv_legacy(m_da_inv.to_bigint()) {}

SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group group) :
EC_PrivateKey(rng, std::move(group)),
m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
m_da_inv_legacy(m_da_inv.to_bigint()) {}

SM2_PrivateKey::SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group group, const BigInt& x) :
EC_PrivateKey(rng, std::move(group), x),
m_da_inv((this->_private_key() + EC_Scalar::one(domain())).invert()),
Expand Down
17 changes: 16 additions & 1 deletion src/lib/pubkey/sm2/sm2.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,28 @@ class BOTAN_PUBLIC_API(2, 2) SM2_PrivateKey final : public SM2_PublicKey,
*/
SM2_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits);

/**
* Create a private key from a given secret @p x
* @param domain curve parameters to bu used for this key
* @param x the private key
*/
SM2_PrivateKey(EC_Group domain, const BigInt& x);

/**
* Create a new private key
* @param rng a random number generator
* @param domain parameters to used for this key
*/
SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group domain);

/**
* Create a private key.
* @param rng a random number generator
* @param domain parameters to used for this key
* @param x the private key (if zero, generate a new random key)
*/
SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group domain, const BigInt& x = BigInt::zero());
BOTAN_DEPRECATED("Use one of the other constructors")
SM2_PrivateKey(RandomNumberGenerator& rng, EC_Group domain, const BigInt& x);

bool check_key(RandomNumberGenerator& rng, bool) const override;

Expand Down
Loading