Refactor GenerateDeterministicKey and its call sites:

Remove the use of ec_key parameters and return values from ECDSA crypto
prototypes.  Don't store key data into an ec_key variable only to fetch
it back into the original type again.  Use uint256 and Blob explicitly.

Pass private keys as uint256, and pass public keys as either pointer and
length or Blob in calls to ECDSA{Sign,Verify}() and {en,de}cryptECIES().

Replace GenerateRootDeterministicKey() with separate functions returning
either the public or private key, since no caller needs both at once.

Simplify the use of GenerateDeterministicKey within RippleAddress.  Call
a single routine rather than pass the result of one as input to another.

Add openssl unit with RAII classes for bignum, bn_ctx, and ec_point plus
free utility functions.

Rewrite the functions in GenerateDeterministicKey.cpp to use RAII rather
than explicit cleanup code:
  * factor out secp256k1_group and secp256k1_order for reuse rather than
    computing them each time
  * replace getPublicKey() with serialize_ec_point(), which makes, sets,
    and destroys an ec_key internally (sparing the caller those details)
    and calls i2o_ECPublicKey() directly
  * return bignum rather than ec_key from GenerateRootDeterministicKey()
  * return ec_point rather than EC_KEY* from GenerateRootPubKey()

Move ECDSA{Private,Public}Key() to a new ECDSAKey unit.
Move ec_key.h into impl/ since it's no longer used outside crypto/.

Remove now-unused member functions from ec_key.

Change tabs to spaces; trim trailing whitespace (including blank lines).
This commit is contained in:
Josh Juran
2015-01-06 12:51:38 -08:00
committed by Tom Ritchford
parent be44f75d2d
commit 7a6d533014
19 changed files with 649 additions and 483 deletions

14
Builds/VisualStudio2013/RippleD.vcxproj Executable file → Normal file
View File

@@ -1945,8 +1945,6 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\crypto\ECIES.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\crypto\ec_key.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\crypto\GenerateDeterministicKey.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\Base58.cpp">
@@ -1967,15 +1965,27 @@
<ClCompile Include="..\..\src\ripple\crypto\impl\ECDSACanonical.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\ECDSAKey.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\ECDSAKey.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\ECIES.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\ec_key.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\ec_key.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\GenerateDeterministicKey.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\openssl.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\openssl.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\RandomNumbers.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>

View File

@@ -2871,9 +2871,6 @@
<ClInclude Include="..\..\src\ripple\crypto\ECIES.h">
<Filter>ripple\crypto</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\crypto\ec_key.h">
<Filter>ripple\crypto</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\crypto\GenerateDeterministicKey.h">
<Filter>ripple\crypto</Filter>
</ClInclude>
@@ -2895,15 +2892,30 @@
<ClCompile Include="..\..\src\ripple\crypto\impl\ECDSACanonical.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\ECDSAKey.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\ECDSAKey.h">
<Filter>ripple\crypto\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\ECIES.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\ec_key.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\ec_key.h">
<Filter>ripple\crypto\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\GenerateDeterministicKey.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\crypto\impl\openssl.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\crypto\impl\openssl.h">
<Filter>ripple\crypto\impl</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\crypto\impl\RandomNumbers.cpp">
<Filter>ripple\crypto\impl</Filter>
</ClCompile>

View File

