Coverage Report

Created: 2025-10-10 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/pubkey/ed25519/ed25519_key.cpp
Line
Count
Source
1
/*
2
* Ed25519
3
* (C) 2017 Ribose Inc
4
*     2025 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/ed25519.h>
10
11
#include <botan/ber_dec.h>
12
#include <botan/der_enc.h>
13
#include <botan/hash.h>
14
#include <botan/rng.h>
15
#include <botan/internal/ct_utils.h>
16
#include <botan/internal/ed25519_internal.h>
17
#include <botan/internal/pk_ops_impl.h>
18
19
namespace Botan {
20
21
0
AlgorithmIdentifier Ed25519_PublicKey::algorithm_identifier() const {
22
0
   return AlgorithmIdentifier(object_identifier(), AlgorithmIdentifier::USE_EMPTY_PARAM);
23
0
}
24
25
0
bool Ed25519_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
26
0
   if(m_public.size() != 32) {
27
0
      return false;
28
0
   }
29
30
   /*
31
   This function was derived from public domain code in Tor's blinding.c
32
   */
33
34
0
   const uint8_t identity_element[32] = {1};
35
0
   if(CT::is_equal(m_public.data(), identity_element, 32).as_bool()) {
36
0
      return false;
37
0
   }
38
39
   // The order of the Ed25519 group encoded
40
0
   const uint8_t modm_m[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
41
0
                               0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42
0
                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
43
44
0
   const unsigned char zero[32] = {0};
45
46
0
   unsigned char pkcopy[32];
47
48
0
   copy_mem(pkcopy, m_public.data(), 32);
49
0
   pkcopy[31] ^= (1 << 7);  // flip sign
50
51
0
   return signature_check(pkcopy, modm_m, identity_element, zero);
52
0
}
53
54
0
Ed25519_PublicKey::Ed25519_PublicKey(const uint8_t pub_key[], size_t pub_len) {
55
0
   if(pub_len != 32) {
56
0
      throw Decoding_Error("Invalid length for Ed25519 key");
57
0
   }
58
0
   m_public.assign(pub_key, pub_key + pub_len);
59
0
}
Unexecuted instantiation: Botan::Ed25519_PublicKey::Ed25519_PublicKey(unsigned char const*, unsigned long)
Unexecuted instantiation: Botan::Ed25519_PublicKey::Ed25519_PublicKey(unsigned char const*, unsigned long)
60
61
1
Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
62
1
   m_public.assign(key_bits.begin(), key_bits.end());
63
64
1
   if(m_public.size() != 32) {
65
1
      throw Decoding_Error("Invalid size for Ed25519 public key");
66
1
   }
67
1
}
Unexecuted instantiation: Botan::Ed25519_PublicKey::Ed25519_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::Ed25519_PublicKey::Ed25519_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
61
1
Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
62
1
   m_public.assign(key_bits.begin(), key_bits.end());
63
64
1
   if(m_public.size() != 32) {
65
1
      throw Decoding_Error("Invalid size for Ed25519 public key");
66
1
   }
67
1
}
68
69
0
std::vector<uint8_t> Ed25519_PublicKey::raw_public_key_bits() const {
70
0
   return m_public;
71
0
}
72
73
0
std::vector<uint8_t> Ed25519_PublicKey::public_key_bits() const {
74
0
   return raw_public_key_bits();
75
0
}
76
77
0
std::unique_ptr<Private_Key> Ed25519_PublicKey::generate_another(RandomNumberGenerator& rng) const {
78
0
   return std::make_unique<Ed25519_PrivateKey>(rng);
79
0
}
80
81
0
Ed25519_PrivateKey::Ed25519_PrivateKey(std::span<const uint8_t> secret_key) {
82
0
   if(secret_key.size() == 64) {
83
0
      m_private.assign(secret_key.begin(), secret_key.end());
84
0
      m_public.assign(m_private.begin() + 32, m_private.end());
85
0
   } else if(secret_key.size() == 32) {
86
0
      m_public.resize(32);
87
0
      m_private.resize(64);
88
0
      ed25519_gen_keypair(m_public.data(), m_private.data(), secret_key.data());
89
0
   } else {
90
0
      throw Decoding_Error("Invalid size for Ed25519 private key");
91
0
   }
92
0
}
Unexecuted instantiation: Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(std::__1::span<unsigned char const, 18446744073709551615ul>)
93
94
//static
95
0
Ed25519_PrivateKey Ed25519_PrivateKey::from_seed(std::span<const uint8_t> seed) {
96
0
   BOTAN_ARG_CHECK(seed.size() == 32, "Ed25519 seed must be exactly 32 bytes long");
97
0
   return Ed25519_PrivateKey(seed);
98
0
}
99
100
//static
101
0
Ed25519_PrivateKey Ed25519_PrivateKey::from_bytes(std::span<const uint8_t> bytes) {
102
0
   BOTAN_ARG_CHECK(bytes.size() == 64, "Ed25519 private key must be exactly 64 bytes long");
103
0
   return Ed25519_PrivateKey(bytes);
104
0
}
105
106
0
Ed25519_PrivateKey::Ed25519_PrivateKey(RandomNumberGenerator& rng) {
107
0
   const secure_vector<uint8_t> seed = rng.random_vec(32);
108
0
   m_public.resize(32);
109
0
   m_private.resize(64);
110
0
   ed25519_gen_keypair(m_public.data(), m_private.data(), seed.data());
111
0
}
Unexecuted instantiation: Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(Botan::RandomNumberGenerator&)
Unexecuted instantiation: Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(Botan::RandomNumberGenerator&)
112
113
16
Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
114
16
   secure_vector<uint8_t> bits;
