Botan 3.9.0
Crypto and TLS for C&
ed25519_key.cpp
Go to the documentation of this file.
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
19namespace Botan {
20
24
25bool Ed25519_PublicKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
26 if(m_public.size() != 32) {
27 return false;
28 }
29
30 /*
31 This function was derived from public domain code in Tor's blinding.c
32 */
33
34 const uint8_t identity_element[32] = {1};
35 if(CT::is_equal(m_public.data(), identity_element, 32).as_bool()) {
36 return false;
37 }
38
39 // The order of the Ed25519 group encoded
40 const uint8_t modm_m[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7,
41 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
43
44 const unsigned char zero[32] = {0};
45
46 unsigned char pkcopy[32];
47
48 copy_mem(pkcopy, m_public.data(), 32);
49 pkcopy[31] ^= (1 << 7); // flip sign
50
51 return signature_check(pkcopy, modm_m, identity_element, zero);
52}
53
54Ed25519_PublicKey::Ed25519_PublicKey(const uint8_t pub_key[], size_t pub_len) {
55 if(pub_len != 32) {
56 throw Decoding_Error("Invalid length for Ed25519 key");
57 }
58 m_public.assign(pub_key, pub_key + pub_len);
59}
60
61Ed25519_PublicKey::Ed25519_PublicKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
62 m_public.assign(key_bits.begin(), key_bits.end());
63
64 if(m_public.size() != 32) {
65 throw Decoding_Error("Invalid size for Ed25519 public key");
66 }
67}
68
69std::vector<uint8_t> Ed25519_PublicKey::raw_public_key_bits() const {
70 return m_public;
71}
72
73std::vector<uint8_t> Ed25519_PublicKey::public_key_bits() const {
74 return raw_public_key_bits();
75}
76
77std::unique_ptr<Private_Key> Ed25519_PublicKey::generate_another(RandomNumberGenerator& rng) const {
78 return std::make_unique<Ed25519_PrivateKey>(rng);
79}
80
81Ed25519_PrivateKey::Ed25519_PrivateKey(std::span<const uint8_t> secret_key) {
82 if(secret_key.size() == 64) {
83 m_private.assign(secret_key.begin(), secret_key.end());
84 m_public.assign(m_private.begin() + 32, m_private.end());
85 } else if(secret_key.size() == 32) {
86 m_public.resize(32);
87 m_private.resize(64);
88 ed25519_gen_keypair(m_public.data(), m_private.data(), secret_key.data());
89 } else {
90 throw Decoding_Error("Invalid size for Ed25519 private key");
91 }
92}
93
94//static
95Ed25519_PrivateKey Ed25519_PrivateKey::from_seed(std::span<const uint8_t> seed) {
96 BOTAN_ARG_CHECK(seed.size() == 32, "Ed25519 seed must be exactly 32 bytes long");
97 return Ed25519_PrivateKey(seed);
98}
99
100//static
101Ed25519_PrivateKey Ed25519_PrivateKey::from_bytes(std::span<const uint8_t> bytes) {
102 BOTAN_ARG_CHECK(bytes.size() == 64, "Ed25519 private key must be exactly 64 bytes long");
103 return Ed25519_PrivateKey(bytes);
104}
105
107 const secure_vector<uint8_t> seed = rng.random_vec(32);
108 m_public.resize(32);
109 m_private.resize(64);
110 ed25519_gen_keypair(m_public.data(), m_private.data(), seed.data());
111}
112
113Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier& /*unused*/, std::span<const uint8_t> key_bits) {
116
117 if(bits.size() != 32) {
118 throw Decoding_Error("Invalid size for Ed25519 private key");
119 }
120 m_public.resize(32);
121 m_private.resize(64);
122 ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data());
123}
124
125std::unique_ptr<Public_Key> Ed25519_PrivateKey::public_key() const {
126 return std::make_unique<Ed25519_PublicKey>(get_public_key());
127}
128
133
134bool Ed25519_PrivateKey::check_key(RandomNumberGenerator& /*rng*/, bool /*strong*/) const {
135 return true; // ???
136}
137
138namespace {
139
140/**
141* Ed25519 verifying operation
142*/
143class Ed25519_Pure_Verify_Operation final : public PK_Ops::Verification {
144 public:
145 explicit Ed25519_Pure_Verify_Operation(const Ed25519_PublicKey& key) : m_key(key.get_public_key()) {}
146
147 void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
148
149 bool is_valid_signature(std::span<const uint8_t> sig) override {
150 if(sig.size() != 64) {
151 return false;
152 }
153
154 BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
155 const bool ok = ed25519_verify(m_msg.data(), m_msg.size(), sig.data(), m_key.data(), nullptr, 0);
156 m_msg.clear();
157 return ok;
158 }
159
160 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*/
170class 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 m_key(key.get_public_key()) {
174 m_hash = HashFunction::create_or_throw(hash);
175
176 if(rfc8032) {
177 m_domain_sep = {0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
178 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
179 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
180 }
181 }
182
183 void update(std::span<const uint8_t> msg) override { m_hash->update(msg); }
184
185 bool is_valid_signature(std::span<const uint8_t> sig) override {
186 if(sig.size() != 64) {
187 return false;
188 }
189 std::vector<uint8_t> msg_hash(m_hash->output_length());
190 m_hash->final(msg_hash.data());
191
192 BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
193 return ed25519_verify(
194 msg_hash.data(), msg_hash.size(), sig.data(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
195 }
196
197 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*/
208class Ed25519_Pure_Sign_Operation final : public PK_Ops::Signature {
209 public:
210 explicit Ed25519_Pure_Sign_Operation(const Ed25519_PrivateKey& key) : m_key(key.raw_private_key_bits()) {}
211
212 void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
213
214 std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
215 std::vector<uint8_t> sig(64);
216 ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.data(), nullptr, 0);
217 m_msg.clear();
218 return sig;
219 }
220
221 size_t signature_length() const override { return 64; }
222
223 AlgorithmIdentifier algorithm_identifier() const override;
224
225 std::string hash_function() const override { return "SHA-512"; }
226
227 private:
228 std::vector<uint8_t> m_msg;
230};
231
232AlgorithmIdentifier Ed25519_Pure_Sign_Operation::algorithm_identifier() const {
233 return AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
234}
235
236/**
237* Ed25519 signing operation with pre-hash
238*/
239class 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 m_key(key.raw_private_key_bits()) {
243 m_hash = HashFunction::create_or_throw(hash);
244
245 if(rfc8032) {
246 m_domain_sep = std::vector<uint8_t>{0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
247 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
248 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
249 }
250 }
251
252 size_t signature_length() const override { return 64; }
253
254 void update(std::span<const uint8_t> msg) override { m_hash->update(msg); }
255
256 std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
257 std::vector<uint8_t> sig(64);
258 std::vector<uint8_t> msg_hash(m_hash->output_length());
259 m_hash->final(msg_hash.data());
261 sig.data(), msg_hash.data(), msg_hash.size(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
262 return sig;
263 }
264
265 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
275std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_verification_op(std::string_view params,
276 std::string_view provider) const {
277 if(provider == "base" || provider.empty()) {
278 if(params.empty() || params == "Identity" || params == "Pure") {
279 return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
280 } else if(params == "Ed25519ph") {
281 return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, "SHA-512", true);
282 } else {
283 return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, params, false);
284 }
285 }
286 throw Provider_Not_Found(algo_name(), provider);
287}
288
289std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_x509_verification_op(const AlgorithmIdentifier& alg_id,
290 std::string_view provider) const {
291 if(provider == "base" || provider.empty()) {
292 if(alg_id != this->algorithm_identifier()) {
293 throw Decoding_Error("Unexpected AlgorithmIdentifier for Ed25519 X509 signature");
294 }
295
296 return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
297 }
298 throw Provider_Not_Found(algo_name(), provider);
299}
300
301std::unique_ptr<PK_Ops::Signature> Ed25519_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
302 std::string_view params,
303 std::string_view provider) const {
304 if(provider == "base" || provider.empty()) {
305 if(params.empty() || params == "Identity" || params == "Pure") {
306 return std::make_unique<Ed25519_Pure_Sign_Operation>(*this);
307 } else if(params == "Ed25519ph") {
308 return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, "SHA-512", true);
309 } else {
310 return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, params, false);
311 }
312 }
313 throw Provider_Not_Found(algo_name(), provider);
314}
315
316} // namespace Botan
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
Definition assert.h:88
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
virtual OID object_identifier() const
Definition pk_keys.cpp:22
BER_Decoder & decode(bool &out)
Definition ber_dec.h:188
BER_Decoder & discard_remaining()
Definition ber_dec.cpp:231
secure_vector< uint8_t > get_contents()
Definition der_enc.cpp:134
DER_Encoder & encode(bool b)
Definition der_enc.cpp:252
Ed25519_PrivateKey(const AlgorithmIdentifier &alg_id, std::span< const uint8_t > key_bits)
static Ed25519_PrivateKey from_seed(std::span< const uint8_t > seed)
std::unique_ptr< Public_Key > public_key() const override
bool check_key(RandomNumberGenerator &rng, bool strong) const override
static Ed25519_PrivateKey from_bytes(std::span< const uint8_t > bytes)
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
secure_vector< uint8_t > private_key_bits() const override
std::vector< uint8_t > m_public
Definition ed25519.h:61
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
const std::vector< uint8_t > & get_public_key() const
Definition ed25519.h:37
bool check_key(RandomNumberGenerator &rng, bool strong) const override
std::string algo_name() const override
Definition ed25519.h:19
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
std::vector< uint8_t > public_key_bits() const override
AlgorithmIdentifier algorithm_identifier() const override
std::vector< uint8_t > raw_public_key_bits() const override
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:298
void random_vec(std::span< uint8_t > v)
Definition rng.h:199
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:826
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:145
void ed25519_sign(uint8_t sig[64], const uint8_t m[], size_t mlen, const uint8_t sk[64], const uint8_t domain_sep[], size_t domain_sep_len)
Definition ed25519.cpp:36
bool signature_check(std::span< const uint8_t, 32 > pk, const uint8_t h[32], const uint8_t r[32], const uint8_t s[32])
Definition ge.cpp:1904
void ed25519_gen_keypair(uint8_t pk[32], uint8_t sk[64], const uint8_t seed[32])
Definition ed25519.cpp:20
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:69
bool ed25519_verify(const uint8_t *m, size_t mlen, const uint8_t sig[64], const uint8_t *pk, const uint8_t domain_sep[], size_t domain_sep_len)
Definition ed25519.cpp:72