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