rippled
Loading...
Searching...
No Matches
SecretKey.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/contract.h>
21#include <xrpl/basics/strHex.h>
22#include <xrpl/beast/utility/rngfill.h>
23#include <xrpl/crypto/csprng.h>
24#include <xrpl/crypto/secure_erase.h>
25#include <xrpl/protocol/SecretKey.h>
26#include <xrpl/protocol/detail/secp256k1.h>
27#include <xrpl/protocol/digest.h>
28#include <cstring>
29#include <ed25519.h>
30
31namespace ripple {
32
34{
35 secure_erase(buf_, sizeof(buf_));
36}
37
39{
40 std::memcpy(buf_, key.data(), key.size());
41}
42
44{
45 if (slice.size() != sizeof(buf_))
46 LogicError("SecretKey::SecretKey: invalid size");
47 std::memcpy(buf_, slice.data(), sizeof(buf_));
48}
49
52{
53 return strHex(*this);
54}
55
56namespace detail {
57
58void
60{
61 *out++ = v >> 24;
62 *out++ = (v >> 16) & 0xff;
63 *out++ = (v >> 8) & 0xff;
64 *out = v & 0xff;
65}
66
69{
70 // We fill this buffer with the seed and append a 32-bit "counter"
71 // that counts how many attempts we've had to make to generate a
72 // non-zero key that's less than the curve's order:
73 //
74 // 1 2
75 // 0 6 0
76 // buf |----------------|----|
77 // | seed | seq|
78
80 std::copy(seed.begin(), seed.end(), buf.begin());
81
82 // The odds that this loop executes more than once are neglible
83 // but *just* in case someone managed to generate a key that required
84 // more iterations loop a few times.
85 for (std::uint32_t seq = 0; seq != 128; ++seq)
86 {
87 copy_uint32(buf.data() + 16, seq);
88
89 auto const ret = sha512Half(buf);
90
91 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
92 {
93 secure_erase(buf.data(), buf.size());
94 return ret;
95 }
96 }
97
98 Throw<std::runtime_error>("Unable to derive generator from seed");
99}
100
101//------------------------------------------------------------------------------
121{
122private:
125
126 uint256
128 {
129 // We fill the buffer with the generator, the provided sequence
130 // and a 32-bit counter tracking the number of attempts we have
131 // already made looking for a non-zero key that's less than the
132 // curve's order:
133 // 3 3 4
134 // 0 pubGen 3 7 1
135 // buf |---------------------------------|----|----|
136 // | generator | seq| cnt|
137
140 copy_uint32(buf.data() + 33, seq);
141
142 // The odds that this loop executes more than once are neglible
143 // but we impose a maximum limit just in case.
144 for (std::uint32_t subseq = 0; subseq != 128; ++subseq)
145 {
146 copy_uint32(buf.data() + 37, subseq);
147
148 auto const ret = sha512Half_s(buf);
149
150 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
151 {
152 secure_erase(buf.data(), buf.size());
153 return ret;
154 }
155 }
156
157 Throw<std::runtime_error>("Unable to derive generator from seed");
158 }
159
160public:
161 explicit Generator(Seed const& seed)
163 {
164 secp256k1_pubkey pubkey;
165 if (secp256k1_ec_pubkey_create(
166 secp256k1Context(), &pubkey, root_.data()) != 1)
167 LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
168
169 auto len = generator_.size();
170
171 if (secp256k1_ec_pubkey_serialize(
174 &len,
175 &pubkey,
176 SECP256K1_EC_COMPRESSED) != 1)
177 LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
178 }
179
181 {
184 }
185
188 operator()(std::size_t ordinal) const
189 {
190 // Generates Nth secret key:
191 auto gsk = [this, tweak = calculateTweak(ordinal)]() {
192 auto rpk = root_;
193
194 if (secp256k1_ec_seckey_tweak_add(
195 secp256k1Context(), rpk.data(), tweak.data()) == 1)
196 {
197 SecretKey sk{Slice{rpk.data(), rpk.size()}};
198 secure_erase(rpk.data(), rpk.size());
199 return sk;
200 }
201
202 LogicError("Unable to add a tweak!");
203 }();
204
205 return {derivePublicKey(KeyType::secp256k1, gsk), gsk};
206 }
207};
208
209} // namespace detail
210
211Buffer
212signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
213{
215 LogicError("sign: secp256k1 required for digest signing");
216
217 BOOST_ASSERT(sk.size() == 32);
218 secp256k1_ecdsa_signature sig_imp;
219 if (secp256k1_ecdsa_sign(
221 &sig_imp,
222 reinterpret_cast<unsigned char const*>(digest.data()),
223 reinterpret_cast<unsigned char const*>(sk.data()),
224 secp256k1_nonce_function_rfc6979,
225 nullptr) != 1)
226 LogicError("sign: secp256k1_ecdsa_sign failed");
227
228 unsigned char sig[72];
229 size_t len = sizeof(sig);
230 if (secp256k1_ecdsa_signature_serialize_der(
231 secp256k1Context(), sig, &len, &sig_imp) != 1)
232 LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
233
234 return Buffer{sig, len};
235}
236
237Buffer
238sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
239{
240 auto const type = publicKeyType(pk.slice());
241 if (!type)
242 LogicError("sign: invalid type");
243 switch (*type)
244 {
245 case KeyType::ed25519: {
246 Buffer b(64);
247 ed25519_sign(
248 m.data(), m.size(), sk.data(), pk.data() + 1, b.data());
249 return b;
250 }
251 case KeyType::secp256k1: {
253 h(m.data(), m.size());
255
256 secp256k1_ecdsa_signature sig_imp;
257 if (secp256k1_ecdsa_sign(
259 &sig_imp,
260 reinterpret_cast<unsigned char const*>(digest.data()),
261 reinterpret_cast<unsigned char const*>(sk.data()),
262 secp256k1_nonce_function_rfc6979,
263 nullptr) != 1)
264 LogicError("sign: secp256k1_ecdsa_sign failed");
265
266 unsigned char sig[72];
267 size_t len = sizeof(sig);
268 if (secp256k1_ecdsa_signature_serialize_der(
269 secp256k1Context(), sig, &len, &sig_imp) != 1)
271 "sign: secp256k1_ecdsa_signature_serialize_der failed");
272
273 return Buffer{sig, len};
274 }
275 default:
276 LogicError("sign: invalid type");
277 }
278}
279
280SecretKey
282{
283 std::uint8_t buf[32];
284 beast::rngfill(buf, sizeof(buf), crypto_prng());
285 SecretKey sk(Slice{buf, sizeof(buf)});
286 secure_erase(buf, sizeof(buf));
287 return sk;
288}
289
290SecretKey
292{
293 if (type == KeyType::ed25519)
294 {
295 auto key = sha512Half_s(Slice(seed.data(), seed.size()));
296 SecretKey sk{Slice{key.data(), key.size()}};
297 secure_erase(key.data(), key.size());
298 return sk;
299 }
300
301 if (type == KeyType::secp256k1)
302 {
303 auto key = detail::deriveDeterministicRootKey(seed);
304 SecretKey sk{Slice{key.data(), key.size()}};
305 secure_erase(key.data(), key.size());
306 return sk;
307 }
308
309 LogicError("generateSecretKey: unknown key type");
310}
311
312PublicKey
314{
315 switch (type)
316 {
317 case KeyType::secp256k1: {
318 secp256k1_pubkey pubkey_imp;
319 if (secp256k1_ec_pubkey_create(
321 &pubkey_imp,
322 reinterpret_cast<unsigned char const*>(sk.data())) != 1)
324 "derivePublicKey: secp256k1_ec_pubkey_create failed");
325
326 unsigned char pubkey[33];
327 std::size_t len = sizeof(pubkey);
328 if (secp256k1_ec_pubkey_serialize(
330 pubkey,
331 &len,
332 &pubkey_imp,
333 SECP256K1_EC_COMPRESSED) != 1)
335 "derivePublicKey: secp256k1_ec_pubkey_serialize failed");
336
337 return PublicKey{Slice{pubkey, len}};
338 }
339 case KeyType::ed25519: {
340 unsigned char buf[33];
341 buf[0] = 0xED;
342 ed25519_publickey(sk.data(), &buf[1]);
343 return PublicKey(Slice{buf, sizeof(buf)});
344 }
345 default:
346 LogicError("derivePublicKey: bad key type");
347 };
348}
349
351generateKeyPair(KeyType type, Seed const& seed)
352{
353 switch (type)
354 {
355 case KeyType::secp256k1: {
356 detail::Generator g(seed);
357 return g(0);
358 }
359 default:
360 case KeyType::ed25519: {
361 auto const sk = generateSecretKey(type, seed);
362 return {derivePublicKey(type, sk), sk};
363 }
364 }
365}
366
369{
370 auto const sk = randomSecretKey();
371 return {derivePublicKey(type, sk), sk};
372}
373
374template <>
377{
378 auto const result = decodeBase58Token(s, type);
379 if (result.empty())
380 return std::nullopt;
381 if (result.size() != 32)
382 return std::nullopt;
383 return SecretKey(makeSlice(result));
384}
385
386} // namespace ripple
T begin(T... args)
Like std::vector<char> but better.
Definition: Buffer.h:36
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Buffer.h:151
A public key.
Definition: PublicKey.h:62
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:87
Slice slice() const noexcept
Definition: PublicKey.h:123
A secret key.
Definition: SecretKey.h:37
std::uint8_t const * data() const
Definition: SecretKey.h:55
std::size_t size() const
Definition: SecretKey.h:61
std::uint8_t buf_[32]
Definition: SecretKey.h:39
std::string to_string() const
Convert the secret key to a hexadecimal string.
Definition: SecretKey.cpp:51
Seeds are used to generate deterministic secret keys.
Definition: Seed.h:33
std::size_t size() const
Definition: Seed.h:64
const_iterator end() const noexcept
Definition: Seed.h:82
const_iterator begin() const noexcept
Definition: Seed.h:70
std::uint8_t const * data() const
Definition: Seed.h:58
An immutable linear range of bytes.
Definition: Slice.h:45
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:97
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition: Slice.h:80
pointer data()
Definition: base_uint.h:124
static constexpr std::size_t size()
Definition: base_uint.h:525
Produces a sequence of secp256k1 key pairs.
Definition: SecretKey.cpp:121
uint256 calculateTweak(std::uint32_t seq) const
Definition: SecretKey.cpp:127
std::array< std::uint8_t, 33 > generator_
Definition: SecretKey.cpp:124
std::pair< PublicKey, SecretKey > operator()(std::size_t ordinal) const
Generate the nth key pair.
Definition: SecretKey.cpp:188
Generator(Seed const &seed)
Definition: SecretKey.cpp:161
T copy(T... args)
T data(T... args)
T end(T... args)
T memcpy(T... args)
void rngfill(void *buffer, std::size_t bytes, Generator &g)
Definition: rngfill.h:33
void copy_uint32(std::uint8_t *out, std::uint32_t v)
Definition: SecretKey.cpp:59
uint256 deriveDeterministicRootKey(Seed const &seed)
Definition: SecretKey.cpp:68
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
secp256k1_context const * secp256k1Context()
Definition: secp256k1.h:29
sha512_half_hasher_s::result_type sha512Half_s(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:239
TokenType
Definition: tokens.h:38
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Definition: AccountID.cpp:116
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:351
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
Definition: csprng.cpp:99
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:291
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
Definition: SecretKey.cpp:238
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition: tokens.cpp:205
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:207
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
static Hasher::result_type digest(void const *data, std::size_t size) noexcept
Definition: tokens.cpp:152
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:243
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
KeyType
Definition: KeyType.h:28
Buffer signDigest(PublicKey const &pk, SecretKey const &sk, uint256 const &digest)
Generate a signature for a message digest.
Definition: SecretKey.cpp:212
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:223
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
void secure_erase(void *dest, std::size_t bytes)
Attempts to clear the given blob of memory.
T size(T... args)
Returns the SHA512-Half digest of a message.
Definition: digest.h:171