/src/botan/src/lib/pubkey/ecc_key/ec_key_data.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * (C) 2024 Jack Lloyd |
3 | | * |
4 | | * Botan is released under the Simplified BSD License (see license.txt) |
5 | | */ |
6 | | |
7 | | #include <botan/internal/ec_key_data.h> |
8 | | |
9 | | #include <botan/mem_ops.h> |
10 | | #include <botan/rng.h> |
11 | | |
12 | | namespace Botan { |
13 | | |
14 | | EC_PublicKey_Data::EC_PublicKey_Data(EC_Group group, EC_AffinePoint pt) : |
15 | 22.6k | m_group(std::move(group)), m_point(std::move(pt)) { |
16 | 22.6k | #if defined(BOTAN_HAS_LEGACY_EC_POINT) |
17 | 22.6k | m_legacy_point = m_point.to_legacy_point(); |
18 | 22.6k | #endif |
19 | | |
20 | | // Checking that the point lies on the curve is done in the deserialization |
21 | | // of EC_AffinePoint. |
22 | 22.6k | BOTAN_ARG_CHECK(!m_point.is_identity(), "ECC public key cannot be point at infinity"); |
23 | 22.6k | } |
24 | | |
25 | | EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, EC_Scalar x) : |
26 | 20.6k | m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) { |
27 | | // Checking that the scalar is lower than the group order is ensured in the |
28 | | // deserialization of the EC_Scalar or during the random generation respectively. |
29 | 20.6k | BOTAN_ARG_CHECK(m_scalar.is_nonzero(), "ECC private key cannot be zero"); |
30 | 20.6k | } |
31 | | |
32 | | namespace { |
33 | | |
34 | 8.93k | EC_Scalar decode_ec_secret_key_scalar(const EC_Group& group, std::span<const uint8_t> bytes) { |
35 | 8.93k | const size_t order_bytes = group.get_order_bytes(); |
36 | | |
37 | 8.93k | if(bytes.size() < order_bytes) { |
38 | | /* |
39 | | * Older versions had a bug which caused secret keys to not be encoded to |
40 | | * the full byte length of the order if there were leading zero bytes. This |
41 | | * was particularly a problem for P-521, where on average half of keys do |
42 | | * not have their high bit set and so can be encoded in 65 bytes, vs 66 |
43 | | * bytes for the full order. |
44 | | * |
45 | | * To accomodate this, zero prefix the key if we see such a short input |
46 | | */ |
47 | 966 | secure_vector<uint8_t> padded_sk(order_bytes); |
48 | 966 | copy_mem(std::span{padded_sk}.last(bytes.size()), bytes); |
49 | 966 | return decode_ec_secret_key_scalar(group, padded_sk); |
50 | 966 | } |
51 | | |
52 | 7.96k | if(auto s = EC_Scalar::deserialize(group, bytes)) { |
53 | 7.88k | return s.value(); |
54 | 7.88k | } else { |
55 | 80 | throw Decoding_Error("EC private key is invalid for this group"); |
56 | 80 | } |
57 | 7.96k | } |
58 | | |
59 | | } // namespace |
60 | | |
61 | | EC_PrivateKey_Data::EC_PrivateKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) : |
62 | 7.96k | Botan::EC_PrivateKey_Data(group, decode_ec_secret_key_scalar(group, bytes)) {} |
63 | | |
64 | | std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng, |
65 | 12.9k | bool with_modular_inverse) const { |
66 | 12.9k | auto public_point = [&] { |
67 | 12.9k | if(with_modular_inverse) { |
68 | 0 | return EC_AffinePoint::g_mul(m_scalar.invert(), rng); |
69 | 12.9k | } else { |
70 | 12.9k | return EC_AffinePoint::g_mul(m_scalar, rng); |
71 | 12.9k | } |
72 | 12.9k | }; |
73 | | |
74 | 12.9k | return std::make_shared<EC_PublicKey_Data>(m_group, public_point()); |
75 | 12.9k | } |
76 | | |
77 | 152 | std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const { |
78 | 152 | Null_RNG null_rng; |
79 | 152 | return this->public_key(null_rng, with_modular_inverse); |
80 | 152 | } |
81 | | |
82 | 0 | void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const { |
83 | 0 | m_scalar.serialize_to(output); |
84 | 0 | } |
85 | | |
86 | | } // namespace Botan |