115
16
   BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString).discard_remaining();
116
117
16
   if(bits.size() != 32) {
118
10
      throw Decoding_Error("Invalid size for Ed25519 private key");
119
10
   }
120
6
   m_public.resize(32);
121
6
   m_private.resize(64);
122
6
   ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data());
123
6
}
Unexecuted instantiation: Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Botan::Ed25519_PrivateKey::Ed25519_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Line
Count
Source
113
16
Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
114
16
   secure_vector<uint8_t> bits;
115
16
   BER_Decoder(key_bits).decode(bits, ASN1_Type::OctetString).discard_remaining();
116
117
16
   if(bits.size() != 32) {
118
10
      throw Decoding_Error("Invalid size for Ed25519 private key");
119
10
   }
120
6
   m_public.resize(32);
121
6
   m_private.resize(64);
122
6
   ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data());
123
6
}
124
125
0
std::unique_ptr<Public_Key> Ed25519_PrivateKey::public_key() const {
126
0
   return std::make_unique<Ed25519_PublicKey>(get_public_key());
127
0
}
128
129
0
secure_vector<uint8_t> Ed25519_PrivateKey::private_key_bits() const {
130
0
   secure_vector<uint8_t> bits(m_private.data(), &m_private[32]);
131
0
   return DER_Encoder().encode(bits, ASN1_Type::OctetString).get_contents();
132
0
}
133
134
0
bool Ed25519_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
135
0
   return true;  // ???