@@ -20,18 +20,17 @@
#ifndef RIPPLE_CRYPTO_ECDSA_H_INCLUDED
#define RIPPLE_CRYPTO_ECDSA_H_INCLUDED
#include <ripple/crypto/ec_key.h>
#include <ripple/basics/base_uint.h>
#include <ripple/basics/Blob.h>
namespace ripple {
openssl::ec_key ECDSAPrivateKey (uint256 const& serialized);
openssl::ec_key ECDSAPublicKey (Blob const& serialized);
Blob ECDSASign (uint256 const& hash, uint256 const& key);
Blob ECDSASign (uint256 const& hash, const openssl::ec_key& key);
bool ECDSAVerify (uint256 const& hash, Blob const& sig, const openssl::ec_key& key);
bool ECDSAVerify (uint256 const& hash,
Blob const& sig,
std::uint8_t const* key_data,
std::size_t key_size);
} // ripple

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_CRYPTO_ECIES_H_INCLUDED
#define RIPPLE_CRYPTO_ECIES_H_INCLUDED
#include <ripple/crypto/ec_key.h>
#include <ripple/basics/base_uint.h>
#include <ripple/basics/Blob.h>
namespace ripple {
@@ -29,8 +29,8 @@ namespace ripple {
// encrypt/decrypt functions with integrity checking.
// Note that the other side must somehow know what keys to use
Blob encryptECIES (const openssl::ec_key& secretKey, const openssl::ec_key& publicKey, Blob const& plaintext);
Blob decryptECIES (const openssl::ec_key& secretKey, const openssl::ec_key& publicKey, Blob const& ciphertext);
Blob encryptECIES (uint256 const& secretKey, Blob const& publicKey, Blob const& plaintext);
Blob decryptECIES (uint256 const& secretKey, Blob const& publicKey, Blob const& ciphertext);
} // ripple

View File

@@ -25,15 +25,15 @@
#ifndef RIPPLE_CRYPTO_GENERATEDETERMINISTICKEY_H_INCLUDED
#define RIPPLE_CRYPTO_GENERATEDETERMINISTICKEY_H_INCLUDED
#include <ripple/crypto/ec_key.h>
#include <ripple/basics/base_uint.h>
#include <openssl/bn.h>
namespace ripple {
openssl::ec_key GenerateRootDeterministicKey (const uint128& passPhrase);
openssl::ec_key GeneratePublicDeterministicKey (Blob const& generator, int n);
openssl::ec_key GeneratePrivateDeterministicKey (Blob const& family, const BIGNUM* rootPriv, int n);
Blob GenerateRootDeterministicPublicKey (const uint128& passPhrase);
uint256 GenerateRootDeterministicPrivateKey (const uint128& passPhrase);
Blob GeneratePublicDeterministicKey (Blob const& generator, int n);
uint256 GeneratePrivateDeterministicKey (Blob const& family, uint128 const& seed, int n);
} // ripple

View File

@@ -25,6 +25,8 @@
#include <BeastConfig.h>
#include <ripple/crypto/ECDSA.h>
#include <ripple/crypto/ECDSACanonical.h>
#include <ripple/crypto/impl/ec_key.h>
#include <ripple/crypto/impl/ECDSAKey.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/hmac.h>
@@ -34,63 +36,7 @@ namespace ripple {
using openssl::ec_key;
static EC_KEY* new_initialized_EC_KEY()
{
EC_KEY* key = EC_KEY_new_by_curve_name (NID_secp256k1);
if (key == nullptr)
{
throw std::runtime_error ("new_initialized_EC_KEY() : EC_KEY_new_by_curve_name failed");
}
EC_KEY_set_conv_form (key, POINT_CONVERSION_COMPRESSED);
return key;
}
ec_key ECDSAPrivateKey (uint256 const& serialized)
{
EC_KEY* key = new_initialized_EC_KEY();
BIGNUM* bn = BN_bin2bn (serialized.begin(), serialized.size(), nullptr);
if (bn == nullptr)
{
// leaks key
throw std::runtime_error ("ec_key::ec_key: BN_bin2bn failed");
}
const bool ok = EC_KEY_set_private_key (key, bn);
BN_clear_free (bn);
if (! ok)
{
EC_KEY_free (key);
}
return ec_key::acquire ((ec_key::pointer_t) key);
}
ec_key ECDSAPublicKey (Blob const& serialized)
{
EC_KEY* key = new_initialized_EC_KEY();
std::uint8_t const* begin = &serialized[0];
if (o2i_ECPublicKey (&key, &begin, serialized.size()) != nullptr)
{
EC_KEY_set_conv_form (key, POINT_CONVERSION_COMPRESSED);
}
else
{
EC_KEY_free (key);
}
return ec_key::acquire ((ec_key::pointer_t) key);
}
Blob ECDSASign (uint256 const& hash, const openssl::ec_key& key)
static Blob ECDSASign (uint256 const& hash, const openssl::ec_key& key)
{
Blob result;
@@ -112,15 +58,28 @@ Blob ECDSASign (uint256 const& hash, const openssl::ec_key& key)
return result;
}
Blob ECDSASign (uint256 const& hash, uint256 const& key)
{
return ECDSASign (hash, ECDSAPrivateKey (key));
}
static bool ECDSAVerify (uint256 const& hash, std::uint8_t const* sig, size_t sigLen, EC_KEY* key)
{
// -1 = error, 0 = bad sig, 1 = good
return ECDSA_verify (0, hash.begin(), hash.size(), sig, sigLen, key) > 0;
}
bool ECDSAVerify (uint256 const& hash, Blob const& sig, const openssl::ec_key& key)
static bool ECDSAVerify (uint256 const& hash, Blob const& sig, const openssl::ec_key& key)
{
return ECDSAVerify (hash, sig.data(), sig.size(), (EC_KEY*) key.get());
}
bool ECDSAVerify (uint256 const& hash,
Blob const& sig,
std::uint8_t const* key_data,
std::size_t key_size)
{
return ECDSAVerify (hash, sig, ECDSAPublicKey (key_data, key_size));
}
} // ripple

View File

@@ -0,0 +1,92 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include <BeastConfig.h>
#include <ripple/crypto/impl/ECDSAKey.h>
#include <openssl/ec.h>
#include <openssl/hmac.h>
namespace ripple {
using openssl::ec_key;
static EC_KEY* new_initialized_EC_KEY()
{
EC_KEY* key = EC_KEY_new_by_curve_name (NID_secp256k1);
if (key == nullptr)
{
throw std::runtime_error ("new_initialized_EC_KEY() : EC_KEY_new_by_curve_name failed");
}
EC_KEY_set_conv_form (key, POINT_CONVERSION_COMPRESSED);
return key;
}
ec_key ECDSAPrivateKey (uint256 const& serialized)
{
BIGNUM* bn = BN_bin2bn (serialized.begin(), serialized.size(), nullptr);
if (bn == nullptr)
{
throw std::runtime_error ("ec_key::ec_key: BN_bin2bn failed");
}
EC_KEY* key = new_initialized_EC_KEY();
const bool ok = EC_KEY_set_private_key (key, bn);
BN_clear_free (bn);
if (! ok)
{
EC_KEY_free (key);
}
return ec_key::acquire ((ec_key::pointer_t) key);
}
ec_key ECDSAPublicKey (std::uint8_t const* data, std::size_t size)
{
EC_KEY* key = new_initialized_EC_KEY();
if (o2i_ECPublicKey (&key, &data, size) != nullptr)
{
EC_KEY_set_conv_form (key, POINT_CONVERSION_COMPRESSED);
}
else
{
EC_KEY_free (key);
}
return ec_key::acquire ((ec_key::pointer_t) key);
}
ec_key ECDSAPublicKey (Blob const& serialized)
{
return ECDSAPublicKey (&serialized[0], serialized.size());
}
} // ripple

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_ECDSAKEY_H
#define RIPPLE_ECDSAKEY_H
#include <ripple/basics/base_uint.h>
#include <ripple/basics/Blob.h>
#include <ripple/crypto/impl/ec_key.h>
namespace ripple {
openssl::ec_key ECDSAPrivateKey (uint256 const& serialized);
openssl::ec_key ECDSAPublicKey (Blob const& serialized);
openssl::ec_key ECDSAPublicKey (std::uint8_t const* data, std::size_t size);
} // ripple
#endif

View File

@@ -19,6 +19,8 @@
#include <BeastConfig.h>
#include <ripple/crypto/ECIES.h>
#include <ripple/crypto/impl/ec_key.h>
#include <ripple/crypto/impl/ECDSAKey.h>
#include <ripple/crypto/RandomNumbers.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
@@ -97,6 +99,14 @@ static void getECIESSecret (const openssl::ec_key& secretKey, const openssl::ec_
memset (hbuf, 0, ECIES_KEY_LENGTH);
}
static void getECIESSecret (uint256 const& secretKey,
Blob const& publicKey,
ECIES_ENC_KEY_TYPE& enc_key,
ECIES_HMAC_KEY_TYPE& hmac_key)
{
getECIESSecret (ECDSAPrivateKey (secretKey), ECDSAPublicKey (publicKey), enc_key, hmac_key);
}
static ECIES_HMAC_TYPE makeHMAC (const ECIES_HMAC_KEY_TYPE& secret, Blob const& data)
{
HMAC_CTX ctx;
@@ -129,7 +139,7 @@ static ECIES_HMAC_TYPE makeHMAC (const ECIES_HMAC_KEY_TYPE& secret, Blob const&
return ret;
}
Blob encryptECIES (const openssl::ec_key& secretKey, const openssl::ec_key& publicKey, Blob const& plaintext)
Blob encryptECIES (uint256 const& secretKey, Blob const& publicKey, Blob const& plaintext)
{
ECIES_ENC_IV_TYPE iv;
@@ -204,7 +214,7 @@ Blob encryptECIES (const openssl::ec_key& secretKey, const openssl::ec_key& publ
return out;
}
Blob decryptECIES (const openssl::ec_key& secretKey, const openssl::ec_key& publicKey, Blob const& ciphertext)
Blob decryptECIES (uint256 const& secretKey, Blob const& publicKey, Blob const& ciphertext)
{
// minimum ciphertext = IV + HMAC + 1 block
if (ciphertext.size () < ((2 * ECIES_ENC_BLK_SIZE) + ECIES_HMAC_SIZE) )

View File

@@ -19,17 +19,32 @@
#include <BeastConfig.h>
#include <ripple/crypto/GenerateDeterministicKey.h>
#include <ripple/crypto/Base58.h>
#include <ripple/crypto/CBigNum.h>
#include <ripple/crypto/impl/ec_key.h>
#include <ripple/crypto/impl/openssl.h>
#include <array>
#include <string>
#include <openssl/ec.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
namespace ripple {
using openssl::ec_key;
namespace openssl {
static EC_GROUP const* const secp256k1_group = EC_GROUP_new_by_curve_name (NID_secp256k1);
static bignum const secp256k1_order = get_order (secp256k1_group);
} // namespace openssl
using namespace openssl;
static Blob serialize_ec_point (ec_point const& point)
{
Blob result (33);
serialize_ec_point (point, &result[0]);
return result;
}
uint256
getSHA512Half (void const* data, std::size_t bytes)
@@ -56,43 +71,12 @@ copy_uint32 (FwdIt out, std::uint32_t v)
// --> seed
// <-- private root generator + public root generator
ec_key GenerateRootDeterministicKey (uint128 const& seed)
static bignum GenerateRootDeterministicKey (uint128 const& seed)
{
BN_CTX* ctx = BN_CTX_new ();
if (!ctx) return ec_key::invalid;
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
if (!pkey)
{
BN_CTX_free (ctx);
return ec_key::invalid;
}
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
BIGNUM* order = BN_new ();
if (!order)
{
BN_CTX_free (ctx);
EC_KEY_free (pkey);
return ec_key::invalid;
}
if (!EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
{
assert (false);
BN_free (order);
EC_KEY_free (pkey);
BN_CTX_free (ctx);
return ec_key::invalid;
}
// find non-zero private key less than the curve's order
BIGNUM* privKey = nullptr;
bignum privKey;
std::uint32_t seq = 0;
do
{
// buf: 0 seed 16 seq 20
@@ -102,114 +86,54 @@ ec_key GenerateRootDeterministicKey (uint128 const& seed)
copy_uint32 (buf.begin() + 16, seq++);
uint256 root = getSHA512Half (buf.data(), buf.size());
std::fill (buf.begin(), buf.end(), 0); // security erase
privKey = BN_bin2bn ((const unsigned char*) &root, sizeof (root), privKey);
if (privKey == nullptr)
{
EC_KEY_free (pkey);
BN_free (order);
BN_CTX_free (ctx);
return ec_key::invalid;
}
privKey.assign ((unsigned char const*) &root, sizeof (root));
root.zero(); // security erase
}
while (BN_is_zero (privKey) || (BN_cmp (privKey, order) >= 0));
while (privKey.is_zero() || privKey >= secp256k1_order);
BN_free (order);
if (!EC_KEY_set_private_key (pkey, privKey))
{
// set the random point as the private key
assert (false);
EC_KEY_free (pkey);
BN_clear_free (privKey);
BN_CTX_free (ctx);
return ec_key::invalid;
return privKey;
}
EC_POINT* pubKey = EC_POINT_new (EC_KEY_get0_group (pkey));
if (!EC_POINT_mul (EC_KEY_get0_group (pkey), pubKey, privKey, nullptr, nullptr, ctx))
// --> seed
// <-- private root generator + public root generator
Blob GenerateRootDeterministicPublicKey (uint128 const& seed)
{
bn_ctx ctx;
bignum privKey = GenerateRootDeterministicKey (seed);
// compute the corresponding public key point
assert (false);
BN_clear_free (privKey);
EC_POINT_free (pubKey);
EC_KEY_free (pkey);
BN_CTX_free (ctx);
return ec_key::invalid;
ec_point pubKey = multiply (secp256k1_group, privKey, ctx);
privKey.clear(); // security erase
return serialize_ec_point (pubKey);
}
BN_clear_free (privKey);
if (!EC_KEY_set_public_key (pkey, pubKey))
uint256 GenerateRootDeterministicPrivateKey (uint128 const& seed)
{
assert (false);
EC_POINT_free (pubKey);
EC_KEY_free (pkey);
BN_CTX_free (ctx);
return ec_key::invalid;
}
bignum key = GenerateRootDeterministicKey (seed);
EC_POINT_free (pubKey);
BN_CTX_free (ctx);
#ifdef EC_DEBUG
assert (EC_KEY_check_key (pkey) == 1); // CAUTION: This check is *very* expensive
#endif
return ec_key::acquire ((ec_key::pointer_t) pkey);
return uint256_from_bignum_clear (key);
}
// Take ripple address.
// --> root public generator (consumes)
// <-- root public generator in EC format
static EC_KEY* GenerateRootPubKey (BIGNUM* pubGenerator)
static ec_point GenerateRootPubKey (bignum&& pubGenerator)
{
if (pubGenerator == nullptr)
{
assert (false);
return nullptr;
}
ec_point pubPoint = bn2point (secp256k1_group, pubGenerator.get());
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
if (!pkey)
{
BN_free (pubGenerator);
return nullptr;
}
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
EC_POINT* pubPoint = EC_POINT_bn2point (EC_KEY_get0_group (pkey), pubGenerator, nullptr, nullptr);
BN_free (pubGenerator);
if (!pubPoint)
{
assert (false);
EC_KEY_free (pkey);
return nullptr;
}
if (!EC_KEY_set_public_key (pkey, pubPoint))
{
assert (false);
EC_POINT_free (pubPoint);
EC_KEY_free (pkey);
return nullptr;
}
EC_POINT_free (pubPoint);
return pkey;
return pubPoint;
}
// --> public generator
static BIGNUM* makeHash (Blob const& pubGen, int seq, BIGNUM const* order)
static bignum makeHash (Blob const& pubGen, int seq, bignum const& order)
{
int subSeq = 0;
BIGNUM* ret = nullptr;
bignum result;
assert(pubGen.size() == 33);
do
@@ -222,167 +146,51 @@ static BIGNUM* makeHash (Blob const& pubGen, int seq, BIGNUM const* order)
copy_uint32 (buf.begin() + 37, subSeq++);
uint256 root = getSHA512Half (buf.data(), buf.size());
std::fill(buf.begin(), buf.end(), 0); // security erase
ret = BN_bin2bn ((const unsigned char*) &root, sizeof (root), ret);
if (!ret) return nullptr;
result.assign ((unsigned char const*) &root, sizeof (root));
root.zero(); // security erase
}
while (BN_is_zero (ret) || (BN_cmp (ret, order) >= 0));
while (result.is_zero() || result >= order);
return ret;
return result;
}
// --> public generator
ec_key GeneratePublicDeterministicKey (Blob const& pubGen, int seq)
Blob GeneratePublicDeterministicKey (Blob const& pubGen, int seq)
{
// publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point
BIGNUM* generator = BN_bin2bn (
pubGen.data(),
pubGen.size(),
nullptr);
ec_point rootPubKey = GenerateRootPubKey (bignum (pubGen));
if (generator == nullptr)
return ec_key::invalid;
EC_KEY* rootKey = GenerateRootPubKey (generator);
const EC_POINT* rootPubKey = EC_KEY_get0_public_key (rootKey);
BN_CTX* ctx = BN_CTX_new ();
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
EC_POINT* newPoint = 0;
BIGNUM* order = 0;
BIGNUM* hash = 0;
bool success = true;
if (!ctx || !pkey) success = false;
if (success)
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
if (success)
{
newPoint = EC_POINT_new (EC_KEY_get0_group (pkey));
if (!newPoint) success = false;
}
if (success)
{
order = BN_new ();
if (!order || !EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
success = false;
}
bn_ctx ctx;
// Calculate the private additional key.
if (success)
{
hash = makeHash (pubGen, seq, order);
bignum hash = makeHash (pubGen, seq, secp256k1_order);
if (!hash) success = false;
}
if (success)
{
// Calculate the corresponding public key.
EC_POINT_mul (EC_KEY_get0_group (pkey), newPoint, hash, nullptr, nullptr, ctx);
ec_point newPoint = multiply (secp256k1_group, hash, ctx);
// Add the master public key and set.
EC_POINT_add (EC_KEY_get0_group (pkey), newPoint, newPoint, rootPubKey, ctx);
EC_KEY_set_public_key (pkey, newPoint);
}
add_to (secp256k1_group, rootPubKey, newPoint, ctx);
if (order) BN_free (order);
if (hash) BN_free (hash);
if (newPoint) EC_POINT_free (newPoint);
if (ctx) BN_CTX_free (ctx);
if (rootKey) EC_KEY_free (rootKey);
if (pkey && !success) EC_KEY_free (pkey);
return success ? ec_key::acquire ((ec_key::pointer_t) pkey) : ec_key::invalid;
return serialize_ec_point (newPoint);
}
// --> root private key
ec_key GeneratePrivateDeterministicKey (Blob const& pubGen, const BIGNUM* rootPrivKey, int seq)
uint256 GeneratePrivateDeterministicKey (Blob const& pubGen, uint128 const& seed, int seq)
{
// privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order
BN_CTX* ctx = BN_CTX_new ();
bignum rootPrivKey = GenerateRootDeterministicKey (seed);
if (ctx == nullptr) return ec_key::invalid;
EC_KEY* pkey = EC_KEY_new_by_curve_name (NID_secp256k1);
if (pkey == nullptr)
{
BN_CTX_free (ctx);
return ec_key::invalid;
}
EC_KEY_set_conv_form (pkey, POINT_CONVERSION_COMPRESSED);
BIGNUM* order = BN_new ();
if (order == nullptr)
{
BN_CTX_free (ctx);
EC_KEY_free (pkey);
return ec_key::invalid;
}
if (!EC_GROUP_get_order (EC_KEY_get0_group (pkey), order, ctx))
{
BN_free (order);
BN_CTX_free (ctx);
EC_KEY_free (pkey);
return ec_key::invalid;
}
bn_ctx ctx;
// calculate the private additional key
BIGNUM* privKey = makeHash (pubGen, seq, order);
if (privKey == nullptr)
{
BN_free (order);
BN_CTX_free (ctx);
EC_KEY_free (pkey);
return ec_key::invalid;
}
bignum privKey = makeHash (pubGen, seq, secp256k1_order);
// calculate the final private key
BN_mod_add (privKey, privKey, rootPrivKey, order, ctx);
BN_free (order);
EC_KEY_set_private_key (pkey, privKey);
add_to (rootPrivKey, privKey, secp256k1_order, ctx);
// compute the corresponding public key
EC_POINT* pubKey = EC_POINT_new (EC_KEY_get0_group (pkey));
rootPrivKey.clear(); // security erase
if (!pubKey)
{
BN_clear_free (privKey);
BN_CTX_free (ctx);
EC_KEY_free (pkey);
return ec_key::invalid;
}
if (EC_POINT_mul (EC_KEY_get0_group (pkey), pubKey, privKey, nullptr, nullptr, ctx) == 0)
{
BN_clear_free (privKey);
EC_POINT_free (pubKey);
EC_KEY_free (pkey);
BN_CTX_free (ctx);
return ec_key::invalid;
}
BN_clear_free (privKey);
EC_KEY_set_public_key (pkey, pubKey);
EC_POINT_free (pubKey);
BN_CTX_free (ctx);
return ec_key::acquire ((ec_key::pointer_t) pkey);
return uint256_from_bignum_clear (privKey);
}
} // ripple

View File

@@ -23,7 +23,7 @@
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include <BeastConfig.h>
#include <ripple/crypto/ec_key.h>
#include <ripple/crypto/impl/ec_key.h>
#include <openssl/ec.h>
namespace ripple {
@@ -63,53 +63,5 @@ void ec_key::destroy()
}
}
uint256 ec_key::get_private_key() const
{
uint256 result;
result.zero();
if (valid())
{
const BIGNUM* bn = EC_KEY_get0_private_key (get_EC_KEY (*this));
if (bn == nullptr)
{
throw std::runtime_error ("ec_key::get_private_key: EC_KEY_get0_private_key failed");
}
BN_bn2bin (bn, result.end() - BN_num_bytes (bn));
}
return result;
}
std::size_t ec_key::get_public_key_size() const
{
int const size = i2o_ECPublicKey (get_EC_KEY (*this), nullptr);
if (size == 0)
{
throw std::runtime_error ("ec_key::get_public_key_size() : i2o_ECPublicKey failed");
}
if (size > get_public_key_max_size())
{
throw std::runtime_error ("ec_key::get_public_key_size() : i2o_ECPublicKey() result too big");
}
return size;
}
std::uint8_t ec_key::get_public_key (std::uint8_t* buffer) const
{
std::uint8_t* begin = buffer;
int const size = i2o_ECPublicKey (get_EC_KEY (*this), &begin);
assert (size == get_public_key_size());
return std::uint8_t (size);
}
} // openssl
} // ripple

View File

@@ -67,14 +67,6 @@ public:
}
bool valid() const { return ptr != nullptr; }
uint256 get_private_key() const;
static std::size_t get_public_key_max_size() { return 33; }
std::size_t get_public_key_size() const;
std::uint8_t get_public_key (std::uint8_t* buffer) const;
};
} // openssl

