Browse Source

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.

cl-refactor
subtly 10 years ago
parent
commit
538aae8078
  1. 25
      libdevcrypto/Common.cpp
  2. 5
      libdevcrypto/Common.h
  3. 79
      libdevcrypto/CryptoPP.cpp
  4. 30
      libdevcrypto/CryptoPP.h
  5. 42
      libdevcrypto/EC.cpp
  6. 9
      libdevcrypto/EC.h
  7. 3
      libdevcrypto/SHA3MAC.cpp
  8. 99
      test/crypto.cpp

25
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;
}

5
libdevcrypto/Common.h

@ -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.

79
libdevcrypto/CryptoPP.cpp

@ -25,11 +25,61 @@ 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<ECP, CryptoPP::SHA3_256>::Signer& _signer)
{
_signer.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve);
_signer.AccessKey().SetPrivateExponent(secretToExponent(_s));
}
void pp::initializeVerifier(Public const& _p, ECDSA<ECP, CryptoPP::SHA3_256>::Verifier& _verifier)
{
_verifier.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve);
_verifier.AccessKey().SetPublicElement(publicToPoint(_p));
}
void pp::initializeEncryptor(Public const& _p, CryptoPP::ECIES<CryptoPP::ECP>::Encryptor& _encryptor)
{
_encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve);
_encryptor.AccessKey().SetPublicElement(publicToPoint(_p));
}
void pp::initializeDecryptor(Secret const& _s, CryptoPP::ECIES<CryptoPP::ECP>::Decryptor& _decryptor)
{
_decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1Curve);
_decryptor.AccessKey().SetPrivateExponent(secretToExponent(_s));
}
void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> 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<CryptoPP::ECP> 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<CryptoPP::ECP> pub;
pub.AccessGroupParameters().Initialize(pp::secp256k1());
pub.AccessGroupParameters().Initialize(pp::secp256k1Curve);
bytes prefixedKey(pub.GetGroupParameters().GetEncodedElementSize(true));
prefixedKey[0] = 0x04;
@ -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<CryptoPP::ECP> k;
k.AccessGroupParameters().Initialize(secp256k1());
k.AccessGroupParameters().Initialize(pp::secp256k1Curve);
k.SetPrivateExponent(_e);
CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> 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<CryptoPP::ECP> 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<CryptoPP::ECP> const& _k, Secret& _s)
{
_k.GetPrivateExponent().Encode(_s.data(), Secret::size);
pp::exportPublicKey(p, _p);
}

30
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,26 +56,30 @@ 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; }
/// CryptoPP random number pool
static CryptoPP::AutoSeededRandomPool PRNG;
/// Conversion from bytes to cryptopp point
CryptoPP::ECP::Point PointFromPublic(Public const& _p);
/// 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<CryptoPP::ECP, CryptoPP::SHA3_256>::Signer& out_signer);
/// Conversion from cryptopp exponent Integer to bytes
void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s);
/// Initialize verifier
void initializeVerifier(Public const& _p, CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA3_256>::Verifier& _verifier);
/// Conversion from Public key to cryptopp encryptor
void initializeEncryptor(Public const& _p, CryptoPP::ECIES<CryptoPP::ECP>::Encryptor& out_encryptor);
/// Conversion from Secret key to cryptopp decryptor
void initializeDecryptor(Secret const& _s, CryptoPP::ECIES<CryptoPP::ECP>::Decryptor& out_decryptor);
/// Conversion from cryptopp public key to bytes
void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& _p);
void exportPublicKey(CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> const& _k, Public& out_p);
/// Conversion from cryptopp private key to bytes
void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> const& _k, Secret& _s);
void exportPrivateKey(CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> const& _k, Secret& out_s);
}
}

42
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<ECP>::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<CryptoPP::ECP>::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<ECP, SHA3_256>::Signer signer;
pp::initializeSigner(_k, signer);
string sigstr;
StringSource s(_message.toString(), true, new SignerFilter(pp::PRNG, signer, new StringSink(sigstr)));
FixedHash<sizeof(Signature)> 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<ECP, SHA3_256>::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);
}

9
libdevcrypto/EC.h

@ -36,6 +36,15 @@ 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);
}
}

3
libdevcrypto/SHA3MAC.cpp

@ -28,9 +28,10 @@ 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;
if (_secret.size() > 0)
ctx.Update((byte*)_secret.data(), _secret.size());
ctx.Update((byte*)_plain.data(), _plain.size());
assert(_output.size() >= 32);

99
test/crypto.cpp

@ -28,6 +28,7 @@
#include <libethereum/Transaction.h>
#include <boost/test/unit_test.hpp>
#include <libdevcrypto/EC.h>
#include <libdevcrypto/SHA3MAC.h>
#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<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::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<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::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);
string emptystr(""), msgstr("test");
bytesConstRef empty(emptystr), msg(msgstr);
// Test that exported DL_EC private is same as exponent from Secret
CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP> privatek;
privatek.AccessGroupParameters().Initialize(pp::secp256k1());
privatek.SetPrivateExponent(e);
assert(e == privatek.GetPrivateExponent());
// 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<ECP, SHA3_256>::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 exported secret is same as decryptor(privatek) secret
ECIES<ECP>::Decryptor d;
d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1());
d.AccessKey().SetPrivateExponent(e);
assert(d.AccessKey().GetPrivateExponent() == e);
// Test that decryptor->encryptor->public == private->makepublic->public
CryptoPP::DL_PublicKey_EC<CryptoPP::ECP> pubk;
pubk.AccessGroupParameters().Initialize(pp::secp256k1());
privatek.MakePublicKey(pubk);
ECIES<ECP>::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<ECP>::Decryptor d(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Decryptor d(pp::PRNG, pp::secp256k1Curve);
ECIES<ECP>::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<ECP> 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<ECP>::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1());
ECIES<ECP>::Decryptor localDecryptor(pp::PRNG, pp::secp256k1Curve);
SavePrivateKey(localDecryptor.GetPrivateKey());
ECIES<ECP>::Encryptor localEncryptor(localDecryptor);
@ -191,31 +174,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message)
ECIES<ECP>::Decryptor futureDecryptor;
LoadPrivateKey(futureDecryptor.AccessPrivateKey());
futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3);
futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3);
ECIES<ECP>::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);

Loading…
Cancel
Save