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/Buffer.h>
21#include <xrpl/basics/Slice.h>
22#include <xrpl/basics/base_uint.h>
23#include <xrpl/basics/contract.h>
24#include <xrpl/basics/strHex.h>
25#include <xrpl/beast/utility/rngfill.h>
26#include <xrpl/crypto/csprng.h>
27#include <xrpl/crypto/secure_erase.h>
28#include <xrpl/protocol/KeyType.h>
29#include <xrpl/protocol/PublicKey.h>
30#include <xrpl/protocol/SecretKey.h>
31#include <xrpl/protocol/Seed.h>
32#include <xrpl/protocol/detail/secp256k1.h>
33#include <xrpl/protocol/digest.h>
34#include <xrpl/protocol/tokens.h>
35
36#include <boost/utility/string_view.hpp>
37#include <ed25519.h>
38#include <secp256k1.h>
39
40#include <algorithm>
41#include <array>
42#include <cstdint>
43#include <cstring>
44#include <optional>
45#include <stdexcept>
46#include <utility>
47
48namespace ripple {
49
51{
52 secure_erase(buf_, sizeof(buf_));
53}
54
56{
57 std::memcpy(buf_, key.data(), key.size());
58}
59
61{
62 if (slice.size() != sizeof(buf_))
63 LogicError("SecretKey::SecretKey: invalid size");
64 std::memcpy(buf_, slice.data(), sizeof(buf_));
65}
66
69{
70 return strHex(*this);
71}
72
73namespace detail {
74
75void
77{
78 *out++ = v >> 24;
79 *out++ = (v >> 16) & 0xff;
80 *out++ = (v >> 8) & 0xff;
81 *out = v & 0xff;
82}
83
86{
87 // We fill this buffer with the seed and append a 32-bit "counter"
88 // that counts how many attempts we've had to make to generate a
89 // non-zero key that's less than the curve's order:
90 //
91 // 1 2
92 // 0 6 0
93 // buf |----------------|----|
94 // | seed | seq|
95
97 std::copy(seed.begin(), seed.end(), buf.begin());
98
99 // The odds that this loop executes more than once are neglible
100 // but *just* in case someone managed to generate a key that required
101 // more iterations loop a few times.
102 for (std::uint32_t seq = 0; seq != 128; ++seq)
103 {
104 copy_uint32(buf.data() + 16, seq);
105
106 auto const ret = sha512Half(buf);
107
108 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
109 {
110 secure_erase(buf.data(), buf.size());
111 return ret;
112 }
113 }
114
115 Throw<std::runtime_error>("Unable to derive generator from seed");
116}
117
118//------------------------------------------------------------------------------
138{
139private:
142
143 uint256
145 {
146 // We fill the buffer with the generator, the provided sequence
147 // and a 32-bit counter tracking the number of attempts we have
148 // already made looking for a non-zero key that's less than the
149 // curve's order:
150 // 3 3 4
151 // 0 pubGen 3 7 1
152 // buf |---------------------------------|----|----|
153 // | generator | seq| cnt|
154
157 copy_uint32(buf.data() + 33, seq);
158
159 // The odds that this loop executes more than once are neglible
160 // but we impose a maximum limit just in case.
161 for (std::uint32_t subseq = 0; subseq != 128; ++subseq)
162 {
163 copy_uint32(buf.data() + 37, subseq);
164
165 auto const ret = sha512Half_s(buf);
166
167 if (secp256k1_ec_seckey_verify(secp256k1Context(), ret.data()) == 1)
168 {
169 secure_erase(buf.data(), buf.size());
170 return ret;
171 }
172 }
173
174 Throw<std::runtime_error>("Unable to derive generator from seed");
175 }
176
177public:
178 explicit Generator(Seed const& seed)
180 {
181 secp256k1_pubkey pubkey;
182 if (secp256k1_ec_pubkey_create(
183 secp256k1Context(), &pubkey, root_.data()) != 1)
184 LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
185
186 auto len = generator_.size();
187
188 if (secp256k1_ec_pubkey_serialize(
191 &len,
192 &pubkey,
193 SECP256K1_EC_COMPRESSED) != 1)
194 LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
195 }
196
198 {
201 }
202
205 operator()(std::size_t ordinal) const
206 {
207 // Generates Nth secret key:
208 auto gsk = [this, tweak = calculateTweak(ordinal)]() {
209 auto rpk = root_;
210
211 if (secp256k1_ec_seckey_tweak_add(
212 secp256k1Context(), rpk.data(), tweak.data()) == 1)
213 {
214 SecretKey sk{Slice{rpk.data(), rpk.size()}};
215 secure_erase(rpk.data(), rpk.size());
216 return sk;
217 }
218
219 LogicError("Unable to add a tweak!");
220 }();
221
222 return {derivePublicKey(KeyType::secp256k1, gsk), gsk};
223 }
224};
225
226} // namespace detail
227
228Buffer
229signDigest(PublicKey const& pk, SecretKey const& sk, uint256 const& digest)
230{
232 LogicError("sign: secp256k1 required for digest signing");
233
234 BOOST_ASSERT(sk.size() == 32);
235 secp256k1_ecdsa_signature sig_imp;
236 if (secp256k1_ecdsa_sign(
238 &sig_imp,
239 reinterpret_cast<unsigned char const*>(digest.data()),
240 reinterpret_cast<unsigned char const*>(sk.data()),
241 secp256k1_nonce_function_rfc6979,
242 nullptr) != 1)
243 LogicError("sign: secp256k1_ecdsa_sign failed");
244
245 unsigned char sig[72];
246 size_t len = sizeof(sig);
247 if (secp256k1_ecdsa_signature_serialize_der(
248 secp256k1Context(), sig, &len, &sig_imp) != 1)
249 LogicError("sign: secp256k1_ecdsa_signature_serialize_der failed");
250
251 return Buffer{sig, len};
252}
253
254Buffer
255sign(PublicKey const& pk, SecretKey const& sk, Slice const& m)
256{
257 auto const type = publicKeyType(pk.slice());
258 if (!type)
259 LogicError("sign: invalid type");
260 switch (*type)
261 {
262 case KeyType::ed25519: {
263 Buffer b(64);
264 ed25519_sign(
265 m.data(), m.size(), sk.data(), pk.data() + 1, b.data());
266 return b;
267 }
268 case KeyType::secp256k1: {
270 h(m.data(), m.size());
272
273 secp256k1_ecdsa_signature sig_imp;
274 if (secp256k1_ecdsa_sign(
276 &sig_imp,
277 reinterpret_cast<unsigned char const*>(digest.data()),
278 reinterpret_cast<unsigned char const*>(sk.data()),
279 secp256k1_nonce_function_rfc6979,
280 nullptr) != 1)
281 LogicError("sign: secp256k1_ecdsa_sign failed");
282
283 unsigned char sig[72];
284 size_t len = sizeof(sig);
285 if (secp256k1_ecdsa_signature_serialize_der(
286 secp256k1Context(), sig, &len, &sig_imp) != 1)
288 "sign: secp256k1_ecdsa_signature_serialize_der failed");
289
290 return Buffer{sig, len};
291 }
292 default:
293 LogicError("sign: invalid type");
294 }
295}
296
297SecretKey
299{
300 std::uint8_t buf[32];
301 beast::rngfill(buf, sizeof(buf), crypto_prng());
302 SecretKey sk(Slice{buf, sizeof(buf)});
303 secure_erase(buf, sizeof(buf));
304 return sk;
305}
306
307SecretKey
309{
310 if (type == KeyType::ed25519)
311 {
312 auto key = sha512Half_s(Slice(seed.data(), seed.size()));
313 SecretKey sk{Slice{key.data(), key.size()}};
314 secure_erase(key.data(), key.size());
315 return sk;
316 }
317
318 if (type == KeyType::secp256k1)
319 {
320 auto key = detail::deriveDeterministicRootKey(seed);
321 SecretKey sk{Slice{key.data(), key.size()}};
322 secure_erase(key.data(), key.size());
323 return sk;
324 }
325
326 LogicError("generateSecretKey: unknown key type");
327}
328
329PublicKey
331{
332 switch (type)
333 {
334 case KeyType::secp256k1: {
335 secp256k1_pubkey pubkey_imp;
336 if (secp256k1_ec_pubkey_create(
338 &pubkey_imp,
339 reinterpret_cast<unsigned char const*>(sk.data())) != 1)
341 "derivePublicKey: secp256k1_ec_pubkey_create failed");
342
343 unsigned char pubkey[33];
344 std::size_t len = sizeof(pubkey);
345 if (secp256k1_ec_pubkey_serialize(
347 pubkey,
348 &len,
349 &pubkey_imp,
350 SECP256K1_EC_COMPRESSED) != 1)
352 "derivePublicKey: secp256k1_ec_pubkey_serialize failed");
353
354 return PublicKey{Slice{pubkey, len}};
355 }
356 case KeyType::ed25519: {
357 unsigned char buf[33];
358 buf[0] = 0xED;
359 ed25519_publickey(sk.data(), &buf[1]);
360 return PublicKey(Slice{buf, sizeof(buf)});
361 }
362 default:
363 LogicError("derivePublicKey: bad key type");
364 };
365}
366
368generateKeyPair(KeyType type, Seed const& seed)
369{
370 switch (type)
371 {
372 case KeyType::secp256k1: {
373 detail::Generator g(seed);
374 return g(0);
375 }
376 default:
377 case KeyType::ed25519: {
378 auto const sk = generateSecretKey(type, seed);
379 return {derivePublicKey(type, sk), sk};
380 }
381 }
382}
383
386{
387 auto const sk = randomSecretKey();
388 return {derivePublicKey(type, sk), sk};
389}
390
391template <>
394{
395 auto const result = decodeBase58Token(s, type);
396 if (result.empty())
397 return std::nullopt;
398 if (result.size() != 32)
399 return std::nullopt;
400 return SecretKey(makeSlice(result));
401}
402
403} // namespace ripple
T begin(T... args)
Like std::vector<char> but better.
Definition: Buffer.h:35
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Buffer.h:150
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:38
std::uint8_t const * data() const
Definition: SecretKey.h:56
std::size_t size() const
Definition: SecretKey.h:62
std::uint8_t buf_[32]
Definition: SecretKey.h:40
std::string to_string() const
Convert the secret key to a hexadecimal string.
Definition: SecretKey.cpp:68
Seeds are used to generate deterministic secret keys.
Definition: Seed.h:34
std::size_t size() const
Definition: Seed.h:65
const_iterator end() const noexcept
Definition: Seed.h:83
const_iterator begin() const noexcept
Definition: Seed.h:71
std::uint8_t const * data() const
Definition: Seed.h:59
An immutable linear range of bytes.
Definition: Slice.h:46
std::uint8_t const * data() const noexcept
Return a pointer to beginning of the storage.
Definition: Slice.h:98
std::size_t size() const noexcept
Returns the number of bytes in the storage.
Definition: Slice.h:81
pointer data()
Definition: base_uint.h:125
static constexpr std::size_t size()
Definition: base_uint.h:526
Produces a sequence of secp256k1 key pairs.
Definition: SecretKey.cpp:138
uint256 calculateTweak(std::uint32_t seq) const
Definition: SecretKey.cpp:144
std::array< std::uint8_t, 33 > generator_
Definition: SecretKey.cpp:141
std::pair< PublicKey, SecretKey > operator()(std::size_t ordinal) const
Generate the nth key pair.
Definition: SecretKey.cpp:205
Generator(Seed const &seed)
Definition: SecretKey.cpp:178
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:34
void copy_uint32(std::uint8_t *out, std::uint32_t v)
Definition: SecretKey.cpp:76
uint256 deriveDeterministicRootKey(Seed const &seed)
Definition: SecretKey.cpp:85
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:241
TokenType
Definition: tokens.h:38
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Definition: AccountID.cpp:124
std::pair< PublicKey, SecretKey > generateKeyPair(KeyType type, Seed const &seed)
Generate a key pair deterministically.
Definition: SecretKey.cpp:368
csprng_engine & crypto_prng()
The default cryptographically secure PRNG.
Definition: csprng.cpp:103
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:330
SecretKey generateSecretKey(KeyType type, Seed const &seed)
Generate a new secret key deterministically.
Definition: SecretKey.cpp:308
Buffer sign(PublicKey const &pk, SecretKey const &sk, Slice const &message)
Generate a signature for a message.
Definition: SecretKey.cpp:255
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition: tokens.cpp:209
std::optional< KeyType > publicKeyType(Slice const &slice)
Returns the type of public key.
Definition: PublicKey.cpp:222
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:156
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:244
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:298
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:229
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:385
sha512_half_hasher::result_type sha512Half(Args const &... args)
Returns the SHA512-Half of a series of objects.
Definition: digest.h:225
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:50
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:173