View File

@@ -0,0 +1,154 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/crypto/impl/openssl.h>
#include <openssl/hmac.h>
namespace ripple {
namespace openssl {
bignum::bignum()
{
ptr = BN_new();
if (ptr == nullptr)
{
throw std::runtime_error ("BN_new() failed");
}
}
void bignum::assign (uint8_t const* data, size_t size)
{
// This reuses and assigns ptr
BIGNUM* bn = BN_bin2bn (data, size, ptr);
if (bn == nullptr)
{
throw std::runtime_error ("BN_bin2bn() failed");
}
}
void bignum::assign_new (uint8_t const* data, size_t size)
{
// ptr must not be allocated
ptr = BN_bin2bn (data, size, nullptr);
if (ptr == nullptr)
{
throw std::runtime_error ("BN_bin2bn() failed");
}
}
bn_ctx::bn_ctx()
{
ptr = BN_CTX_new();
if (ptr == nullptr)
{
throw std::runtime_error ("BN_CTX_new() failed");
}
}
bignum get_order (EC_GROUP const* group, bn_ctx& ctx)
{
bignum result;
if (!EC_GROUP_get_order (group, result.get(), ctx.get()))
{
throw std::runtime_error ("EC_GROUP_get_order() failed");
}
return result;
}
ec_point::ec_point (EC_GROUP const* group)
{
ptr = EC_POINT_new (group);
if (ptr == nullptr)
{
throw std::runtime_error ("EC_POINT_new() failed");
}
}
void add_to (EC_GROUP const* group,
ec_point const& a,
ec_point& b,
bn_ctx& ctx)
{
if (!EC_POINT_add (group, b.get(), a.get(), b.get(), ctx.get()))
{
throw std::runtime_error ("EC_POINT_add() failed");
}
}
ec_point multiply (EC_GROUP const* group,
bignum const& n,
bn_ctx& ctx)
{
ec_point result (group);
if (!EC_POINT_mul (group, result.get(), n.get(), nullptr, nullptr, ctx.get()))
{
throw std::runtime_error ("EC_POINT_mul() failed");
}
return result;
}
ec_point bn2point (EC_GROUP const* group, BIGNUM const* number)
{
EC_POINT* result = EC_POINT_bn2point (group, number, nullptr, nullptr);
if (result == nullptr)
{
throw std::runtime_error ("EC_POINT_bn2point() failed");
}
return ec_point::acquire (result);
}
static ec_key ec_key_new_secp256k1_compressed()
{
EC_KEY* key = EC_KEY_new_by_curve_name (NID_secp256k1);
if (key == nullptr) throw std::runtime_error ("EC_KEY_new_by_curve_name() failed");
EC_KEY_set_conv_form (key, POINT_CONVERSION_COMPRESSED);
return ec_key::acquire ((ec_key::pointer_t) key);
}
void serialize_ec_point (ec_point const& point, std::uint8_t* ptr)
{
ec_key key = ec_key_new_secp256k1_compressed();
if (EC_KEY_set_public_key((EC_KEY*) key.get(), point.get()) <= 0)
{
throw std::runtime_error ("EC_KEY_set_public_key() failed");
}
int const size = i2o_ECPublicKey ((EC_KEY*) key.get(), &ptr);
assert (size <= 33);
}
} // openssl
} // ripple

