Botan 3.11.1
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
130 const secure_vector<uint8_t> bits(m_private.data(), &m_private[32]);
132}
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 m_msg.clear();
152 return false;
153 }
154
155 BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
156 const bool ok = ed25519_verify(m_msg.data(), m_msg.size(), sig.data(), m_key.data(), nullptr, 0);
157 m_msg.clear();
158 return ok;
159 }
160
161 std::string hash_function() const override { return "SHA-512"; }
162
163 private:
164 std::vector<uint8_t> m_msg;
165 std::vector<uint8_t> m_key;
166};
167
168/**
169* Ed25519 verifying operation with pre-hash
170*/
171class Ed25519_Hashed_Verify_Operation final : public PK_Ops::Verification_with_Hash {
172 public:
173 Ed25519_Hashed_Verify_Operation(const Ed25519_PublicKey& key, std::string_view hash, bool rfc8032) :
174 PK_Ops::Verification_with_Hash(hash), m_key(key.get_public_key()) {
175 if(rfc8032) {
176 m_domain_sep = {0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
177 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
178 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
179 }
180 }
181
182 bool verify(std::span<const uint8_t> ph, std::span<const uint8_t> sig) override {
183 if(sig.size() != 64) {
184 return false;
185 }
186
187 BOTAN_ASSERT_EQUAL(m_key.size(), 32, "Expected size");
188 return ed25519_verify(
189 ph.data(), ph.size(), sig.data(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
190 }
191
192 private:
193 std::vector<uint8_t> m_key;
194 std::vector<uint8_t> m_domain_sep;
195};
196
197/**
198* Ed25519 signing operation ('pure' - signs message directly)
199*/
200class Ed25519_Pure_Sign_Operation final : public PK_Ops::Signature {
201 public:
202 explicit Ed25519_Pure_Sign_Operation(const Ed25519_PrivateKey& key) : m_key(key.raw_private_key_bits()) {}
203
204 void update(std::span<const uint8_t> msg) override { m_msg.insert(m_msg.end(), msg.begin(), msg.end()); }
205
206 std::vector<uint8_t> sign(RandomNumberGenerator& /*rng*/) override {
207 std::vector<uint8_t> sig(64);
208 ed25519_sign(sig.data(), m_msg.data(), m_msg.size(), m_key.data(), nullptr, 0);
209 m_msg.clear();
210 return sig;
211 }
212
213 size_t signature_length() const override { return 64; }
214
215 AlgorithmIdentifier algorithm_identifier() const override;
216
217 std::string hash_function() const override { return "SHA-512"; }
218
219 private:
220 std::vector<uint8_t> m_msg;
222};
223
224AlgorithmIdentifier Ed25519_Pure_Sign_Operation::algorithm_identifier() const {
225 return AlgorithmIdentifier(OID::from_string("Ed25519"), AlgorithmIdentifier::USE_EMPTY_PARAM);
226}
227
228/**
229* Ed25519 signing operation with pre-hash
230*/
231class Ed25519_Hashed_Sign_Operation final : public PK_Ops::Signature_with_Hash {
232 public:
233 Ed25519_Hashed_Sign_Operation(const Ed25519_PrivateKey& key, std::string_view hash, bool rfc8032) :
234 PK_Ops::Signature_with_Hash(hash), m_key(key.raw_private_key_bits()) {
235 if(rfc8032) {
236 m_domain_sep = std::vector<uint8_t>{0x53, 0x69, 0x67, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x6E,
237 0x6F, 0x20, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x20, 0x63, 0x6F,
238 0x6C, 0x6C, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0x73, 0x01, 0x00};
239 }
240 }
241
242 size_t signature_length() const override { return 64; }
243
244 std::vector<uint8_t> raw_sign(std::span<const uint8_t> ph, RandomNumberGenerator& /*rng*/) override {
245 std::vector<uint8_t> sig(64);
246 ed25519_sign(sig.data(), ph.data(), ph.size(), m_key.data(), m_domain_sep.data(), m_domain_sep.size());
247 return sig;
248 }
249
250 private:
251 secure_vector<uint8_t> m_key;
252 std::vector<uint8_t> m_domain_sep;
253};
254
255} // namespace
256
257std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_verification_op(std::string_view params,
258 std::string_view provider) const {
259 if(provider == "base" || provider.empty()) {
260 if(params.empty() || params == "Identity" || params == "Pure") {
261 return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
262 } else if(params == "Ed25519ph") {
263 return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, "SHA-512", true);
264 } else {
265 return std::make_unique<Ed25519_Hashed_Verify_Operation>(*this, params, false);
266 }
267 }
268 throw Provider_Not_Found(algo_name(), provider);
269}
270
271std::unique_ptr<PK_Ops::Verification> Ed25519_PublicKey::create_x509_verification_op(const AlgorithmIdentifier& alg_id,
272 std::string_view provider) const {
273 if(provider == "base" || provider.empty()) {
274 if(alg_id != this->algorithm_identifier()) {
275 throw Decoding_Error("Unexpected AlgorithmIdentifier for Ed25519 X509 signature");
276 }
277
278 return std::make_unique<Ed25519_Pure_Verify_Operation>(*this);
279 }
280 throw Provider_Not_Found(algo_name(), provider);
281}
282
283std::unique_ptr<PK_Ops::Signature> Ed25519_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
284 std::string_view params,
285 std::string_view provider) const {
286 if(provider == "base" || provider.empty()) {
287 if(params.empty() || params == "Identity" || params == "Pure") {
288 return std::make_unique<Ed25519_Pure_Sign_Operation>(*this);
289 } else if(params == "Ed25519ph") {
290 return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, "SHA-512", true);
291 } else {
292 return std::make_unique<Ed25519_Hashed_Sign_Operation>(*this, params, false);
293 }
294 }
295 throw Provider_Not_Found(algo_name(), provider);
296}
297
298} // 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:234
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
void random_vec(std::span< uint8_t > v)
Definition rng.h:204
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
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:34
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:18
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
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:70