|
@ -27,13 +27,170 @@ |
|
|
#include <libdevcore/Log.h> |
|
|
#include <libdevcore/Log.h> |
|
|
#include <libethereum/Transaction.h> |
|
|
#include <libethereum/Transaction.h> |
|
|
#include <boost/test/unit_test.hpp> |
|
|
#include <boost/test/unit_test.hpp> |
|
|
|
|
|
#include "TestHelperCrypto.h" |
|
|
|
|
|
|
|
|
using namespace std; |
|
|
using namespace std; |
|
|
using namespace dev; |
|
|
using namespace dev; |
|
|
using namespace dev::eth; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace dev |
|
|
|
|
|
{ |
|
|
|
|
|
namespace crypto |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
inline CryptoPP::AutoSeededRandomPool& PRNG() { |
|
|
|
|
|
static CryptoPP::AutoSeededRandomPool prng; |
|
|
|
|
|
return prng; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
using namespace CryptoPP; |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE(crypto) |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) |
|
|
|
|
|
{ |
|
|
|
|
|
cnote << "Testing cryptopp_ecies_message..."; |
|
|
|
|
|
|
|
|
|
|
|
string const message("Now is the time for all good men to come to the aide of humanity."); |
|
|
|
|
|
|
|
|
|
|
|
AutoSeededRandomPool prng; |
|
|
|
|
|
|
|
|
|
|
|
ECIES<ECP>::Decryptor localDecryptor(prng, ASN1::secp256r1()); |
|
|
|
|
|
SavePrivateKey(localDecryptor.GetPrivateKey()); |
|
|
|
|
|
|
|
|
|
|
|
ECIES<ECP>::Encryptor localEncryptor(localDecryptor); |
|
|
|
|
|
SavePublicKey(localEncryptor.GetPublicKey()); |
|
|
|
|
|
|
|
|
|
|
|
ECIES<ECP>::Decryptor futureDecryptor; |
|
|
|
|
|
LoadPrivateKey(futureDecryptor.AccessPrivateKey()); |
|
|
|
|
|
futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3); |
|
|
|
|
|
|
|
|
|
|
|
ECIES<ECP>::Encryptor futureEncryptor; |
|
|
|
|
|
LoadPublicKey(futureEncryptor.AccessPublicKey()); |
|
|
|
|
|
futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3); |
|
|
|
|
|
|
|
|
|
|
|
// encrypt/decrypt with local
|
|
|
|
|
|
string cipherLocal; |
|
|
|
|
|
StringSource ss1 (message, true, new PK_EncryptorFilter(prng, localEncryptor, new StringSink(cipherLocal) ) ); |
|
|
|
|
|
string plainLocal; |
|
|
|
|
|
StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocal) ) ); |
|
|
|
|
|
|
|
|
|
|
|
// encrypt/decrypt with future
|
|
|
|
|
|
string cipherFuture; |
|
|
|
|
|
StringSource ss3 (message, true, new PK_EncryptorFilter(prng, futureEncryptor, new StringSink(cipherFuture) ) ); |
|
|
|
|
|
string plainFuture; |
|
|
|
|
|
StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFuture) ) ); |
|
|
|
|
|
|
|
|
|
|
|
// decrypt local w/future
|
|
|
|
|
|
string plainFutureFromLocal; |
|
|
|
|
|
StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); |
|
|
|
|
|
|
|
|
|
|
|
// decrypt future w/local
|
|
|
|
|
|
string plainLocalFromFuture; |
|
|
|
|
|
StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocalFromFuture) ) ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(plainLocal == message); |
|
|
|
|
|
assert(plainFuture == plainLocal); |
|
|
|
|
|
assert(plainFutureFromLocal == plainLocal); |
|
|
|
|
|
assert(plainLocalFromFuture == plainLocal); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(crypto_tests) |
|
|
BOOST_AUTO_TEST_CASE(cryptopp_ecdh_prime) |
|
|
|
|
|
{ |
|
|
|
|
|
cnote << "Testing cryptopp_ecdh_prime..."; |
|
|
|
|
|
|
|
|
|
|
|
using namespace CryptoPP; |
|
|
|
|
|
OID curve = ASN1::secp256r1(); |
|
|
|
|
|
|
|
|
|
|
|
ECDH<ECP>::Domain dhLocal(curve); |
|
|
|
|
|
SecByteBlock privLocal(dhLocal.PrivateKeyLength()); |
|
|
|
|
|
SecByteBlock pubLocal(dhLocal.PublicKeyLength()); |
|
|
|
|
|
dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal); |
|
|
|
|
|
|
|
|
|
|
|
ECDH<ECP>::Domain dhRemote(curve); |
|
|
|
|
|
SecByteBlock privRemote(dhRemote.PrivateKeyLength()); |
|
|
|
|
|
SecByteBlock pubRemote(dhRemote.PublicKeyLength()); |
|
|
|
|
|
dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote); |
|
|
|
|
|
|
|
|
|
|
|
assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); |
|
|
|
|
|
|
|
|
|
|
|
// local: send public to remote; remote: send public to local
|
|
|
|
|
|
|
|
|
|
|
|
// Local
|
|
|
|
|
|
SecByteBlock sharedLocal(dhLocal.AgreedValueLength()); |
|
|
|
|
|
assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote)); |
|
|
|
|
|
|
|
|
|
|
|
// Remote
|
|
|
|
|
|
SecByteBlock sharedRemote(dhRemote.AgreedValueLength()); |
|
|
|
|
|
assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal)); |
|
|
|
|
|
|
|
|
|
|
|
// Test
|
|
|
|
|
|
Integer ssLocal, ssRemote; |
|
|
|
|
|
ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes()); |
|
|
|
|
|
ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes()); |
|
|
|
|
|
|
|
|
|
|
|
assert(ssLocal != 0); |
|
|
|
|
|
assert(ssLocal == ssRemote); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth) |
|
|
|
|
|
{ |
|
|
|
|
|
// ECDH gives 256-bit shared while aes uses 128-bits
|
|
|
|
|
|
// Use first 128-bits of shared secret as symmetric key
|
|
|
|
|
|
// IV is 0
|
|
|
|
|
|
// New connections require new ECDH keypairs
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(cryptopp_eth_fbba) |
|
|
|
|
|
{ |
|
|
|
|
|
// Initial Authentication:
|
|
|
|
|
|
//
|
|
|
|
|
|
// New/Known Peer:
|
|
|
|
|
|
// pubkeyL = knownR? ? myKnown : myECDH
|
|
|
|
|
|
// pubkeyR = knownR? ? theirKnown : theirECDH
|
|
|
|
|
|
//
|
|
|
|
|
|
// Initial message = hmac(k=sha3(shared-secret[128..255]), address(pubkeyL)) || ECIES encrypt(pubkeyR, pubkeyL)
|
|
|
|
|
|
//
|
|
|
|
|
|
// Key Exchange (this could occur after handshake messages):
|
|
|
|
|
|
// If peers do not know each other they will need to exchange public keys.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Drop ECDH (this could occur after handshake messages):
|
|
|
|
|
|
// After authentication and/or key exchange, both sides generate shared key
|
|
|
|
|
|
// from their 'known' keys and use this to encrypt all future messages.
|
|
|
|
|
|
//
|
|
|
|
|
|
// v2: If one side doesn't trust the other then a single-use key maybe sent.
|
|
|
|
|
|
// This will need to be tracked for future connections; when non-trusting peer
|
|
|
|
|
|
// wants to trust the other, it can request that it's old, 'new', public key be
|
|
|
|
|
|
// accepted. And, if the peer *really* doesn't trust the other side, it can request
|
|
|
|
|
|
// that a new, 'new', public key be accepted.
|
|
|
|
|
|
//
|
|
|
|
|
|
// Handshake (all or nothing, padded):
|
|
|
|
|
|
// All Peers (except blacklisted):
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// New Peer:
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// Known Untrusted Peer:
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// Known Trusted Peer:
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// Blacklisted Peeer:
|
|
|
|
|
|
// Already dropped by now.
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
|
|
|
// MAC:
|
|
|
|
|
|
// ...
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(eth_keypairs) |
|
|
{ |
|
|
{ |
|
|
cnote << "Testing Crypto..."; |
|
|
cnote << "Testing Crypto..."; |
|
|
secp256k1_start(); |
|
|
secp256k1_start(); |
|
@ -42,7 +199,7 @@ BOOST_AUTO_TEST_CASE(crypto_tests) |
|
|
BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); |
|
|
BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); |
|
|
BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); |
|
|
BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); |
|
|
{ |
|
|
{ |
|
|
Transaction t; |
|
|
eth::Transaction t; |
|
|
t.nonce = 0; |
|
|
t.nonce = 0; |
|
|
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); |
|
|
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); |
|
|
t.value = 1000; |
|
|
t.value = 1000; |
|
@ -70,7 +227,7 @@ int cryptoTest() |
|
|
assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); |
|
|
assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); |
|
|
assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); |
|
|
assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); |
|
|
{ |
|
|
{ |
|
|
Transaction t; |
|
|
eth::Transaction t; |
|
|
t.nonce = 0; |
|
|
t.nonce = 0; |
|
|
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); |
|
|
t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); |
|
|
t.value = 1000; |
|
|
t.value = 1000; |
|
@ -156,3 +313,5 @@ int cryptoTest() |
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() |
|
|
|
|
|
|
|
|