136
0
}
137
138
namespace {
139
140
/**
141
* Ed25519 verifying operation
142
*/
143
class Ed25519_Pure_Verify_Operation final : public PK_Ops::Verification {
144
   public:
145
0
      explicit Ed25519_Pure_Verify_Operation(const Ed25519_PublicKey& key) : m_key(key.get_public_key()) {}
146
147
0
      void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
148
149
0
      bool is_valid_signature(std::span<const uint8_t> sig) override {
150
0
         if(sig.size() != 64) {
151
0
            return false;
152
0
         }
153
154
0
         BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
155
0
         const bool ok = ed25519_verify(m_msg.data(), m_msg.size(), sig.data(), m_key.data(), nullptr, 0);
156
0
         m_msg.clear();
157
0
         return ok;
158
0
      }
159
160
0
      std::string hash_function() const override { return "SHA-512"; }
161
162
   private:
163
      std::vector<uint8_t> m_msg;
164
      std::vector<uint8_t> m_key;
165
};
166
167
/**
168
* Ed25519 verifying operation with pre-hash
169
*/
170
class Ed25519_Hashed_Verify_Operation final : public PK_Ops::Verification {
171
   public:
172
      Ed25519_Hashed_Verify_Operation(const Ed25519_PublicKey& key, std::string_view hash, bool rfc8032) :
173
0
            m_key(key.get_public_key()) {
174
0
         m_hash = HashFunction::create_or_throw(hash);
175
176
0
         if(rfc8032) {
177
0
            m_domain_sep = {0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
178
0
                            0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
179
0
                            0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
180
0
         }
181
0
      }
182
183
0
      void update(std::span<const uint8_t> msg) override { m_hash->update(msg); }
184
185
0
      bool is_valid_signature(std::span<const uint8_t> sig) override {
186
0
         if(sig.size() != 64) {
187
0
            return false;
188
0
         }
189
0
         std::vector<uint8_t> msg_hash(m_hash->output_length());
190
0
         m_hash->final(msg_hash.data());
191
192
0
         BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
193
0
         return ed25519_verify(
194
0
            msg_hash.data(), msg_hash.size(), sig.data(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
195
0
      }
196
197
0
      std::string hash_function() const override { return m_hash->name(); }
198
199
   private:
200
      std::unique_ptr<HashFunction> m_hash;
201
      std::vector<uint8_t> m_key;
202
      std::vector<uint8_t> m_domain_sep;
203
};
204
205
/**
206
* Ed25519 signing operation ('pure' - signs message directly)
207
*/
208
class Ed25519_Pure_Sign_Operation final : public PK_Ops::Signature {
209
   public:
210
0
      explicit Ed25519_Pure_Sign_Operation(const Ed25519_PrivateKey& key) : m_key(key.raw_private_key_bits()) {}
211
212
0
      void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
213
214
0
      std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
215
0
         std::vector<uint8_t> sig(64);
216
0
         ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.data(), nullptr, 0);
217
0
         m_msg.clear();
218
0
         return sig;
219
0
      }
220
221
0
      size_t signature_length() const override { return 64; }
222
223
      AlgorithmIdentifier algorithm_identifier() const override;
224
225
0
      std::string hash_function() const override { return "SHA-512"; }
226
227
   private:
228
      std::vector<uint8_t> m_msg;
229
      secure_vector<uint8_t> m_key;
230
};
231
232
0
AlgorithmIdentifier Ed25519_Pure_Sign_Operation::algorithm_identifier() const {
233
0
   return AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
234
0
}
235
236
/**
237
* Ed25519 signing operation with pre-hash
238
*/
239
class Ed25519_Hashed_Sign_Operation final : public PK_Ops::Signature {
240
   public:
241
      Ed25519_Hashed_Sign_Operation(const Ed25519_PrivateKey& key, std::string_view hash, bool rfc8032) :
242
0
            m_key(key.raw_private_key_bits()) {
243
0
         m_hash = HashFunction::create_or_throw(hash);
244
245
0
         if(rfc8032) {
246
0
            m_domain_sep = std::vector<uint8_t>{0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
247
0
                                                0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
248
0
                                                0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
249
0
         }
250
0
      }
251
252
0
      size_t signature_length() const override { return 64; }
253
254
0
      void update(std::span<const uint8_t> msg) override { m_hash->update(msg); }
255
256
0
      std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
257
0
         std::vector<uint8_t> sig(64);
258
0
         std::vector<uint8_t> msg_hash(m_hash->output_length());
259
0
         m_hash->final(msg_hash.data());
260
0
         ed25519_sign(
261
0
            sig.data(), msg_hash.data(), msg_hash.size(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
262
0
         return sig;
263
0
      }
264
265
0
      std::string hash_function() const override { return m_hash->name(); }
266
267
   private:
268
      std::unique_ptr<HashFunction> m_hash;
269
      secure_vector<uint8_t> m_key;
270
      std::vector<uint8_t> m_domain_sep;
271
};
272
273
}  // namespace
274
275
std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_verification_op(std::string_view params,
276
0
                                                                                std::string_view provider) const {
277
0
   if(provider == "base" || provider.empty()) {
278
0
      if(params.empty() || params == "Identity" || params == "Pure") {
279
0
         return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
280
0
      } else if(params == "Ed25519ph") {
281
0
         return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, "SHA-512", true);
282
0
      } else {
283
0
         return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, params, false);
284
0
      }
285
0
   }
286
0
   throw Provider_Not_Found(algo_name(), provider);
287
0
}
288
289
std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_x509_verification_op(const AlgorithmIdentifier& alg_id,
290
0
                                                                                     std::string_view provider) const {
291
0
   if(provider == "base" || provider.empty()) {
292
0
      if(alg_id != this->algorithm_identifier()) {
293
0
         throw Decoding_Error("Unexpected AlgorithmIdentifier for Ed25519 X509 signature");
294
0
      }
295
296
0
      return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
297
0
   }
298
0
   throw Provider_Not_Found(algo_name(), provider);
299
0
}
300
301
std::unique_ptr<PK_Ops::Signature> Ed25519_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
302
                                                                           std::string_view params,
303
0
                                                                           std::string_view provider) const {
304
0
   if(provider == "base" || provider.empty()) {
305
0
      if(params.empty() || params == "Identity" || params == "Pure") {
306
0
         return std::make_unique<Ed25519_Pure_Sign_Operation>(*this);
307
0
      } else if(params == "Ed25519ph") {
308
0
         return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, "SHA-512", true);
309
0
      } else {
310
0
         return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, params, false);
311
0
      }
312
0
   }
313
0
   throw Provider_Not_Found(algo_name(), provider);
314
0
}
315
316
}  // namespace Botan