View File

@@ -0,0 +1,200 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_OPENSSL_H
#define RIPPLE_OPENSSL_H
#include <ripple/basics/base_uint.h>
#include <ripple/crypto/impl/ec_key.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
namespace ripple {
namespace openssl {
class bignum
{
private:
BIGNUM* ptr;
// non-copyable
bignum (bignum const&) = delete;
bignum& operator=(bignum const&) = delete;
void assign_new (uint8_t const* data, size_t size);
public:
bignum();
~bignum()
{
if ( ptr != nullptr)
{
BN_free (ptr);
}
}
bignum (uint8_t const* data, size_t size)
{
assign_new (data, size);
}
template <class T>
explicit bignum (T const& thing)
{
assign_new (thing.data(), thing.size());
}
bignum(bignum&& that) : ptr( that.ptr )
{
that.ptr = nullptr;
}
bignum& operator= (bignum&& that)
{
using std::swap;
swap( ptr, that.ptr );
return *this;
}
BIGNUM * get() { return ptr; }
BIGNUM const* get() const { return ptr; }
bool is_zero() const { return BN_is_zero (ptr); }
void clear() { BN_clear (ptr); }
void assign (uint8_t const* data, size_t size);
};
inline bool operator< (bignum const& a, bignum const& b)
{
return BN_cmp (a.get(), b.get()) < 0;
}
inline bool operator>= (bignum const& a, bignum const& b)
{
return !(a < b);
}
inline uint256 uint256_from_bignum_clear (bignum& number)
{
uint256 result;
result.zero();
BN_bn2bin (number.get(), result.end() - BN_num_bytes (number.get()));
number.clear();
return result;
}
class bn_ctx
{
private:
BN_CTX* ptr;
// non-copyable
bn_ctx (bn_ctx const&);
bn_ctx& operator=(bn_ctx const&);
public:
bn_ctx();
~bn_ctx()
{
BN_CTX_free (ptr);
}
BN_CTX * get() { return ptr; }
BN_CTX const* get() const { return ptr; }
};
bignum get_order (EC_GROUP const* group, bn_ctx& ctx);
inline bignum get_order (EC_GROUP const* group)
{
bn_ctx ctx;
return get_order (group, ctx);
}
inline void add_to (bignum const& a,
bignum& b,
bignum const& modulus,
bn_ctx& ctx)
{
BN_mod_add (b.get(), a.get(), b.get(), modulus.get(), ctx.get());
}
class ec_point
{
public:
typedef EC_POINT* pointer_t;
private:
pointer_t ptr;
ec_point (pointer_t raw) : ptr(raw)
{
}
public:
static ec_point acquire (pointer_t raw)
{
return ec_point (raw);
}
ec_point (EC_GROUP const* group);
~ec_point() { EC_POINT_free (ptr); }
ec_point (ec_point const&) = delete;
ec_point& operator=(ec_point const&) = delete;
ec_point(ec_point&& that)
{
ptr = that.ptr;
that.ptr = nullptr;
}
EC_POINT * get() { return ptr; }
EC_POINT const* get() const { return ptr; }
};
void add_to (EC_GROUP const* group,
ec_point const& a,
ec_point& b,
bn_ctx& ctx);
ec_point multiply (EC_GROUP const* group,
bignum const& n,
bn_ctx& ctx);
ec_point bn2point (EC_GROUP const* group, BIGNUM const* number);
// output buffer must hold 33 bytes
void serialize_ec_point (ec_point const& point, std::uint8_t* ptr);
} // openssl
} // ripple
#endif

