/src/botan/src/lib/pubkey/curve448/x448/x448.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * X448 |
3 | | * (C) 2024 Jack Lloyd |
4 | | * 2024 Fabian Albert - Rohde & Schwarz Cybersecurity |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/x448.h> |
10 | | |
11 | | #include <botan/ber_dec.h> |
12 | | #include <botan/der_enc.h> |
13 | | #include <botan/rng.h> |
14 | | #include <botan/internal/ct_utils.h> |
15 | | #include <botan/internal/pk_ops_impl.h> |
16 | | #include <botan/internal/x448_internal.h> |
17 | | |
18 | | namespace Botan { |
19 | | |
20 | | namespace { |
21 | 1.87k | void x448_basepoint_from_data(std::span<uint8_t, X448_LEN> mypublic, std::span<const uint8_t, X448_LEN> secret) { |
22 | 1.87k | auto bp = x448_basepoint(decode_scalar(secret)); |
23 | 1.87k | auto bp_bytes = encode_point(bp); |
24 | 1.87k | copy_mem(mypublic, bp_bytes); |
25 | 1.87k | } |
26 | | |
27 | 409 | secure_vector<uint8_t> ber_decode_sk(std::span<const uint8_t> key_bits) { |
28 | 409 | secure_vector<uint8_t> decoded_bits; |
29 | 409 | BER_Decoder(key_bits).decode(decoded_bits, ASN1_Type::OctetString).verify_end(); |
30 | 409 | BOTAN_ASSERT_NOMSG(decoded_bits.size() == X448_LEN); |
31 | 409 | return decoded_bits; |
32 | 409 | } |
33 | | |
34 | | } // namespace |
35 | | |
36 | 0 | AlgorithmIdentifier X448_PublicKey::algorithm_identifier() const { |
37 | 0 | return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM); |
38 | 0 | } |
39 | | |
40 | 0 | bool X448_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const { |
41 | 0 | return true; // no tests possible? |
42 | 0 | } |
43 | | |
44 | 462 | std::vector<uint8_t> X448_PublicKey::raw_public_key_bits() const { |
45 | 462 | return public_value(); |
46 | 462 | } |
47 | | |
48 | 1.47k | std::vector<uint8_t> X448_PublicKey::public_key_bits() const { |
49 | 1.47k | return public_value(); |
50 | 1.47k | } |
51 | | |
52 | 0 | std::unique_ptr<Private_Key> X448_PublicKey::generate_another(RandomNumberGenerator& rng) const { |
53 | 0 | return std::make_unique<X448_PrivateKey>(rng); |
54 | 0 | } |
55 | | |
56 | | X448_PublicKey::X448_PublicKey(const AlgorithmIdentifier& /*alg_id*/, std::span<const uint8_t> key_bits) : |
57 | 0 | X448_PublicKey(key_bits) {} Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) |
58 | | |
59 | 468 | X448_PublicKey::X448_PublicKey(std::span<const uint8_t> pub) { |
60 | 468 | BOTAN_ARG_CHECK(pub.size() == X448_LEN, "Invalid size for X448 public key"); |
61 | 468 | copy_mem(m_public, pub); |
62 | 468 | } Unexecuted instantiation: Botan::X448_PublicKey::X448_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>) Botan::X448_PublicKey::X448_PublicKey(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 59 | 468 | X448_PublicKey::X448_PublicKey(std::span<const uint8_t> pub) { | 60 | 468 | BOTAN_ARG_CHECK(pub.size() == X448_LEN, "Invalid size for X448 public key"); | 61 | 468 | copy_mem(m_public, pub); | 62 | 468 | } |
|
63 | | |
64 | | X448_PrivateKey::X448_PrivateKey(const AlgorithmIdentifier& /*alg_id*/, std::span<const uint8_t> key_bits) : |
65 | 409 | X448_PrivateKey(ber_decode_sk(key_bits)) {} Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) Botan::X448_PrivateKey::X448_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 65 | 409 | X448_PrivateKey(ber_decode_sk(key_bits)) {} |
|
66 | | |
67 | 1.87k | X448_PrivateKey::X448_PrivateKey(std::span<const uint8_t> secret_key) { |
68 | 1.87k | BOTAN_ARG_CHECK(secret_key.size() == X448_LEN, "Invalid size for X448 private key"); |
69 | 1.87k | m_private.assign(secret_key.begin(), secret_key.end()); |
70 | 1.87k | auto scope = CT::scoped_poison(m_private); |
71 | 1.87k | x448_basepoint_from_data(m_public, std::span(m_private).first<X448_LEN>()); |
72 | 1.87k | CT::unpoison(m_public); |
73 | 1.87k | } Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>) Botan::X448_PrivateKey::X448_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>) Line | Count | Source | 67 | 1.87k | X448_PrivateKey::X448_PrivateKey(std::span<const uint8_t> secret_key) { | 68 | 1.87k | BOTAN_ARG_CHECK(secret_key.size() == X448_LEN, "Invalid size for X448 private key"); | 69 | 1.87k | m_private.assign(secret_key.begin(), secret_key.end()); | 70 | 1.87k | auto scope = CT::scoped_poison(m_private); | 71 | 1.87k | x448_basepoint_from_data(m_public, std::span(m_private).first<X448_LEN>()); | 72 | 1.87k | CT::unpoison(m_public); | 73 | 1.87k | } |
|
74 | | |
75 | 1.47k | X448_PrivateKey::X448_PrivateKey(RandomNumberGenerator& rng) : X448_PrivateKey(rng.random_vec(X448_LEN)) {} Unexecuted instantiation: Botan::X448_PrivateKey::X448_PrivateKey(Botan::RandomNumberGenerator&) Botan::X448_PrivateKey::X448_PrivateKey(Botan::RandomNumberGenerator&) Line | Count | Source | 75 | 1.47k | X448_PrivateKey::X448_PrivateKey(RandomNumberGenerator& rng) : X448_PrivateKey(rng.random_vec(X448_LEN)) {} |
|
76 | | |
77 | 0 | std::unique_ptr<Public_Key> X448_PrivateKey::public_key() const { |
78 | 0 | return std::make_unique<X448_PublicKey>(public_value()); |
79 | 0 | } |
80 | | |
81 | 0 | secure_vector<uint8_t> X448_PrivateKey::private_key_bits() const { |
82 | 0 | return DER_Encoder().encode(m_private, ASN1_Type::OctetString).get_contents(); |
83 | 0 | } |
84 | | |
85 | 0 | bool X448_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const { |
86 | 0 | std::array<uint8_t, X448_LEN> public_point; |
87 | 0 | BOTAN_ASSERT_NOMSG(m_private.size() == X448_LEN); |
88 | 0 | auto scope = CT::scoped_poison(m_private); |
89 | 0 | x448_basepoint_from_data(public_point, std::span(m_private).first<X448_LEN>()); |
90 | 0 | return CT::is_equal(public_point.data(), m_public.data(), m_public.size()).as_bool(); |
91 | 0 | } |
92 | | |
93 | | namespace { |
94 | | |
95 | | /** |
96 | | * X448 operation |
97 | | */ |
98 | | class X448_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF { |
99 | | public: |
100 | | X448_KA_Operation(std::span<const uint8_t> sk, std::string_view kdf) : |
101 | 462 | PK_Ops::Key_Agreement_with_KDF(kdf), m_sk(sk.begin(), sk.end()) { |
102 | 462 | BOTAN_ARG_CHECK(sk.size() == X448_LEN, "Invalid size for X448 private key"); |
103 | 462 | } |
104 | | |
105 | 0 | size_t agreed_value_size() const override { return X448_LEN; } |
106 | | |
107 | 462 | secure_vector<uint8_t> raw_agree(const uint8_t w_data[], size_t w_len) override { |
108 | 462 | auto scope = CT::scoped_poison(m_sk); |
109 | | |
110 | 462 | std::span<const uint8_t> w(w_data, w_len); |
111 | 462 | BOTAN_ARG_CHECK(w.size() == X448_LEN, "Invalid size for X448 private key"); |
112 | 462 | BOTAN_ASSERT_NOMSG(m_sk.size() == X448_LEN); |
113 | 462 | const auto k = decode_scalar(m_sk); |
114 | 462 | const auto u = decode_point(w); |
115 | | |
116 | 462 | auto shared_secret = encode_point(x448(k, u)); |
117 | 462 | CT::unpoison(shared_secret); |
118 | | |
119 | | // RFC 7748 Section 6.2 |
120 | | // As with X25519, both sides MAY check, without leaking extra |
121 | | // information about the value of K, whether the resulting shared K |
122 | | // is the all-zero value and abort if so. |
123 | | // |
124 | | // TODO: once the generic Key Agreement operation creation is equipped |
125 | | // with a more flexible parameterization, this check could be |
126 | | // made optional. |
127 | | // For instance: `sk->agree().with_optional_sanity_checks(true)`. |
128 | | // See also: https://github.com/randombit/botan/pull/4318 |
129 | 462 | if(CT::all_zeros(shared_secret.data(), shared_secret.size()).as_bool()) { |
130 | 1 | throw Invalid_Argument("X448 public point appears to be of low order"); |
131 | 1 | } |
132 | | |
133 | 461 | return shared_secret; |
134 | 462 | } |
135 | | |
136 | | private: |
137 | | secure_vector<uint8_t> m_sk; |
138 | | }; |
139 | | |
140 | | } // namespace |
141 | | |
142 | | std::unique_ptr<PK_Ops::Key_Agreement> X448_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/, |
143 | | std::string_view params, |
144 | 462 | std::string_view provider) const { |
145 | 462 | if(provider == "base" || provider.empty()) { |
146 | 462 | return std::make_unique<X448_KA_Operation>(m_private, params); |
147 | 462 | } |
148 | 0 | throw Provider_Not_Found(algo_name(), provider); |
149 | 462 | } |
150 | | |
151 | | } // namespace Botan |