From 538aae8078fb8bd2cd3c0be5d7dbf64081adec3d Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 25 Oct 2014 18:23:19 +0200 Subject: [PATCH 01/16] Cleaner everything. CryptoPP doesn't recover public keys. secp256k1lib base doesn't verify compact signatures. CryptoPP sign and verify. Stub for secp256k1lib verification from compact signature. --- libdevcrypto/Common.cpp | 25 ++++++++-- libdevcrypto/Common.h | 7 ++- libdevcrypto/CryptoPP.cpp | 83 ++++++++++++++++++++++--------- libdevcrypto/CryptoPP.h | 34 +++++++------ libdevcrypto/EC.cpp | 42 +++++++++++++--- libdevcrypto/EC.h | 9 ++++ libdevcrypto/SHA3MAC.cpp | 5 +- test/crypto.cpp | 101 ++++++++++++++++---------------------- 8 files changed, 192 insertions(+), 114 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 6d57bf2b2..f4caa5027 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -152,17 +152,18 @@ inline h256 kFromMessage(h256 _msg, h256 _priv) return _msg ^ _priv; } -Signature dev::sign(Secret _k, h256 _message) +Signature dev::sign(Secret _k, h256 _hash) { int v = 0; secp256k1_start(); SignatureStruct ret; - h256 nonce = kFromMessage(_message, _k); + h256 nonce = kFromMessage(_hash, _k); - if (!secp256k1_ecdsa_sign_compact(_message.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) + if (!secp256k1_ecdsa_sign_compact(_hash.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) return Signature(); + #if ETH_ADDRESS_DEBUG cout << "---- SIGN -------------------------------" << endl; cout << "MSG: " << _message << endl; @@ -174,3 +175,21 @@ Signature dev::sign(Secret _k, h256 _message) ret.v = v; return *(Signature const*)&ret; } + +bool dev::verify(Public _p, Signature _s, h256 _hash) +{ + secp256k1_start(); + + // sig_t +// secp256k1_ecdsa_sig_t s; + int sz = sizeof(_s)-1; +// secp256k1_ecdsa_sig_serialize(_s.data()+1, &sz, &s); + + // pubk_t + byte pubkey[65] = {0x04}; + memcpy(&pubkey[1], _p.data(), 64); + +// int result = secp256k1_ecdsa_verify(_hash.data(), sizeof(_hash), &s, sizeof(s), pubkey, 65); + return 0; +} + diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7f2a8192e..bd9a4fbd4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -59,7 +59,7 @@ Address toAddress(Secret _secret); /// Encrypts plain text using Public key. void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); - + /// Decrypts cipher using Secret key. bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); @@ -67,7 +67,10 @@ bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); Public recover(Signature _sig, h256 _message); /// Returns siganture of message hash. -Signature sign(Secret _k, h256 _message); +Signature sign(Secret _k, h256 _hash); + +/// Verify signature. +bool verify(Public _k, Signature _s, h256 _hash); /// Simple class that represents a "key pair". /// All of the data of the class can be regenerated from the secret key (m_secret) alone. diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index cabcfd45a..fa45e6242 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,12 +25,62 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -ECP::Point pp::PointFromPublic(Public const& _p) +/// Conversion from bytes to cryptopp point +inline ECP::Point publicToPoint(Public const& _p); + +/// Conversion from bytes to cryptopp exponent +inline Integer secretToExponent(Secret const& _s); + +/// Conversion from cryptopp exponent Integer to bytes +inline void exponentToPublic(Integer const& _e, Public& _p); + +void pp::initializeSigner(Secret const& _s, ECDSA::Signer& _signer) +{ + _signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _signer.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +void pp::initializeVerifier(Public const& _p, ECDSA::Verifier& _verifier) +{ + _verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _verifier.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& _encryptor) +{ + _encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _encryptor.AccessKey().SetPublicElement(publicToPoint(_p)); +} + +void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& _decryptor) +{ + _decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); + _decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s)); +} + +void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) +{ + bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); + _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + + static_assert(Public::size == 64, "Public key must be 64 bytes."); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); + memcpy(_p.data(), &prefixedKey[1], Public::size); +} + +void pp::exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +{ + _k.GetPrivateExponent().Encode(_s.data(), Secret::size); +} + +/// Integer and Point Conversion: + +inline ECP::Point publicToPoint(Public const& _p) { ECP::Point p; CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1()); - + pub.AccessGroupParameters().Initialize(pp::secp256k1Curve); + bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); prefixedKey[0] = 0x04; assert(Public::size == prefixedKey.size() - 1); @@ -40,35 +90,20 @@ ECP::Point pp::PointFromPublic(Public const& _p) return std::move(p); } -Integer pp::ExponentFromSecret(Secret const& _s) +inline Integer secretToExponent(Secret const& _s) { static_assert(Secret::size == 32, "Secret key must be 32 bytes."); return std::move(Integer(_s.data(), Secret::size)); } -void pp::PublicFromExponent(Integer const& _e, Public& _p) +inline void exponentToPublic(Integer const& _e, Public& _p) { CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(secp256k1()); + k.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.SetPrivateExponent(_e); - + CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(secp256k1()); + p.AccessGroupParameters().Initialize(pp::secp256k1Curve); k.MakePublicKey(p); - pp::PublicFromDL_PublicKey_EC(p, _p); -} - -void pp::PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) -{ - bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); - _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); - - static_assert(Public::size == 64, "Public key must be 64 bytes."); - assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); - memcpy(_p.data(), &prefixedKey[1], Public::size); -} - -void pp::SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) -{ - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); + pp::exportPublicKey(p, _p); } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index d7e4181ee..87334b847 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,8 +23,6 @@ #pragma once -// need to leave this one disabled -//#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push @@ -58,27 +56,31 @@ namespace crypto namespace pp { -/// RNG used by CryptoPP -inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } -/// EC curve used by CryptoPP -inline CryptoPP::OID const& secp256k1() { static CryptoPP::OID curve = CryptoPP::ASN1::secp256k1(); return curve; } - -/// Conversion from bytes to cryptopp point -CryptoPP::ECP::Point PointFromPublic(Public const& _p); +/// CryptoPP random number pool +static CryptoPP::AutoSeededRandomPool PRNG; + +/// CryptoPP EC Cruve +static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); -/// Conversion from bytes to cryptopp exponent -CryptoPP::Integer ExponentFromSecret(Secret const& _s); +/// Initialize signer +void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); + +/// Initialize verifier +void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); -/// Conversion from cryptopp exponent Integer to bytes -void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); +/// Conversion from Public key to cryptopp encryptor +void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); +/// Conversion from Secret key to cryptopp decryptor +void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); + /// Conversion from cryptopp public key to bytes -void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& out_p); /// Conversion from cryptopp private key to bytes -void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); - +void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& out_s); + } } } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b38703ac3..d3c9d9c9f 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -42,32 +42,58 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +void crypto::encrypt(Public const& _key, bytes& io_cipher) { ECIES::Encryptor e; - e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + pp::initializeEncryptor(_key, e); size_t plen = io_cipher.size(); bytes c; c.resize(e.CiphertextLength(plen)); // todo: use StringSource with _plain as input and output. - e.Encrypt(pp::PRNG(), io_cipher.data(), plen, c.data()); + e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); bzero(io_cipher.data(), io_cipher.size()); io_cipher = std::move(c); } -void dev::crypto::decrypt(Secret const& _k, bytes& io_text) +void crypto::decrypt(Secret const& _k, bytes& io_text) { CryptoPP::ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(pp::ExponentFromSecret(_k)); + pp::initializeDecryptor(_k, d); size_t clen = io_text.size(); bytes p; p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with _c as input and output. - DecodingResult r = d.Decrypt(pp::PRNG(), io_text.data(), clen, p.data()); + DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); assert(r.messageLength); io_text.resize(r.messageLength); io_text = std::move(p); } +Signature crypto::sign(Secret const& _k, bytesConstRef _message) +{ + ECDSA::Signer signer; + pp::initializeSigner(_k, signer); + + string sigstr; + StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + + /// eth signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. + return std::move(retsig); +} + +//Public crypto::recover(Signature _sig, bytesConstRef _message) +//{ +// +//} + +bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) +{ + ECDSA::Verifier verifier; + pp::initializeVerifier(_p, verifier); + // cryptopp signatures are 64 bytes + static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); + return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); +} + + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index cf6714faf..c7ce01ed0 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -35,7 +35,16 @@ void encrypt(Public const& _k, bytes& io_cipher); /// Decrypts text (in place). void decrypt(Secret const& _k, bytes& io_text); + +/// Returns siganture of message hash. +Signature sign(Secret const& _k, bytesConstRef _message); +/// Recovers Public key from signed message. +//Public recover(Signature _sig, bytesConstRef _message); + +/// Verify signature +bool verify(Public _p, Signature _sig, bytesConstRef _message); + } } diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 5c74edd7e..1fa370ca1 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -28,10 +28,11 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { CryptoPP::SHA3_256 ctx; - ctx.Update((byte*)_secret.data(), _secret.size()); + if (_secret.size() > 0) + ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); diff --git a/test/crypto.cpp b/test/crypto.cpp index 0d3b6202f..187ca6c79 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "TestHelperCrypto.h" using namespace std; @@ -57,96 +58,81 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); Secret previous = s; for (auto i = 0; i < 30; i++) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); assert(s != previous); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); } } -BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_sipaseckp256k1) +BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { KeyPair k = KeyPair::create(); Secret s = k.sec(); - - // Convert secret to exponent used by pp - Integer e = pp::ExponentFromSecret(s); - // Test that exported DL_EC private is same as exponent from Secret - CryptoPP::DL_PrivateKey_EC privatek; - privatek.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.SetPrivateExponent(e); - assert(e == privatek.GetPrivateExponent()); + string emptystr(""), msgstr("test"); + bytesConstRef empty(emptystr), msg(msgstr); - // Test that exported secret is same as decryptor(privatek) secret - ECIES::Decryptor d; - d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); - d.AccessKey().SetPrivateExponent(e); - assert(d.AccessKey().GetPrivateExponent() == e); + // sha3 output of strings are the same + h256 hashpp; + sha3mac(empty, msg, hashpp.ref()); + assert(sha3(msg) == hashpp); + + // cryptopp sign and verify + Signature sigpp = crypto::sign(s, msg); + cout << std::hex << sigpp << endl; + + ECDSA::Verifier verifier; + pp::initializeVerifier(k.pub(), verifier); + assert(verifier.VerifyMessage(msg.data(), msgstr.size(), sigpp.data(), sizeof(Signature))); + + // seckp256k1lib sign and verify + h256 hashed(sha3(h256().asBytes())); + Signature sig = dev::sign(s, hashed); + Public recoveredp = dev::recover(sig, hashed); + bool result = dev::verify(k.pub(), sig, hashed); +// assert(result); + - // Test that decryptor->encryptor->public == private->makepublic->public - CryptoPP::DL_PublicKey_EC pubk; - pubk.AccessGroupParameters().Initialize(pp::secp256k1()); - privatek.MakePublicKey(pubk); - ECIES::Encryptor enc(d); - assert(pubk.GetPublicElement() == enc.AccessKey().GetPublicElement()); - // Test against sipa/seckp256k1 - Public p; - pp::PublicFromExponent(pp::ExponentFromSecret(s), p); - assert(toAddress(s) == dev::right160(dev::sha3(p.ref()))); - assert(k.pub() == p); } BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) { - ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); Secret s; - pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + pp::exportPrivateKey(d.GetKey(), s); Public p; - pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + pp::exportPublicKey(e.GetKey(), p); Address addr = right160(dev::sha3(p.ref())); assert(toAddress(s) == addr); KeyPair l(s); assert(l.address() == addr); - - DL_PublicKey_EC pub; - pub.Initialize(pp::secp256k1(), pp::PointFromPublic(p)); - assert(pub.GetPublicElement() == e.GetKey().GetPublicElement()); - - KeyPair k = KeyPair::create(); - Public p2; - pp::PublicFromExponent(pp::ExponentFromSecret(k.sec()), p2); - assert(k.pub() == p2); - - Address a = k.address(); - Address a2 = toAddress(k.sec()); - assert(a2 == a); } BOOST_AUTO_TEST_CASE(ecies_eckeypair) @@ -172,9 +158,6 @@ BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) // All connections should share seed for PRF (or PRNG) for nonces - - - } BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) @@ -183,7 +166,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) string const message("Now is the time for all good persons to come to the aide of humanity."); - ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); + ECIES::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -191,31 +174,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG, 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); + StringSource ss1 (message, true, new PK_EncryptorFilter(pp::PRNG, localEncryptor, new StringSink(cipherLocal) ) ); string plainLocal; - StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); + StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocal) ) ); // encrypt/decrypt with future string cipherFuture; - StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); + StringSource ss3 (message, true, new PK_EncryptorFilter(pp::PRNG, futureEncryptor, new StringSink(cipherFuture) ) ); string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); + StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) ); // decrypt local w/future string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); // decrypt future w/local string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message); From 6e889cd88757c7b80b4a5a46db6c4302f7bfac95 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 04:17:03 +0100 Subject: [PATCH 02/16] ecdsa tests --- libdevcrypto/Common.cpp | 17 ++----- libdevcrypto/EC.cpp | 8 +-- libdevcrypto/EC.h | 3 -- test/crypto.cpp | 109 ++++++++++++++++++++++++++++------------ 4 files changed, 81 insertions(+), 56 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index fd9d6a563..584f4cfe7 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -78,6 +78,7 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { + secp256k1_start(); int ok = secp256k1_ecdsa_seckey_verify(m_secret.data()); if (!ok) return; @@ -180,18 +181,8 @@ Signature dev::sign(Secret _k, h256 _hash) bool dev::verify(Public _p, Signature _s, h256 _hash) { - secp256k1_start(); - - // sig_t -// secp256k1_ecdsa_sig_t s; - int sz = sizeof(_s)-1; -// secp256k1_ecdsa_sig_serialize(_s.data()+1, &sz, &s); - - // pubk_t - byte pubkey[65] = {0x04}; - memcpy(&pubkey[1], _p.data(), 64); - -// int result = secp256k1_ecdsa_verify(_hash.data(), sizeof(_hash), &s, sizeof(s), pubkey, 65); - return 0; + // Placeholder. The signature should be verified if recovering public key isn't proof. + Public v = dev::recover(_s, _hash); + return (v == _p); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 5d05b2aec..b8321102b 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -81,20 +81,14 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) string sigstr; StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); - - /// eth signature: 65 bytes: r: [0, 32), s: [32, 64), v: 64. return std::move(retsig); } -//Public crypto::recover(Signature _sig, bytesConstRef _message) -//{ -// -//} - bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) { ECDSA::Verifier verifier; pp::initializeVerifier(_p, verifier); + // cryptopp signatures are 64 bytes static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index c7ce01ed0..8b66a7bfe 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -38,9 +38,6 @@ void decrypt(Secret const& _k, bytes& io_text); /// Returns siganture of message hash. Signature sign(Secret const& _k, bytesConstRef _message); - -/// Recovers Public key from signed message. -//Public recover(Signature _sig, bytesConstRef _message); /// Verify signature bool verify(Public _p, Signature _sig, bytesConstRef _message); diff --git a/test/crypto.cpp b/test/crypto.cpp index 187ca6c79..ebb844688 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -47,13 +47,13 @@ BOOST_AUTO_TEST_CASE(common_encrypt_decrypt) KeyPair k = KeyPair::create(); bytes cipher; encrypt(k.pub(), bcr, cipher); - assert(cipher != asBytes(message) && cipher.size() > 0); + BOOST_REQUIRE(cipher != asBytes(message) && cipher.size() > 0); bytes plain; decrypt(k.sec(), bytesConstRef(&cipher), plain); - assert(asString(plain) == message); - assert(plain == asBytes(message)); + BOOST_REQUIRE(asString(plain) == message); + BOOST_REQUIRE(plain == asBytes(message)); } BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) @@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Public p; pp::exportPublicKey(e.GetKey(), p); - assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); Secret previous = s; for (auto i = 0; i < 30; i++) @@ -77,45 +77,88 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Secret s; pp::exportPrivateKey(d.GetKey(), s); - assert(s != previous); + BOOST_REQUIRE(s != previous); Public p; pp::exportPublicKey(e.GetKey(), p); - assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); } } BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { - KeyPair k = KeyPair::create(); - Secret s = k.sec(); - - string emptystr(""), msgstr("test"); - bytesConstRef empty(emptystr), msg(msgstr); - - // sha3 output of strings are the same - h256 hashpp; - sha3mac(empty, msg, hashpp.ref()); - assert(sha3(msg) == hashpp); - - // cryptopp sign and verify - Signature sigpp = crypto::sign(s, msg); - cout << std::hex << sigpp << endl; - + // cryptopp integer encoding + Integer nHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); + Integer nB(fromHex("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2").data(), 32); + BOOST_REQUIRE(nHex == nB); + + bytes sbytes(fromHex("0x01")); + Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 + KeyPair key(secret); + + bytes m(fromHex("0x02")); + h256 hm(sha3(m)); // f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2 + Integer hInt("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); // 32b msg hash + h256 k(hm ^ key.sec()); + Integer kInt(k.asBytes().data(), 32); + + // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) + ECDSA::Signer signer; + pp::initializeSigner(key.sec(), signer); + Integer r, s; + signer.RawSign(kInt, hInt, r, s); + cout << "cryptopp-raw r, s: " << endl << r << endl << s << endl; + + // verify cryptopp raw-signature w/cryptopp ECDSA::Verifier verifier; - pp::initializeVerifier(k.pub(), verifier); - assert(verifier.VerifyMessage(msg.data(), msgstr.size(), sigpp.data(), sizeof(Signature))); - - // seckp256k1lib sign and verify - h256 hashed(sha3(h256().asBytes())); - Signature sig = dev::sign(s, hashed); - Public recoveredp = dev::recover(sig, hashed); - bool result = dev::verify(k.pub(), sig, hashed); -// assert(result); - - - + pp::initializeVerifier(key.pub(), verifier); + Signature sigppraw; + r.Encode(sigppraw.data(), 32); + s.Encode(sigppraw.data()+32, 32); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); + BOOST_REQUIRE(dev::recover(sigppraw, hm) == key.pub()); + + // sign with sec256lib, verify with cryptopp + Signature seclibsig(dev::sign(key.sec(), hm)); + r.Decode(seclibsig.data(), 32); + s.Decode(seclibsig.data()+32, 32); + cout << "sec256lib r, s: " << endl << r << endl << s << endl; + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); + BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); + + // sign with cryptopp (w/hash filter?), verify with cryptopp + bytes sigppb(signer.MaxSignatureLength()); + size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); + r.Decode(sigppb.data(), 32); + s.Decode(sigppb.data()+32, 32); + cout << "cryptopp-signmsg r, s: " << endl << r << endl << s << endl; + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); + + // this has a 25% of failing + Signature sigpp; + r.Encode(sigpp.data(), 32); + s.Encode(sigpp.data()+32, 32); + BOOST_WARN(dev::recover(sigpp, hm) == key.pub()); + + // sign with stringsource + string sigstr; + StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); + + + // need to serialize signature for secp256k1lib to verify compact sig, then + // test if secp256k1lib can verify cryptopp sigs + + +// byte dersig[70]; +// DSAConvertSignatureFormat(dersig, 70, DSA_DER, sig.data(), 64, DSA_P1363); +// +// byte encpub[65] = {0x04}; +// memcpy(&encpub[1], key.pub().data(), 64); +// int r = secp256k1_ecdsa_verify(msg.data(), msg.size(), dersig, 70, encpub, 65); +// assert(r); } From 5517fa2f4222d097ab2f0f0758c42cab84febffd Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 05:15:44 +0100 Subject: [PATCH 03/16] support for verifying ec signatures w/secp256k1 or cryptopp. --- libdevcrypto/Common.cpp | 4 +- libdevcrypto/CryptoPP.h | 1 + libdevcrypto/EC.cpp | 14 +++- libdevcrypto/EC.h | 2 +- test/crypto.cpp | 178 +++++++++++++++++++++------------------- 5 files changed, 109 insertions(+), 90 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 584f4cfe7..c7503a820 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -181,8 +181,6 @@ Signature dev::sign(Secret _k, h256 _hash) bool dev::verify(Public _p, Signature _s, h256 _hash) { - // Placeholder. The signature should be verified if recovering public key isn't proof. - Public v = dev::recover(_s, _hash); - return (v == _p); + return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 87334b847..3064f0dc4 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -45,6 +45,7 @@ #include #include #include +#include #pragma warning(pop) #pragma GCC diagnostic pop #include "Common.h" diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index b8321102b..77096b691 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -84,11 +84,21 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) return std::move(retsig); } -bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message) +bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) { + if (_raw) + { + assert(_message.size() == 32); + byte encpub[65] = {0x04}; + memcpy(&encpub[1], _p.data(), 64); + byte dersig[72]; + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, _sig.data(), 64, DSA_P1363); + assert(cssz <= 72); + return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65)); + } + ECDSA::Verifier verifier; pp::initializeVerifier(_p, verifier); - // cryptopp signatures are 64 bytes static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index 8b66a7bfe..d98472a54 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -40,7 +40,7 @@ void decrypt(Secret const& _k, bytes& io_text); Signature sign(Secret const& _k, bytesConstRef _message); /// Verify signature -bool verify(Public _p, Signature _sig, bytesConstRef _message); +bool verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw = false); } } diff --git a/test/crypto.cpp b/test/crypto.cpp index ebb844688..c1f678fcb 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -97,69 +97,79 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) Secret secret(sha3(sbytes)); // 5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2 KeyPair key(secret); - bytes m(fromHex("0x02")); - h256 hm(sha3(m)); // f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2 - Integer hInt("f2ee15ea639b73fa3db9b34a245bdfa015c260c598b211bf05a1ecc4b3e3b4f2H"); // 32b msg hash - h256 k(hm ^ key.sec()); - Integer kInt(k.asBytes().data(), 32); - - // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) - ECDSA::Signer signer; - pp::initializeSigner(key.sec(), signer); - Integer r, s; - signer.RawSign(kInt, hInt, r, s); - cout << "cryptopp-raw r, s: " << endl << r << endl << s << endl; - - // verify cryptopp raw-signature w/cryptopp - ECDSA::Verifier verifier; - pp::initializeVerifier(key.pub(), verifier); - Signature sigppraw; - r.Encode(sigppraw.data(), 32); - s.Encode(sigppraw.data()+32, 32); - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); - BOOST_REQUIRE(dev::recover(sigppraw, hm) == key.pub()); - - // sign with sec256lib, verify with cryptopp - Signature seclibsig(dev::sign(key.sec(), hm)); - r.Decode(seclibsig.data(), 32); - s.Decode(seclibsig.data()+32, 32); - cout << "sec256lib r, s: " << endl << r << endl << s << endl; - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); - BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); - - // sign with cryptopp (w/hash filter?), verify with cryptopp - bytes sigppb(signer.MaxSignatureLength()); - size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); - r.Decode(sigppb.data(), 32); - s.Decode(sigppb.data()+32, 32); - cout << "cryptopp-signmsg r, s: " << endl << r << endl << s << endl; - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); - - // this has a 25% of failing - Signature sigpp; - r.Encode(sigpp.data(), 32); - s.Encode(sigpp.data()+32, 32); - BOOST_WARN(dev::recover(sigpp, hm) == key.pub()); - - // sign with stringsource - string sigstr; - StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); - FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); - BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); - - - // need to serialize signature for secp256k1lib to verify compact sig, then - // test if secp256k1lib can verify cryptopp sigs - - -// byte dersig[70]; -// DSAConvertSignatureFormat(dersig, 70, DSA_DER, sig.data(), 64, DSA_P1363); -// -// byte encpub[65] = {0x04}; -// memcpy(&encpub[1], key.pub().data(), 64); -// int r = secp256k1_ecdsa_verify(msg.data(), msg.size(), dersig, 70, encpub, 65); -// assert(r); - + bytes m(fromHex("0x01")); + int tests = 5; + while (m[0]++ && tests--) + { + h256 hm(sha3(m)); + Integer hInt(hm.asBytes().data(), 32); + h256 k(hm ^ key.sec()); + Integer kInt(k.asBytes().data(), 32); + + // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) + ECDSA::Signer signer; + pp::initializeSigner(key.sec(), signer); + Integer r, s; + signer.RawSign(kInt, hInt, r, s); + + // verify cryptopp raw-signature w/cryptopp + ECDSA::Verifier verifier; + pp::initializeVerifier(key.pub(), verifier); + Signature sigppraw; + r.Encode(sigppraw.data(), 32); + s.Encode(sigppraw.data()+32, 32); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); + BOOST_CHECK(dev::recover(sigppraw, hm) == key.pub()); + + // sign with sec256lib, verify with cryptopp + Signature seclibsig(dev::sign(key.sec(), hm)); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); + BOOST_CHECK(dev::recover(seclibsig, hm) == key.pub()); + + // sign with cryptopp (w/hash filter?), verify with cryptopp + bytes sigppb(signer.MaxSignatureLength()); + size_t ssz = signer.SignMessage(pp::PRNG, m.data(), m.size(), sigppb.data()); + Signature sigpp; + memcpy(sigpp.data(), sigppb.data(), 64); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); + BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); + BOOST_CHECK(dev::recover(sigpp, hm) == key.pub()); + + // sign with cryptopp and stringsource hash filter + string sigstr; + StringSource ssrc(asString(m), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); + FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); + BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); + BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m))); + BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); + BOOST_CHECK(dev::recover(retsig, hm) == key.pub()); + + /// verification w/sec256lib + // requires public key and sig in standard format + byte encpub[65] = {0x04}; + memcpy(&encpub[1], key.pub().data(), 64); + byte dersig[72]; + + // verify sec256lib sig w/sec256lib + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, seclibsig.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + + // verify cryptopp-raw sig w/sec256lib + cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppraw.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + + // verify cryptopp sig w/sec256lib + cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sigppb.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(hm.data(), sizeof(hm), dersig, cssz, encpub, 65)); + } } BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) @@ -172,10 +182,10 @@ BOOST_AUTO_TEST_CASE(cryptopp_public_export_import) Public p; pp::exportPublicKey(e.GetKey(), p); Address addr = right160(dev::sha3(p.ref())); - assert(toAddress(s) == addr); + BOOST_REQUIRE(toAddress(s) == addr); KeyPair l(s); - assert(l.address() == addr); + BOOST_REQUIRE(l.address() == addr); } BOOST_AUTO_TEST_CASE(ecies_eckeypair) @@ -187,10 +197,10 @@ BOOST_AUTO_TEST_CASE(ecies_eckeypair) bytes b = asBytes(message); encrypt(k.pub(), b); - assert(b != asBytes(original)); + BOOST_REQUIRE(b != asBytes(original)); decrypt(k.sec(), b); - assert(b == asBytes(original)); + BOOST_REQUIRE(b == asBytes(original)); } BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) @@ -244,16 +254,16 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); - assert(plainLocal == message); - assert(plainFuture == plainLocal); - assert(plainFutureFromLocal == plainLocal); - assert(plainLocalFromFuture == plainLocal); + BOOST_REQUIRE(plainLocal == message); + BOOST_REQUIRE(plainFuture == plainLocal); + BOOST_REQUIRE(plainFutureFromLocal == plainLocal); + BOOST_REQUIRE(plainLocalFromFuture == plainLocal); } BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) { const int aesKeyLen = 16; - assert(sizeof(char) == sizeof(byte)); + BOOST_REQUIRE(sizeof(char) == sizeof(byte)); // generate test key AutoSeededRandomPool rng; @@ -276,7 +286,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) CTR_Mode::Encryption e; e.SetKeyWithIV(key, key.size(), ctr); e.ProcessData(out, in, text.size()); - assert(text != original); + BOOST_REQUIRE(text != original); cipherCopy = text; } catch(CryptoPP::Exception& e) @@ -289,7 +299,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) CTR_Mode< AES >::Decryption d; d.SetKeyWithIV(key, key.size(), ctr); d.ProcessData(out, in, text.size()); - assert(text == original); + BOOST_REQUIRE(text == original); } catch(CryptoPP::Exception& e) { @@ -300,7 +310,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) // reencrypt ciphertext... try { - assert(cipherCopy != text); + BOOST_REQUIRE(cipherCopy != text); in = (unsigned char*)&cipherCopy[0]; out = (unsigned char*)&cipherCopy[0]; @@ -309,7 +319,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) e.ProcessData(out, in, text.size()); // yep, ctr mode. - assert(cipherCopy == original); + BOOST_REQUIRE(cipherCopy == original); } catch(CryptoPP::Exception& e) { @@ -321,7 +331,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) { const int aesKeyLen = 16; - assert(sizeof(char) == sizeof(byte)); + BOOST_REQUIRE(sizeof(char) == sizeof(byte)); AutoSeededRandomPool rng; SecByteBlock key(0x00, aesKeyLen); @@ -336,11 +346,11 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv); cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); - assert(string128 != plainOriginal); + BOOST_REQUIRE(string128 != plainOriginal); CBC_Mode::Decryption cbcDecryption(key, key.size(), iv); cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); - assert(plainOriginal == string128); + BOOST_REQUIRE(plainOriginal == string128); // plaintext whose size isn't divisible by block size must use stream filter for padding @@ -350,10 +360,10 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) string cipher; StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher)); StringSource source(string192, true, aesStream); - assert(cipher.size() == 32); + BOOST_REQUIRE(cipher.size() == 32); cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); - assert(string192 == plainOriginal); + BOOST_REQUIRE(string192 == plainOriginal); } BOOST_AUTO_TEST_CASE(eth_keypairs) @@ -390,8 +400,8 @@ int cryptoTest() secp256k1_start(); KeyPair p(Secret(fromHex("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4"))); - assert(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); - assert(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); + BOOST_REQUIRE(p.pub() == Public(fromHex("97466f2b32bc3bb76d4741ae51cd1d8578b48d3f1e68da206d47321aec267ce78549b514e4453d74ef11b0cd5e4e4c364effddac8b51bcfc8de80682f952896f"))); + BOOST_REQUIRE(p.address() == Address(fromHex("8a40bfaa73256b60764c1bf40675a99083efb075"))); { eth::Transaction t; t.nonce = 0; @@ -406,7 +416,7 @@ int cryptoTest() cnote << RLP(rlp); cnote << toHex(rlp); cnote << t.sha3(true); - assert(t.sender() == p.address()); + BOOST_REQUIRE(t.sender() == p.address()); } From 464fe70e454b8a00de8f434033aa99b6492ca419 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 05:21:02 +0100 Subject: [PATCH 04/16] doc text --- libdevcrypto/CryptoPP.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 3064f0dc4..fdeb67707 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -64,16 +64,16 @@ static CryptoPP::AutoSeededRandomPool PRNG; /// CryptoPP EC Cruve static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); -/// Initialize signer +/// Initialize signer with Secret void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); -/// Initialize verifier +/// Initialize verifier with Public void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); -/// Conversion from Public key to cryptopp encryptor +/// Initialize cryptopp encryptor with Public void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); -/// Conversion from Secret key to cryptopp decryptor +/// Initialize cryptopp decryptor with Secret void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); /// Conversion from cryptopp public key to bytes From 6b6ebcdcdac1b67fea8c41f5fc5ac3d2bf892544 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 17:21:01 +0100 Subject: [PATCH 05/16] Require secret for hmac. --- libdevcrypto/SHA3MAC.cpp | 4 ++-- test/crypto.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp index 1fa370ca1..9498ef87b 100644 --- a/libdevcrypto/SHA3MAC.cpp +++ b/libdevcrypto/SHA3MAC.cpp @@ -31,8 +31,8 @@ using namespace CryptoPP; void crypto::sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) { CryptoPP::SHA3_256 ctx; - if (_secret.size() > 0) - ctx.Update((byte*)_secret.data(), _secret.size()); + assert(_secret.size() > 0); + ctx.Update((byte*)_secret.data(), _secret.size()); ctx.Update((byte*)_plain.data(), _plain.size()); assert(_output.size() >= 32); ctx.Final(_output.data()); diff --git a/test/crypto.cpp b/test/crypto.cpp index c1f678fcb..3d47d0b0c 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) bytes m(fromHex("0x01")); int tests = 5; - while (m[0]++ && tests--) + while (m[0]++, tests--) { h256 hm(sha3(m)); Integer hInt(hm.asBytes().data(), 32); From 5fc22a8cc79ab1e382e87de3490160ff186913c0 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 27 Oct 2014 18:08:10 +0100 Subject: [PATCH 06/16] numbers to words --- libdevcrypto/EC.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 77096b691..d6c2ad622 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -86,14 +86,15 @@ Signature crypto::sign(Secret const& _k, bytesConstRef _message) bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) { + static size_t derMaxEncodingLength = 72; if (_raw) { assert(_message.size() == 32); byte encpub[65] = {0x04}; memcpy(&encpub[1], _p.data(), 64); - byte dersig[72]; - size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, _sig.data(), 64, DSA_P1363); - assert(cssz <= 72); + byte dersig[derMaxEncodingLength]; + size_t cssz = DSAConvertSignatureFormat(dersig, derMaxEncodingLength, DSA_DER, _sig.data(), 64, DSA_P1363); + assert(cssz <= derMaxEncodingLength); return (1 == secp256k1_ecdsa_verify(_message.data(), _message.size(), dersig, cssz, encpub, 65)); } From 3ce9cde377007e84c331706093e92fbb6a943b6f Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 28 Oct 2014 16:24:49 +0100 Subject: [PATCH 07/16] revert oops; warning for unused-function disabled during link-time --- libdevcrypto/CryptoPP.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index fdeb67707..e7a5ea94c 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -23,10 +23,11 @@ #pragma once +// need to leave this one disabled for link-time. blame cryptopp. +#pragma GCC diagnostic ignored "-Wunused-function" #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" #pragma GCC diagnostic ignored "-Wconversion" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-variable" From 4c3894e4558809caa76cce824f70377d163ef5d4 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 29 Oct 2014 18:46:57 +0100 Subject: [PATCH 08/16] recover public key from ecdsa,v sig using cryptopp --- test/crypto.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/test/crypto.cpp b/test/crypto.cpp index acb7b7589..773c64d3b 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -86,6 +86,114 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) } } +BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) +{ + // cryptopp implementation of secp256k1lib sign_compact w/recid parameter for recovering public key from signature + + // cryptopp does this: + // void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const + // { + // const Integer &q = params.GetSubgroupOrder(); + // r %= q; + // Integer kInv = k.InverseMod(q); + // s = (kInv * (x*r + e)) % q; + // assert(!!r && !!s); + // } + + // secp256k1lib does this, which we want cryptopp to do: + // secp256k1_gej_t rp; + // secp256k1_ecmult_gen(&rp, nonce); + // secp256k1_ge_t r; + // secp256k1_ge_set_gej(&r, &rp); + // unsigned char b[32]; + // secp256k1_fe_normalize(&r.x); + // secp256k1_fe_normalize(&r.y); + // secp256k1_fe_get_b32(b, &r.x); + // secp256k1_num_set_bin(&sig->r, b, 32); + // if (recid) + // *recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + // secp256k1_num_mod(&sig->r, &c->order); + // secp256k1_num_t n; + // secp256k1_num_init(&n); + // secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order); + // secp256k1_num_add(&n, &n, message); + // secp256k1_num_mod(&n, &c->order); + // secp256k1_num_mod_inverse(&sig->s, nonce, &c->order); + // secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order); + // secp256k1_num_free(&n); + // if (secp256k1_num_is_zero(&sig->s)) + // return 0; + // if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) { + // secp256k1_num_sub(&sig->s, &c->order, &sig->s); + // if (recid) + // *recid ^= 1; + // } + + + // secret + Secret secret(sha3("privacy")); + + // e := sha3(msg) + bytes e(fromHex("0x01")); + e.resize(32); + int tests = 150; // Oct 29: successful @ 1500 + while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) + { + KeyPair key(secret); + + h256 he(sha3(e)); + Integer heInt(he.asBytes().data(), 32); + h256 k(he ^ key.sec()); + Integer kInt(k.asBytes().data(), 32); + + // we get ec params from signer + ECDSA::Signer signer; + pp::initializeSigner(key.sec(), signer); + + const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); + + ECP::Point rp = params.ExponentiateBase(kInt); + Integer const& q = params.GetGroupOrder(); + Integer r = params.ConvertElementToInteger(rp); + int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); + BOOST_REQUIRE(!(r>=q)); // interesting, this never happens + r %= q; + + Integer kInv = kInt.InverseMod(q); + Integer s = (kInv * (Integer(key.sec().asBytes().data(), 32)*r + heInt)) % q; + BOOST_REQUIRE(!!r && !!s); + + if (s > params.GetSubgroupOrder()) + { + // also interesting, this never happens + s = params.GetGroupOrder() - s; + if (recid) + recid ^= 1; + } + BOOST_REQUIRE(recid < 2); + + Signature sig; + r.Encode(sig.data(), 32); + s.Encode(sig.data()+32, 32); + sig[64] = recid; + + Public p = dev::recover(sig, he); + Public pkey = key.pub(); + BOOST_REQUIRE(p == pkey); + + // verify w/cryptopp + BOOST_REQUIRE(crypto::verify(key.pub(), sig, bytesConstRef(&e))); + + // verify with secp256k1lib + byte encpub[65] = {0x04}; + memcpy(&encpub[1], key.pub().data(), 64); + byte dersig[72]; + size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sig.data(), 64, DSA_P1363); + BOOST_CHECK(cssz <= 72); + BOOST_REQUIRE(1 == secp256k1_ecdsa_verify(he.data(), sizeof(he), dersig, cssz, encpub, 65)); + } +} + BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) { // cryptopp integer encoding From fb00cbc62906c1a0ba7d0b2fa981d92c969c5d09 Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 29 Oct 2014 19:24:23 +0100 Subject: [PATCH 09/16] remove asserts for recid being 2, which is rare, but may occur --- test/crypto.cpp | 74 +++++++++++-------------------------------------- 1 file changed, 16 insertions(+), 58 deletions(-) diff --git a/test/crypto.cpp b/test/crypto.cpp index 773c64d3b..e11659ed0 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -88,89 +88,48 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) { - // cryptopp implementation of secp256k1lib sign_compact w/recid parameter for recovering public key from signature - - // cryptopp does this: - // void Sign(const DL_GroupParameters ¶ms, const Integer &x, const Integer &k, const Integer &e, Integer &r, Integer &s) const - // { - // const Integer &q = params.GetSubgroupOrder(); - // r %= q; - // Integer kInv = k.InverseMod(q); - // s = (kInv * (x*r + e)) % q; - // assert(!!r && !!s); - // } - - // secp256k1lib does this, which we want cryptopp to do: - // secp256k1_gej_t rp; - // secp256k1_ecmult_gen(&rp, nonce); - // secp256k1_ge_t r; - // secp256k1_ge_set_gej(&r, &rp); - // unsigned char b[32]; - // secp256k1_fe_normalize(&r.x); - // secp256k1_fe_normalize(&r.y); - // secp256k1_fe_get_b32(b, &r.x); - // secp256k1_num_set_bin(&sig->r, b, 32); - // if (recid) - // *recid = (secp256k1_num_cmp(&sig->r, &c->order) >= 0 ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); - // secp256k1_num_mod(&sig->r, &c->order); - // secp256k1_num_t n; - // secp256k1_num_init(&n); - // secp256k1_num_mod_mul(&n, &sig->r, seckey, &c->order); - // secp256k1_num_add(&n, &n, message); - // secp256k1_num_mod(&n, &c->order); - // secp256k1_num_mod_inverse(&sig->s, nonce, &c->order); - // secp256k1_num_mod_mul(&sig->s, &sig->s, &n, &c->order); - // secp256k1_num_free(&n); - // if (secp256k1_num_is_zero(&sig->s)) - // return 0; - // if (secp256k1_num_cmp(&sig->s, &c->half_order) > 0) { - // secp256k1_num_sub(&sig->s, &c->order, &sig->s); - // if (recid) - // *recid ^= 1; - // } - - - // secret + // cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature + + // base secret Secret secret(sha3("privacy")); + // we get ec params from signer + ECDSA::Signer signer; + // e := sha3(msg) bytes e(fromHex("0x01")); e.resize(32); - int tests = 150; // Oct 29: successful @ 1500 + int tests = 15; // Oct 29: successful @ 1500 while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) { KeyPair key(secret); + Public pkey = key.pub(); + pp::initializeSigner(secret, signer); h256 he(sha3(e)); Integer heInt(he.asBytes().data(), 32); - h256 k(he ^ key.sec()); + h256 k(he ^ secret); Integer kInt(k.asBytes().data(), 32); - // we get ec params from signer - ECDSA::Signer signer; - pp::initializeSigner(key.sec(), signer); - const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); ECP::Point rp = params.ExponentiateBase(kInt); Integer const& q = params.GetGroupOrder(); Integer r = params.ConvertElementToInteger(rp); int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); - BOOST_REQUIRE(!(r>=q)); // interesting, this never happens - r %= q; - + BOOST_REQUIRE(!(r >= q)); + Integer kInv = kInt.InverseMod(q); - Integer s = (kInv * (Integer(key.sec().asBytes().data(), 32)*r + heInt)) % q; + Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); if (s > params.GetSubgroupOrder()) { - // also interesting, this never happens + // note: this rarely happens s = params.GetGroupOrder() - s; if (recid) recid ^= 1; } - BOOST_REQUIRE(recid < 2); Signature sig; r.Encode(sig.data(), 32); @@ -178,15 +137,14 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) sig[64] = recid; Public p = dev::recover(sig, he); - Public pkey = key.pub(); BOOST_REQUIRE(p == pkey); // verify w/cryptopp - BOOST_REQUIRE(crypto::verify(key.pub(), sig, bytesConstRef(&e))); + BOOST_REQUIRE(crypto::verify(pkey, sig, bytesConstRef(&e))); // verify with secp256k1lib byte encpub[65] = {0x04}; - memcpy(&encpub[1], key.pub().data(), 64); + memcpy(&encpub[1], pkey.data(), 64); byte dersig[72]; size_t cssz = DSAConvertSignatureFormat(dersig, 72, DSA_DER, sig.data(), 64, DSA_P1363); BOOST_CHECK(cssz <= 72); From 67747f8cc57dffb034a586c59183f4d694418317 Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 2 Nov 2014 04:41:16 +0100 Subject: [PATCH 10/16] Placeholder kdf. More cleanup and tests. --- libdevcrypto/Common.cpp | 141 ++++++++++++++------------------------ libdevcrypto/Common.h | 17 +++-- libdevcrypto/CryptoPP.cpp | 80 +++------------------ libdevcrypto/CryptoPP.h | 34 ++++----- libdevcrypto/EC.cpp | 130 ++++++++++++++++++++++++++++++----- libdevcrypto/EC.h | 23 +++++-- libdevcrypto/FileSystem.h | 1 + test/crypto.cpp | 34 ++++----- 8 files changed, 238 insertions(+), 222 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index c7503a820..e763cc9b2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -14,51 +14,30 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file CommonEth.cpp +/** @file Common.cpp * @author Gav Wood + * @author Alex Leverington * @date 2014 */ -#include "Common.h" + #include -#include #include "EC.h" #include "SHA3.h" +#include "FileSystem.h" +#include "Common.h" using namespace std; using namespace dev; //#define ETH_ADDRESS_DEBUG 1 -Address dev::toAddress(Secret _private) +Address dev::toAddress(Secret _secret) { - secp256k1_start(); - - byte pubkey[65]; - int pubkeylen = 65; - int ok = secp256k1_ecdsa_seckey_verify(_private.data()); - if (!ok) - return Address(); - ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _private.data(), 0); - if (asserts(pubkeylen == 65)) - return Address(); - if (!ok) - return Address(); - ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); - if (!ok) - return Address(); - auto ret = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); -#if ETH_ADDRESS_DEBUG - cout << "---- ADDRESS -------------------------------" << endl; - cout << "SEC: " << _private << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; - cout << "ADR: " << ret << endl; -#endif - return ret; + return KeyPair(_secret).address(); } KeyPair KeyPair::create() { - secp256k1_start(); static std::mt19937_64 s_eng(time(0)); std::uniform_int_distribution d(0, 255); @@ -78,25 +57,10 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { - secp256k1_start(); - int ok = secp256k1_ecdsa_seckey_verify(m_secret.data()); - if (!ok) - return; - - byte pubkey[65]; - int pubkeylen = 65; - ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, m_secret.data(), 0); - if (!ok || pubkeylen != 65) - return; - - ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); - if (!ok) - return; - - m_secret = m_secret; - memcpy(m_public.data(), &(pubkey[1]), 64); - m_address = right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); - + crypto::toPublic(m_secret, m_public); + if (crypto::verifySecret(m_secret, m_public)) + m_address = right160(dev::sha3(m_public.ref())); + #if ETH_ADDRESS_DEBUG cout << "---- ADDRESS -------------------------------" << endl; cout << "SEC: " << m_secret << endl; @@ -129,54 +93,12 @@ bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) Public dev::recover(Signature _sig, h256 _message) { - secp256k1_start(); - - byte pubkey[65]; - int pubkeylen = 65; - if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _sig.data(), pubkey, &pubkeylen, 0, (int)_sig[64])) - return Public(); - - // right160(dev::sha3(bytesConstRef(&(pubkey[1]), 64))); -#if ETH_CRYPTO_TRACE - h256* sig = (h256 const*)_sig.data(); - cout << "---- RECOVER -------------------------------" << endl; - cout << "MSG: " << _message << endl; - cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_sig[64] - 27) << "+27" << endl; - cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; -#endif - - Public ret; - memcpy(&ret, &(pubkey[1]), sizeof(Public)); - return ret; -} - -inline h256 kFromMessage(h256 _msg, h256 _priv) -{ - return _msg ^ _priv; + return crypto::recover(_sig, _message.ref()); } Signature dev::sign(Secret _k, h256 _hash) { - int v = 0; - - secp256k1_start(); - - SignatureStruct ret; - h256 nonce = kFromMessage(_hash, _k); - - if (!secp256k1_ecdsa_sign_compact(_hash.data(), 32, ret.r.data(), _k.data(), nonce.data(), &v)) - return Signature(); - -#if ETH_ADDRESS_DEBUG - cout << "---- SIGN -------------------------------" << endl; - cout << "MSG: " << _message << endl; - cout << "SEC: " << _k << endl; - cout << "NON: " << nonce << endl; - cout << "R S V: " << ret.r << " " << ret.s << " " << v << "+27" << endl; -#endif - - ret.v = v; - return *(Signature const*)&ret; + return crypto::sign(_k, _hash); } bool dev::verify(Public _p, Signature _s, h256 _hash) @@ -184,3 +106,40 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } +h256 Sec::getNonce(bool _commit) +{ + // todo: atomic efface bit, periodic save, kdf, rr, rng + static h256 seed; + static string seedFile(getDataDir() + "/seed"); + static mutex x; + lock_guard l(x); + { + if (!seed) + { + static Sec sec; + + bytes b = contents(seedFile); + if (b.size() == 32) + memcpy(seed.data(), b.data(), 32); + else + { + std::mt19937_64 s_eng(time(0)); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + seed[i] = (byte)d(s_eng); + } + writeFile(seedFile, bytes()); + } + assert(seed); + h256 prev(seed); + sha3(prev.ref(), seed.ref()); + if (_commit) + writeFile(seedFile, seed.asBytes()); + } + return seed; +} + +Sec::~Sec() +{ + Sec::getNonce(true); +} diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index bd9a4fbd4..e163fb1c4 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -14,8 +14,9 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file CommonEth.h +/** @file Common.h * @author Gav Wood + * @author Alex Leverington * @date 2014 * * Ethereum-specific data structures & algorithms. @@ -63,8 +64,8 @@ void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); /// Decrypts cipher using Secret key. bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext); -/// Recovers Public key from signed message. -Public recover(Signature _sig, h256 _message); +/// Recovers Public key from signed message hash. +Public recover(Signature _sig, h256 _hash); /// Returns siganture of message hash. Signature sign(Secret _k, h256 _hash); @@ -109,5 +110,13 @@ private: Public m_public; Address m_address; }; + +struct Sec +{ + static h256 getNonce(bool _commit = false); +private: + Sec() {} + ~Sec(); +}; -} +} \ No newline at end of file diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index fa45e6242..1b51d5bd5 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -25,85 +25,21 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -/// Conversion from bytes to cryptopp point -inline ECP::Point publicToPoint(Public const& _p); -/// Conversion from bytes to cryptopp exponent -inline Integer secretToExponent(Secret const& _s); - -/// Conversion from cryptopp exponent Integer to bytes -inline void exponentToPublic(Integer const& _e, Public& _p); - -void pp::initializeSigner(Secret const& _s, ECDSA::Signer& _signer) -{ - _signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _signer.AccessKey().SetPrivateExponent(secretToExponent(_s)); -} - -void pp::initializeVerifier(Public const& _p, ECDSA::Verifier& _verifier) -{ - _verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _verifier.AccessKey().SetPublicElement(publicToPoint(_p)); -} - -void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& _encryptor) -{ - _encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _encryptor.AccessKey().SetPublicElement(publicToPoint(_p)); -} - -void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& _decryptor) -{ - _decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve); - _decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s)); -} +/// Integer and Point Conversion: void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) { bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); - _k.GetGroupParameters().GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); - - static_assert(Public::size == 64, "Public key must be 64 bytes."); + secp256k1Params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); + assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); memcpy(_p.data(), &prefixedKey[1], Public::size); } -void pp::exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) +void pp::exponentToPublic(Integer const& _e, Public& _p) { - _k.GetPrivateExponent().Encode(_s.data(), Secret::size); -} - -/// Integer and Point Conversion: - -inline ECP::Point publicToPoint(Public const& _p) -{ - ECP::Point p; - CryptoPP::DL_PublicKey_EC pub; - pub.AccessGroupParameters().Initialize(pp::secp256k1Curve); - - bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true)); - prefixedKey[0] = 0x04; - assert(Public::size == prefixedKey.size() - 1); - memcpy(&prefixedKey[1], _p.data(), prefixedKey.size() - 1); - - pub.GetGroupParameters().GetCurve().DecodePoint(p, prefixedKey.data(), prefixedKey.size()); - return std::move(p); -} - -inline Integer secretToExponent(Secret const& _s) -{ - static_assert(Secret::size == 32, "Secret key must be 32 bytes."); - return std::move(Integer(_s.data(), Secret::size)); -} - -inline void exponentToPublic(Integer const& _e, Public& _p) -{ - CryptoPP::DL_PrivateKey_EC k; - k.AccessGroupParameters().Initialize(pp::secp256k1Curve); - k.SetPrivateExponent(_e); - - CryptoPP::DL_PublicKey_EC p; - p.AccessGroupParameters().Initialize(pp::secp256k1Curve); - k.MakePublicKey(p); - pp::exportPublicKey(p, _p); -} + CryptoPP::DL_PublicKey_EC pk; + pk.Initialize(secp256k1Params, secp256k1Params.ExponentiateBase(_e)); + pp::exportPublicKey(pk, _p); +} \ No newline at end of file diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index e7a5ea94c..756bbb72a 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * CryptoPP headers and helper methods + * CryptoPP headers and primitive helper methods */ #pragma once @@ -45,7 +45,6 @@ #include #include #include -#include #include #pragma warning(pop) #pragma GCC diagnostic pop @@ -55,34 +54,35 @@ namespace dev { namespace crypto { - namespace pp { - + +using namespace CryptoPP; + /// CryptoPP random number pool static CryptoPP::AutoSeededRandomPool PRNG; /// CryptoPP EC Cruve static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); - -/// Initialize signer with Secret -void initializeSigner(Secret const& _s, CryptoPP::ECDSA::Signer& out_signer); -/// Initialize verifier with Public -void initializeVerifier(Public const& _p, CryptoPP::ECDSA::Verifier& _verifier); +static const CryptoPP::DL_GroupParameters_EC secp256k1Params(secp256k1Curve); -/// Initialize cryptopp encryptor with Public -void initializeEncryptor(Public const& _p, CryptoPP::ECIES::Encryptor& out_encryptor); +static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data()+32, 32); return std::move(ECP::Point(x,y)); } -/// Initialize cryptopp decryptor with Secret -void initializeDecryptor(Secret const& _s, CryptoPP::ECIES::Decryptor& out_decryptor); +static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } + +void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); -/// Conversion from cryptopp public key to bytes -void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& out_p); +static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } -/// Conversion from cryptopp private key to bytes -void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& out_s); +void exponentToPublic(Integer const& _e, Public& _p); +template +void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_s)); } + +template +void initializeDLScheme(Public const& _p, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, publicToPoint(_p)); } + } } } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index d6c2ad622..e6b4c19c8 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * Shared EC classes and functions. + * ECDSA, ECIES */ #pragma warning(push) @@ -32,25 +32,44 @@ #include #pragma warning(pop) #pragma GCC diagnostic pop +#include #include "CryptoPP.h" #include "SHA3.h" +#include "SHA3MAC.h" #include "EC.h" -// CryptoPP and dev conflict so dev and pp namespace are used explicitly +static_assert(dev::Secret::size == 32, "Secret key must be 32 bytes."); +static_assert(dev::Public::size == 64, "Public key must be 64 bytes."); +static_assert(dev::Signature::size == 65, "Signature must be 65 bytes."); + using namespace std; using namespace dev; using namespace dev::crypto; using namespace CryptoPP; +using namespace pp; + +void crypto::toPublic(Secret const& _s, Public& o_public) +{ + exponentToPublic(Integer(_s.data(),sizeof(_s)), o_public); +} -void crypto::encrypt(Public const& _key, bytes& io_cipher) +h256 crypto::kdf(Secret const& _priv, h256 const& _hash) +{ + h256 s; + sha3mac(Sec::getNonce().ref(), _priv.ref(), s.ref()); + assert(s); + return sha3((_hash ^ s).asBytes()); +} + +void crypto::encrypt(Public const& _k, bytes& io_cipher) { ECIES::Encryptor e; - pp::initializeEncryptor(_key, e); + initializeDLScheme(_k, e); size_t plen = io_cipher.size(); bytes c; c.resize(e.CiphertextLength(plen)); // todo: use StringSource with io_cipher as input and output. - e.Encrypt(pp::PRNG, io_cipher.data(), plen, c.data()); + e.Encrypt(PRNG, io_cipher.data(), plen, c.data()); memset(io_cipher.data(), 0, io_cipher.size()); io_cipher = std::move(c); } @@ -58,12 +77,12 @@ void crypto::encrypt(Public const& _key, bytes& io_cipher) void crypto::decrypt(Secret const& _k, bytes& io_text) { CryptoPP::ECIES::Decryptor d; - pp::initializeDecryptor(_k, d); + initializeDLScheme(_k, d); size_t clen = io_text.size(); bytes p; p.resize(d.MaxPlaintextLength(io_text.size())); // todo: use StringSource with io_text as input and output. - DecodingResult r = d.Decrypt(pp::PRNG, io_text.data(), clen, p.data()); + DecodingResult r = d.Decrypt(PRNG, io_text.data(), clen, p.data()); if (!r.isValidCoding) { io_text.clear(); @@ -75,19 +94,51 @@ void crypto::decrypt(Secret const& _k, bytes& io_text) Signature crypto::sign(Secret const& _k, bytesConstRef _message) { - ECDSA::Signer signer; - pp::initializeSigner(_k, signer); + return crypto::sign(_k, sha3(_message)); +} + +Signature crypto::sign(Secret const& _key, h256 const& _hash) +{ + ECDSA::Signer signer; + initializeDLScheme(_key, signer); + + Integer const& q = secp256k1Params.GetGroupOrder(); + Integer e(_hash.asBytes().data(), 32); + + Integer k(kdf(_key, _hash).data(), 32); + k %= secp256k1Params.GetSubgroupOrder()-1; + + ECP::Point rp = secp256k1Params.ExponentiateBase(k); + Integer r = secp256k1Params.ConvertElementToInteger(rp); + int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); + + Integer kInv = k.InverseMod(q); + Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q; + assert(!!r && !!s); + + if (s > secp256k1Params.GetSubgroupOrder()) + { + s = q - s; + if (recid) + recid ^= 1; + } + + Signature sig; + r.Encode(sig.data(), 32); + s.Encode(sig.data()+32, 32); + sig[64] = recid; + return sig; +} - string sigstr; - StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr))); - FixedHash retsig((byte const*)sigstr.data(), Signature::ConstructFromPointer); - return std::move(retsig); +bool crypto::verify(Signature const& _signature, bytesConstRef _message) +{ + return crypto::verify(crypto::recover(_signature, _message), _signature, _message); } -bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw) +bool crypto::verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed) { static size_t derMaxEncodingLength = 72; - if (_raw) + if (_hashed) { assert(_message.size() == 32); byte encpub[65] = {0x04}; @@ -99,10 +150,53 @@ bool crypto::verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw } ECDSA::Verifier verifier; - pp::initializeVerifier(_p, verifier); - // cryptopp signatures are 64 bytes - static_assert(sizeof(Signature) == 65, "Expected 65-byte signature."); + initializeDLScheme(_p, verifier); return verifier.VerifyMessage(_message.data(), _message.size(), _sig.data(), sizeof(Signature) - 1); } +Public crypto::recover(Signature _signature, bytesConstRef _message) +{ + secp256k1_start(); + + byte pubkey[65]; + int pubkeylen = 65; + if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) + return Public(); + +#if ETH_CRYPTO_TRACE + h256* sig = (h256 const*)_signature.data(); + cout << "---- RECOVER -------------------------------" << endl; + cout << "MSG: " << _message << endl; + cout << "R S V: " << sig[0] << " " << sig[1] << " " << (int)(_signature[64] - 27) << "+27" << endl; + cout << "PUB: " << toHex(bytesConstRef(&(pubkey[1]), 64)) << endl; +#endif + + Public ret; + memcpy(&ret, &(pubkey[1]), sizeof(Public)); + return ret; +} + +bool crypto::verifySecret(Secret const& _s, Public const& _p) +{ + secp256k1_start(); + int ok = secp256k1_ecdsa_seckey_verify(_s.data()); + if (!ok) + return false; + + byte pubkey[65]; + int pubkeylen = 65; + ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); + if (!ok || pubkeylen != 65) + return false; + + ok = secp256k1_ecdsa_pubkey_verify(pubkey, 65); + if (!ok) + return false; + + for (int i = 0; i < 32; i++) + if (pubkey[i+1]!=_p[i]) + return false; + + return true; +} diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index d98472a54..2a4155edf 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -18,7 +18,7 @@ * @author Alex Leverington * @date 2014 * - * Shared EC classes and functions. + * ECDSA, ECIES */ #pragma once @@ -30,18 +30,33 @@ namespace dev namespace crypto { +void toPublic(Secret const& _s, Public& o_public); +h256 kdf(Secret const& _priv, h256 const& _hash); + /// Encrypts text (in place). void encrypt(Public const& _k, bytes& io_cipher); /// Decrypts text (in place). void decrypt(Secret const& _k, bytes& io_text); -/// Returns siganture of message hash. +/// Returns siganture of message. Signature sign(Secret const& _k, bytesConstRef _message); + +/// Returns compact siganture of message hash. +Signature sign(Secret const& _k, h256 const& _hash); -/// Verify signature -bool verify(Public _p, Signature _sig, bytesConstRef _message, bool _raw = false); +/// Verify compact signature (public key is extracted from message). +bool verify(Signature const& _signature, bytesConstRef _message); + +/// Verify signature. +bool verify(Public const& _p, Signature const& _sig, bytesConstRef _message, bool _hashed = false); +/// Recovers public key from compact signature. Uses libsecp256k1. +Public recover(Signature _signature, bytesConstRef _message); + +bool verifySecret(Secret const& _s, Public const& _p); + } + } diff --git a/libdevcrypto/FileSystem.h b/libdevcrypto/FileSystem.h index 605545b0d..281e60e24 100644 --- a/libdevcrypto/FileSystem.h +++ b/libdevcrypto/FileSystem.h @@ -24,6 +24,7 @@ #pragma once #include +#include namespace dev { diff --git a/test/crypto.cpp b/test/crypto.cpp index e11659ed0..ab384a038 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); Secret previous = s; - for (auto i = 0; i < 30; i++) + for (auto i = 0; i < 2; i++) { ECIES::Decryptor d(pp::PRNG, pp::secp256k1Curve); ECIES::Encryptor e(d.GetKey()); @@ -82,7 +82,13 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) Public p; pp::exportPublicKey(e.GetKey(), p); - BOOST_REQUIRE(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + h160 secp256k1Addr = dev::toAddress(s); + h160 cryptoppAddr = right160(dev::sha3(p.ref())); + if (secp256k1Addr != cryptoppAddr) + { + BOOST_REQUIRE(secp256k1Addr == cryptoppAddr); + break; + } } } @@ -94,30 +100,29 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) Secret secret(sha3("privacy")); // we get ec params from signer + const CryptoPP::DL_GroupParameters_EC params = pp::secp256k1Params; ECDSA::Signer signer; // e := sha3(msg) bytes e(fromHex("0x01")); e.resize(32); - int tests = 15; // Oct 29: successful @ 1500 + int tests = 2; // Oct 29: successful @ 1500 while (sha3(&e, &e), secret = sha3(secret.asBytes()), tests--) { KeyPair key(secret); Public pkey = key.pub(); - pp::initializeSigner(secret, signer); + pp::initializeDLScheme(secret, signer); h256 he(sha3(e)); Integer heInt(he.asBytes().data(), 32); - h256 k(he ^ secret); + h256 k(crypto::kdf(secret, he)); Integer kInt(k.asBytes().data(), 32); - - const DL_GroupParameters ¶ms = signer.GetKey().GetAbstractGroupParameters(); + kInt %= params.GetSubgroupOrder()-1; ECP::Point rp = params.ExponentiateBase(kInt); Integer const& q = params.GetGroupOrder(); Integer r = params.ConvertElementToInteger(rp); int recid = ((r >= q) ? 2 : 0) | (rp.y.IsOdd() ? 1 : 0); - BOOST_REQUIRE(!(r >= q)); Integer kInv = kInt.InverseMod(q); Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; @@ -164,7 +169,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) KeyPair key(secret); bytes m(fromHex("0x01")); - int tests = 5; + int tests = 2; while (m[0]++, tests--) { h256 hm(sha3(m)); @@ -174,27 +179,26 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) // raw sign w/cryptopp (doesn't pass through cryptopp hash filter) ECDSA::Signer signer; - pp::initializeSigner(key.sec(), signer); + pp::initializeDLScheme(key.sec(), signer); Integer r, s; signer.RawSign(kInt, hInt, r, s); // verify cryptopp raw-signature w/cryptopp ECDSA::Verifier verifier; - pp::initializeVerifier(key.pub(), verifier); + pp::initializeDLScheme(key.pub(), verifier); Signature sigppraw; r.Encode(sigppraw.data(), 32); s.Encode(sigppraw.data()+32, 32); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); - BOOST_CHECK(dev::recover(sigppraw, hm) == key.pub()); - // sign with sec256lib, verify with cryptopp + // sign with cryptopp, verify, recover w/sec256lib Signature seclibsig(dev::sign(key.sec(), hm)); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), seclibsig.data(), 64)); BOOST_REQUIRE(crypto::verify(key.pub(), seclibsig, bytesConstRef(&m))); BOOST_REQUIRE(dev::verify(key.pub(), seclibsig, hm)); - BOOST_CHECK(dev::recover(seclibsig, hm) == key.pub()); + BOOST_REQUIRE(dev::recover(seclibsig, hm) == key.pub()); // sign with cryptopp (w/hash filter?), verify with cryptopp bytes sigppb(signer.MaxSignatureLength()); @@ -204,7 +208,6 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppb.data(), ssz)); BOOST_REQUIRE(crypto::verify(key.pub(), sigpp, bytesConstRef(&m))); BOOST_REQUIRE(dev::verify(key.pub(), sigpp, hm)); - BOOST_CHECK(dev::recover(sigpp, hm) == key.pub()); // sign with cryptopp and stringsource hash filter string sigstr; @@ -213,7 +216,6 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), retsig.data(), 64)); BOOST_REQUIRE(crypto::verify(key.pub(), retsig, bytesConstRef(&m))); BOOST_REQUIRE(dev::verify(key.pub(), retsig, hm)); - BOOST_CHECK(dev::recover(retsig, hm) == key.pub()); /// verification w/sec256lib // requires public key and sig in standard format From 482a1241f78a221e255b9d4cc0700c0fdb30429b Mon Sep 17 00:00:00 2001 From: subtly Date: Sun, 2 Nov 2014 15:05:40 +0100 Subject: [PATCH 11/16] rename nonce generator --- libdevcrypto/Common.cpp | 18 +++++++++--------- libdevcrypto/Common.h | 16 +++++++++++----- libdevcrypto/EC.cpp | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index e763cc9b2..f039435ad 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -28,6 +28,7 @@ #include "Common.h" using namespace std; using namespace dev; +using namespace crypto; //#define ETH_ADDRESS_DEBUG 1 @@ -38,8 +39,8 @@ Address dev::toAddress(Secret _secret) KeyPair KeyPair::create() { - static std::mt19937_64 s_eng(time(0)); - std::uniform_int_distribution d(0, 255); + static mt19937_64 s_eng(time(0)); + uniform_int_distribution d(0, 255); for (int i = 0; i < 100; ++i) { @@ -57,8 +58,8 @@ KeyPair KeyPair::create() KeyPair::KeyPair(h256 _sec): m_secret(_sec) { - crypto::toPublic(m_secret, m_public); - if (crypto::verifySecret(m_secret, m_public)) + toPublic(m_secret, m_public); + if (verifySecret(m_secret, m_public)) m_address = right160(dev::sha3(m_public.ref())); #if ETH_ADDRESS_DEBUG @@ -106,7 +107,7 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) return crypto::verify(_p, _s, bytesConstRef(_hash.data(), 32), true); } -h256 Sec::getNonce(bool _commit) +h256 Nonce::get(bool _commit) { // todo: atomic efface bit, periodic save, kdf, rr, rng static h256 seed; @@ -116,8 +117,7 @@ h256 Sec::getNonce(bool _commit) { if (!seed) { - static Sec sec; - + static Nonce nonce; bytes b = contents(seedFile); if (b.size() == 32) memcpy(seed.data(), b.data(), 32); @@ -139,7 +139,7 @@ h256 Sec::getNonce(bool _commit) return seed; } -Sec::~Sec() +Nonce::~Nonce() { - Sec::getNonce(true); + Nonce::get(true); } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index e163fb1c4..167621ec0 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -110,13 +110,19 @@ private: Public m_public; Address m_address; }; - -struct Sec + +namespace crypto +{ +/** + * @brief Generator for nonce material + */ +struct Nonce { - static h256 getNonce(bool _commit = false); + static h256 get(bool _commit = false); private: - Sec() {} - ~Sec(); + Nonce() {} + ~Nonce(); }; +} } \ No newline at end of file diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index e6b4c19c8..73c36ffdc 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -56,7 +56,7 @@ void crypto::toPublic(Secret const& _s, Public& o_public) h256 crypto::kdf(Secret const& _priv, h256 const& _hash) { h256 s; - sha3mac(Sec::getNonce().ref(), _priv.ref(), s.ref()); + sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); assert(s); return sha3((_hash ^ s).asBytes()); } From a373315639f8763b740032b9d693d98342c84f98 Mon Sep 17 00:00:00 2001 From: subtly Date: Mon, 3 Nov 2014 11:43:07 +0100 Subject: [PATCH 12/16] fix build (mutex header missing) --- libdevcrypto/Common.cpp | 2 +- libdevcrypto/EC.cpp | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index f039435ad..b06a16e57 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -20,8 +20,8 @@ * @date 2014 */ - #include +#include #include "EC.h" #include "SHA3.h" #include "FileSystem.h" diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 73c36ffdc..16f3c6830 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -21,17 +21,6 @@ * ECDSA, ECIES */ -#pragma warning(push) -#pragma warning(disable:4100 4244) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -#pragma GCC diagnostic ignored "-Wextra" -#include -#pragma warning(pop) -#pragma GCC diagnostic pop #include #include "CryptoPP.h" #include "SHA3.h" From 1c746c7233379026562d04dcd385821e8b4001fc Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 4 Nov 2014 10:54:46 +0100 Subject: [PATCH 13/16] codereview fixes --- libdevcrypto/Common.cpp | 34 ++++++++++++++++------------------ libdevcrypto/CryptoPP.h | 2 +- libdevcrypto/EC.cpp | 14 ++++++++------ test/crypto.cpp | 4 ++-- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index b06a16e57..bd1c80268 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -114,28 +114,26 @@ h256 Nonce::get(bool _commit) static string seedFile(getDataDir() + "/seed"); static mutex x; lock_guard l(x); + if (!seed) { - if (!seed) + static Nonce nonce; + bytes b = contents(seedFile); + if (b.size() == 32) + memcpy(seed.data(), b.data(), 32); + else { - static Nonce nonce; - bytes b = contents(seedFile); - if (b.size() == 32) - memcpy(seed.data(), b.data(), 32); - else - { - std::mt19937_64 s_eng(time(0)); - std::uniform_int_distribution d(0, 255); - for (unsigned i = 0; i < 32; ++i) - seed[i] = (byte)d(s_eng); - } - writeFile(seedFile, bytes()); + std::mt19937_64 s_eng(time(0)); + std::uniform_int_distribution d(0, 255); + for (unsigned i = 0; i < 32; ++i) + seed[i] = (byte)d(s_eng); } - assert(seed); - h256 prev(seed); - sha3(prev.ref(), seed.ref()); - if (_commit) - writeFile(seedFile, seed.asBytes()); + writeFile(seedFile, bytes()); } + assert(seed); + h256 prev(seed); + sha3(prev.ref(), seed.ref()); + if (_commit) + writeFile(seedFile, seed.asBytes()); return seed; } diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index 756bbb72a..dc5d6a610 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -67,7 +67,7 @@ static const CryptoPP::OID secp256k1Curve = CryptoPP::ASN1::secp256k1(); static const CryptoPP::DL_GroupParameters_EC secp256k1Params(secp256k1Curve); -static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data()+32, 32); return std::move(ECP::Point(x,y)); } +static ECP::Point publicToPoint(Public const& _p) { Integer x(_p.data(), 32); Integer y(_p.data() + 32, 32); return std::move(ECP::Point(x,y)); } static Integer secretToExponent(Secret const& _s) { return std::move(Integer(_s.data(), Secret::size)); } diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 16f3c6830..890b7e2f4 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -39,7 +39,7 @@ using namespace pp; void crypto::toPublic(Secret const& _s, Public& o_public) { - exponentToPublic(Integer(_s.data(),sizeof(_s)), o_public); + exponentToPublic(Integer(_s.data(), sizeof(_s)), o_public); } h256 crypto::kdf(Secret const& _priv, h256 const& _hash) @@ -92,10 +92,12 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) initializeDLScheme(_key, signer); Integer const& q = secp256k1Params.GetGroupOrder(); + Integer const& qs = secp256k1Params.GetSubgroupOrder(); Integer e(_hash.asBytes().data(), 32); Integer k(kdf(_key, _hash).data(), 32); - k %= secp256k1Params.GetSubgroupOrder()-1; + assert(k); + k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k); Integer r = secp256k1Params.ConvertElementToInteger(rp); @@ -105,7 +107,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer s = (kInv * (Integer(_key.asBytes().data(), 32)*r + e)) % q; assert(!!r && !!s); - if (s > secp256k1Params.GetSubgroupOrder()) + if (s > qs) { s = q - s; if (recid) @@ -114,7 +116,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Signature sig; r.Encode(sig.data(), 32); - s.Encode(sig.data()+32, 32); + s.Encode(sig.data() + 32, 32); sig[64] = recid; return sig; } @@ -147,8 +149,8 @@ Public crypto::recover(Signature _signature, bytesConstRef _message) { secp256k1_start(); - byte pubkey[65]; int pubkeylen = 65; + byte pubkey[pubkeylen]; if (!secp256k1_ecdsa_recover_compact(_message.data(), 32, _signature.data(), pubkey, &pubkeylen, 0, (int)_signature[64])) return Public(); @@ -172,8 +174,8 @@ bool crypto::verifySecret(Secret const& _s, Public const& _p) if (!ok) return false; - byte pubkey[65]; int pubkeylen = 65; + byte pubkey[pubkeylen]; ok = secp256k1_ecdsa_pubkey_create(pubkey, &pubkeylen, _s.data(), 0); if (!ok || pubkeylen != 65) return false; diff --git a/test/crypto.cpp b/test/crypto.cpp index ab384a038..82950f09d 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) Signature sig; r.Encode(sig.data(), 32); - s.Encode(sig.data()+32, 32); + s.Encode(sig.data() + 32, 32); sig[64] = recid; Public p = dev::recover(sig, he); @@ -188,7 +188,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdsa_sipaseckp256k1) pp::initializeDLScheme(key.pub(), verifier); Signature sigppraw; r.Encode(sigppraw.data(), 32); - s.Encode(sigppraw.data()+32, 32); + s.Encode(sigppraw.data() + 32, 32); BOOST_REQUIRE(verifier.VerifyMessage(m.data(), m.size(), sigppraw.data(), 64)); BOOST_REQUIRE(crypto::verify(key.pub(), sigppraw, bytesConstRef(&m))); BOOST_REQUIRE(dev::verify(key.pub(), sigppraw, hm)); From 8eaa26e71693fe47fa50a2bf4593f8dce795949a Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 4 Nov 2014 13:45:45 +0100 Subject: [PATCH 14/16] replace asserts with exception --- libdevcrypto/Common.cpp | 5 ++++- libdevcrypto/Common.h | 3 +++ libdevcrypto/EC.cpp | 12 +++++++++--- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index bd1c80268..14dad127e 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -127,9 +127,12 @@ h256 Nonce::get(bool _commit) for (unsigned i = 0; i < 32; ++i) seed[i] = (byte)d(s_eng); } + if (!seed) + throw InvalidState(); + + // prevent seed reuse if process terminates abnormally writeFile(seedFile, bytes()); } - assert(seed); h256 prev(seed); sha3(prev.ref(), seed.ref()); if (_commit) diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 167621ec0..7e74c754d 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -26,6 +26,7 @@ #include #include +#include namespace dev { @@ -113,6 +114,8 @@ private: namespace crypto { +struct InvalidState: virtual Exception {}; + /** * @brief Generator for nonce material */ diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 890b7e2f4..fd64f60d0 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -44,10 +44,15 @@ void crypto::toPublic(Secret const& _s, Public& o_public) h256 crypto::kdf(Secret const& _priv, h256 const& _hash) { + // H(H(r||k)^h) h256 s; sha3mac(Nonce::get().ref(), _priv.ref(), s.ref()); - assert(s); - return sha3((_hash ^ s).asBytes()); + s ^= _hash; + sha3(s.ref(), s.ref()); + + if (!s || !_hash || !_priv) + throw InvalidState(); + return std::move(s); } void crypto::encrypt(Public const& _k, bytes& io_cipher) @@ -96,7 +101,8 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer e(_hash.asBytes().data(), 32); Integer k(kdf(_key, _hash).data(), 32); - assert(k); + if (k == 0) + throw InvalidState(); k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k); From b50578f1e6ccfdfa3fdda94ebdca1de910c5f67e Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Nov 2014 14:13:27 +0100 Subject: [PATCH 15/16] coding standards, documentation, new exception syntax --- libdevcore/Exceptions.h | 1 - libdevcrypto/Common.cpp | 32 +++++++++++++++++--------------- libdevcrypto/Common.h | 4 ++-- libwhisper/Message.h | 1 + test/crypto.cpp | 9 ++++++++- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 932276d01..7576050e6 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -24,7 +24,6 @@ #include #include #include -#include #include "CommonData.h" #include "FixedHash.h" diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 14dad127e..38d2eb934 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -110,34 +110,36 @@ bool dev::verify(Public _p, Signature _s, h256 _hash) h256 Nonce::get(bool _commit) { // todo: atomic efface bit, periodic save, kdf, rr, rng - static h256 seed; - static string seedFile(getDataDir() + "/seed"); - static mutex x; - lock_guard l(x); - if (!seed) + // todo: encrypt + static h256 s_seed; + static string s_seedFile(getDataDir() + "/seed"); + static mutex s_x; + lock_guard l(s_x); + if (!s_seed) { - static Nonce nonce; - bytes b = contents(seedFile); + static Nonce s_nonce; + bytes b = contents(s_seedFile); if (b.size() == 32) - memcpy(seed.data(), b.data(), 32); + memcpy(s_seed.data(), b.data(), 32); else { + // todo: replace w/entropy from user and system std::mt19937_64 s_eng(time(0)); std::uniform_int_distribution d(0, 255); for (unsigned i = 0; i < 32; ++i) - seed[i] = (byte)d(s_eng); + s_seed[i] = (byte)d(s_eng); } - if (!seed) + if (!s_seed) throw InvalidState(); // prevent seed reuse if process terminates abnormally - writeFile(seedFile, bytes()); + writeFile(s_seedFile, bytes()); } - h256 prev(seed); - sha3(prev.ref(), seed.ref()); + h256 prev(s_seed); + sha3(prev.ref(), s_seed.ref()); if (_commit) - writeFile(seedFile, seed.asBytes()); - return seed; + writeFile(s_seedFile, s_seed.asBytes()); + return std::move(s_seed); } Nonce::~Nonce() diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 7e74c754d..6fcda73cb 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -114,8 +114,8 @@ private: namespace crypto { -struct InvalidState: virtual Exception {}; - +struct InvalidState: public dev::Exception {}; + /** * @brief Generator for nonce material */ diff --git a/libwhisper/Message.h b/libwhisper/Message.h index 6b28073b7..677d16f00 100644 --- a/libwhisper/Message.h +++ b/libwhisper/Message.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "Common.h" diff --git a/test/crypto.cpp b/test/crypto.cpp index 82950f09d..b0785aca1 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) } } -BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) +BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_secp256k1libport) { // cryptopp implementation of secp256k1lib sign_compact w/recid parameter and recovery of public key from signature @@ -128,6 +128,12 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) Integer s = (kInv * (Integer(secret.asBytes().data(), 32)*r + heInt)) % q; BOOST_REQUIRE(!!r && !!s); +/* + // For future reference: + // According to maths, this codepath can't be reached, however, it's in secp256k1. + // Commenting this out diverges from codebase implementation. + // To be removed after upstream PR and proof are evaulated. + if (s > params.GetSubgroupOrder()) { // note: this rarely happens @@ -135,6 +141,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_cryptopp_ecdsav) if (recid) recid ^= 1; } + */ Signature sig; r.Encode(sig.data(), 32); From 5eacc23cb1032cd851caecf43107d2c2d1a85aab Mon Sep 17 00:00:00 2001 From: subtly Date: Wed, 5 Nov 2014 16:09:39 +0100 Subject: [PATCH 16/16] use boost_throw_exception --- libdevcrypto/Common.cpp | 2 +- libdevcrypto/EC.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 38d2eb934..d82098655 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -130,7 +130,7 @@ h256 Nonce::get(bool _commit) s_seed[i] = (byte)d(s_eng); } if (!s_seed) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); // prevent seed reuse if process terminates abnormally writeFile(s_seedFile, bytes()); diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index fd64f60d0..af6d0e65e 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -51,7 +51,7 @@ h256 crypto::kdf(Secret const& _priv, h256 const& _hash) sha3(s.ref(), s.ref()); if (!s || !_hash || !_priv) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); return std::move(s); } @@ -102,7 +102,7 @@ Signature crypto::sign(Secret const& _key, h256 const& _hash) Integer k(kdf(_key, _hash).data(), 32); if (k == 0) - throw InvalidState(); + BOOST_THROW_EXCEPTION(InvalidState()); k = 1 + (k % (qs - 1)); ECP::Point rp = secp256k1Params.ExponentiateBase(k);