View File

@@ -40,11 +40,8 @@ public:
seed1.SetHex ("71ED064155FFADFA38782C5E0158CB26");
seed2.SetHex ("CF0C3BE4485961858C4198515AE5B965");
openssl::ec_key root1 = GenerateRootDeterministicKey (seed1);
openssl::ec_key root2 = GenerateRootDeterministicKey (seed2);
uint256 const priv1 = root1.get_private_key();
uint256 const priv2 = root2.get_private_key();
uint256 const priv1 = GenerateRootDeterministicPrivateKey (seed1);
uint256 const priv2 = GenerateRootDeterministicPrivateKey (seed2);
unexpected (to_string (priv1) != "7CFBA64F771E93E817E15039215430B53F7401C34931D111EAB3510B22DBB0D8",
"Incorrect private key for generator");
@@ -57,4 +54,3 @@ public:
BEAST_DEFINE_TESTSUITE(CKey,ripple_data,ripple);
} // ripple

View File

@@ -30,18 +30,11 @@
#include <ripple/protocol/RipplePublicKey.h>
#include <beast/unit_test/suite.h>
#include <openssl/ripemd.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <mutex>
namespace ripple {
static BIGNUM* GetSecretBN (const openssl::ec_key& keypair)
{
// DEPRECATED
return BN_dup (EC_KEY_get0_private_key ((EC_KEY*) keypair.get()));
}
// <-- seed
static uint128 PassPhraseToKey (std::string const& passPhrase)
{
@@ -57,15 +50,6 @@ static uint128 PassPhraseToKey (std::string const& passPhrase)
return ret;
}
static Blob getPublicKey (openssl::ec_key const& key)
{
Blob result (33);
key.get_public_key (&result[0]);
return result;
}
static bool verifySignature (Blob const& pubkey, uint256 const& hash, Blob const& sig, ECDSA fullyCanonical)
{
if (! isCanonicalECDSASig (sig, fullyCanonical))
@@ -73,9 +57,7 @@ static bool verifySignature (Blob const& pubkey, uint256 const& hash, Blob const
return false;
}
openssl::ec_key key = ECDSAPublicKey (pubkey);
return key.valid() && ECDSAVerify (hash, sig, key);
return ECDSAVerify (hash, sig, &pubkey[0], pubkey.size());
}
RippleAddress::RippleAddress ()
@@ -116,7 +98,7 @@ RippleAddress RippleAddress::createNodePublic (RippleAddress const& naSeed)
RippleAddress naNew;
// YYY Should there be a GetPubKey() equiv that returns a uint256?
naNew.setNodePublic (getPublicKey (GenerateRootDeterministicKey (naSeed.getSeed())));
naNew.setNodePublic (GenerateRootDeterministicPublicKey (naSeed.getSeed()));
return naNew;
}
@@ -229,7 +211,7 @@ RippleAddress RippleAddress::createNodePrivate (RippleAddress const& naSeed)
{
RippleAddress naNew;
naNew.setNodePrivate (GenerateRootDeterministicKey (naSeed.getSeed()).get_private_key());
naNew.setNodePrivate (GenerateRootDeterministicPrivateKey (naSeed.getSeed()));
return naNew;
}
@@ -302,9 +284,7 @@ void RippleAddress::setNodePrivate (uint256 hash256)
void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
{
openssl::ec_key key = ECDSAPrivateKey (getNodePrivate());
vchSig = ECDSASign (hash, key);
vchSig = ECDSASign (hash, getNodePrivate());
if (vchSig.empty())
throw std::runtime_error ("Signing failed.");
@@ -502,7 +482,7 @@ void RippleAddress::setAccountPublic (Blob const& vPublic)
void RippleAddress::setAccountPublic (RippleAddress const& generator, int seq)
{
setAccountPublic (getPublicKey (GeneratePublicDeterministicKey (generator.getGenerator(), seq)));
setAccountPublic (GeneratePublicDeterministicKey (generator.getGenerator(), seq));
}
bool RippleAddress::accountPublicVerify (
@@ -571,26 +551,14 @@ void RippleAddress::setAccountPrivate (uint256 hash256)
void RippleAddress::setAccountPrivate (
RippleAddress const& generator, RippleAddress const& naSeed, int seq)
{
openssl::ec_key publicKey = GenerateRootDeterministicKey (naSeed.getSeed());
openssl::ec_key secretKey = GeneratePrivateDeterministicKey (generator.getGenerator(), GetSecretBN (publicKey), seq);
uint256 secretKey = GeneratePrivateDeterministicKey (generator.getGenerator(), naSeed.getSeed(), seq);
setAccountPrivate (secretKey.get_private_key());
setAccountPrivate (secretKey);
}
bool RippleAddress::accountPrivateSign (uint256 const& uHash, Blob& vucSig) const
{
openssl::ec_key key = ECDSAPrivateKey (getAccountPrivate());
if (!key.valid())
{
// Bad private key.
WriteLog (lsWARNING, RippleAddress)
<< "accountPrivateSign: Bad private key.";
return false;
}
vucSig = ECDSASign (uHash, key);
vucSig = ECDSASign (uHash, getAccountPrivate());
const bool ok = !vucSig.empty();
CondLog (!ok, lsWARNING, RippleAddress)
@@ -602,23 +570,11 @@ bool RippleAddress::accountPrivateSign (uint256 const& uHash, Blob& vucSig) cons
Blob RippleAddress::accountPrivateEncrypt (
RippleAddress const& naPublicTo, Blob const& vucPlainText) const
{
openssl::ec_key secretKey = ECDSAPrivateKey (getAccountPrivate());
openssl::ec_key publicKey = ECDSAPublicKey (naPublicTo.getAccountPublic());
uint256 secretKey = getAccountPrivate();
Blob publicKey = naPublicTo.getAccountPublic();
Blob vucCipherText;
if (! publicKey.valid())
{
WriteLog (lsWARNING, RippleAddress)
<< "accountPrivateEncrypt: Bad public key.";
}
if (! secretKey.valid())
{
WriteLog (lsWARNING, RippleAddress)
<< "accountPrivateEncrypt: Bad private key.";
}
{
try
{
@@ -635,23 +591,11 @@ Blob RippleAddress::accountPrivateEncrypt (
Blob RippleAddress::accountPrivateDecrypt (
RippleAddress const& naPublicFrom, Blob const& vucCipherText) const
{
openssl::ec_key secretKey = ECDSAPrivateKey (getAccountPrivate());
openssl::ec_key publicKey = ECDSAPublicKey (naPublicFrom.getAccountPublic());
uint256 secretKey = getAccountPrivate();
Blob publicKey = naPublicFrom.getAccountPublic();
Blob vucPlainText;
if (! publicKey.valid())
{
WriteLog (lsWARNING, RippleAddress)
<< "accountPrivateDecrypt: Bad public key.";
}
if (! secretKey.valid())
{
WriteLog (lsWARNING, RippleAddress)
<< "accountPrivateDecrypt: Bad private key.";
}
{
try
{
@@ -710,7 +654,7 @@ void RippleAddress::setGenerator (Blob const& vPublic)
RippleAddress RippleAddress::createGeneratorPublic (RippleAddress const& naSeed)
{
RippleAddress naNew;
naNew.setGenerator (getPublicKey (GenerateRootDeterministicKey (naSeed.getSeed())));
naNew.setGenerator (GenerateRootDeterministicPublicKey (naSeed.getSeed()));
return naNew;
}

View File

@@ -26,8 +26,10 @@
#include <ripple/crypto/impl/ec_key.cpp>
#include <ripple/crypto/impl/ECDSA.cpp>
#include <ripple/crypto/impl/ECDSACanonical.cpp>
#include <ripple/crypto/impl/ECDSAKey.cpp>
#include <ripple/crypto/impl/ECIES.cpp>
#include <ripple/crypto/impl/GenerateDeterministicKey.cpp>
#include <ripple/crypto/impl/openssl.cpp>
#include <ripple/crypto/impl/RandomNumbers.cpp>
#include <ripple/crypto/impl/RFC1751.cpp>