diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp index 8e9266a31..26327f271 100644 --- a/libdevcrypto/EC.cpp +++ b/libdevcrypto/EC.cpp @@ -32,19 +32,74 @@ #include #pragma warning(pop) #pragma GCC diagnostic pop +#include "SHA3.h" #include "EC.h" +// CryptoPP and dev conflict so dev and pp namespace are used explicitly using namespace std; using namespace dev::crypto; using namespace CryptoPP; +dev::Public pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k) { + Public p; + ECP::Point q(_k.GetPublicElement()); + q.x.Encode(&p.data()[0], 32); + q.y.Encode(&p.data()[32], 32); + return p; +} + +pp::ECKeyPair::ECKeyPair(): + m_decryptor(pp::PRNG(), pp::secp256k1()) +{ +} + ECKeyPair ECKeyPair::create() { ECKeyPair k; - ECIES::Decryptor d(PRNG(), secp256k1()); - k.m_sec = d.GetKey(); - ECIES::Encryptor e(d); - k.m_pub = e.GetKey(); + + // export public key and set address + ECIES::Encryptor e(k.m_decryptor.GetKey()); + k.m_public = pp::exportPublicKey(e.GetKey()); + k.m_address = dev::right160(dev::sha3(k.m_public.ref())); + return k; } +void ECKeyPair::encrypt(bytes& _text) +{ + ECIES::Encryptor e(m_decryptor); + std::string c; + StringSource ss(_text.data(), _text.size(), true, new PK_EncryptorFilter(pp::PRNG(), e, new StringSink(c))); + bzero(_text.data(), _text.size() * sizeof(byte)); + _text = std::move(asBytes(c)); +} + +void ECKeyPair::encrypt(bytes& _plain, Public _key) +{ + const char* xbytes = (char*)&_key[0]; + Integer x(xbytes); + + const char* ybytes = (char*)&_key[32]; + Integer y(ybytes); + + DL_PublicKey_EC p; + p.Initialize(pp::secp256k1(), ECP::Point(x,y)); + + ECIES::Encryptor e(p); + // todo: determine size and use _plain as input and output. + std::string c; + StringSource ss(_plain.data(), _plain.size(), true, new PK_EncryptorFilter(pp::PRNG(), e, new StringSink(c))); + bzero(_plain.data(), _plain.size() * sizeof(byte)); + _plain = std::move(asBytes(c)); +} + +dev::bytes ECKeyPair::decrypt(bytesConstRef _c) +{ + std::string p; + StringSource ss(_c.data(), _c.size(), true, new PK_DecryptorFilter(pp::PRNG(), m_decryptor, new StringSink(p))); + return std::move(asBytes(p)); +} + + + + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h index a8c8d1ad6..8f7637c48 100644 --- a/libdevcrypto/EC.h +++ b/libdevcrypto/EC.h @@ -31,34 +31,86 @@ namespace dev namespace crypto { -using PublicTrustNonce = h256; -typedef std::pair PublicTrust; - +namespace pp +// cryptopp wrappers +{ +/// RNG used by CryptoPP inline CryptoPP::AutoSeededRandomPool& PRNG() { static CryptoPP::AutoSeededRandomPool prng; return prng; } -inline CryptoPP::OID secp256k1() { return CryptoPP::ASN1::secp256k1(); } - +/// EC curve used by CryptoPP +inline CryptoPP::OID const& secp256k1() { static CryptoPP::OID curve = CryptoPP::ASN1::secp256k1(); return curve; } + +Public exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k); + +/** + * @brief CryptoPP-specific EC keypair + */ class ECKeyPair +{ +public: + /// Create a new, randomly generated keypair. + Address const& address() const { return m_address; } + + Public const& publicKey() const { return m_public; } + +protected: + ECKeyPair(); + + CryptoPP::ECIES::Decryptor m_decryptor; + + Address m_address; + Public m_public; +}; +} + +/// ECDSA Signature +using Signature = FixedHash<65>; + +/// Secret nonce from trusted key exchange. +using Nonce = h256; + +/// Public key with nonce corresponding to trusted key exchange. +typedef std::pair PublicTrust; + +/** + * @brief EC KeyPair + * @todo remove secret access + * @todo Integrate and/or replace KeyPair, move to common.h + */ +class ECKeyPair: public pp::ECKeyPair { friend class ECDHETKeyExchange; + friend class ECIESEncryptor; + friend class ECIESDecryptor; public: static ECKeyPair create(); - /// deprecate - CryptoPP::DL_PublicKey_EC pub() { return m_pub; } - /// deprecate - CryptoPP::DL_PrivateKey_EC sec() { return m_sec; } - -private: - ECKeyPair() {} - CryptoPP::DL_PublicKey_EC m_pub; - CryptoPP::DL_PrivateKey_EC m_sec; + /// Replaces text with ciphertext. + static void encrypt(bytes& _text, Public _key); + + /// @returns ciphertext. + static bytes encrypt(bytesConstRef _text, Public _key); + + /// Recover public key from signature. + static Public recover(Signature _sig, h256 _messageHash); + /// Sign message. + Signature sign(h256 _messageHash); + + /// Decrypt ciphertext. + bytes decrypt(bytesConstRef _cipher); + + /// Encrypt using our own public key. + void encrypt(bytes& _text); + +private: + ECKeyPair() {}; + std::map m_trustEgress; - std::set m_trustIngress; + std::set m_trustIngress; }; - + } } diff --git a/libdevcrypto/ECIES.cpp b/libdevcrypto/ECIES.cpp index caab00fea..e76be2c2c 100644 --- a/libdevcrypto/ECIES.cpp +++ b/libdevcrypto/ECIES.cpp @@ -29,30 +29,31 @@ using namespace dev; using namespace dev::crypto; using namespace CryptoPP; -ECIESEncryptor::ECIESEncryptor(ECKeyPair* _k) -{ - m_encryptor.AccessKey().AccessGroupParameters().Initialize(secp256k1()); - m_encryptor.AccessKey().SetPublicElement(_k->pub().GetPublicElement()); -} - -void ECIESEncryptor::encrypt(bytes& _message) -{ - std::string c; - StringSource ss(_message.data(), _message.size(), true, new PK_EncryptorFilter(PRNG(), m_encryptor, new StringSink(c))); - bzero(_message.data(), _message.size() * sizeof(byte)); - _message = std::move(bytesConstRef(c).toBytes()); -} - -ECIESDecryptor::ECIESDecryptor(ECKeyPair* _k) -{ - m_decryptor.AccessKey().AccessGroupParameters().Initialize(secp256k1()); - m_decryptor.AccessKey().SetPrivateExponent(_k->sec().GetPrivateExponent()); -} - -bytes ECIESDecryptor::decrypt(bytesConstRef& _c) -{ - std::string p; - StringSource ss(_c.data(), _c.size(), true, new PK_DecryptorFilter(PRNG(), m_decryptor, new StringSink(p))); - return std::move(bytesConstRef(p).toBytes()); -} +//ECIESEncryptor::ECIESEncryptor(ECKeyPair* _k) +//{ +// m_encryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); +// m_encryptor.AccessKey().SetPublicElement(_k->pub().GetPublicElement()); +//} +// +//void ECIESEncryptor::encrypt(bytes& _message) +//{ +// // todo: determine size and use _message as input and output. +// std::string c; +// StringSource ss(_message.data(), _message.size(), true, new PK_EncryptorFilter(pp::PRNG(), m_encryptor, new StringSink(c))); +// bzero(_message.data(), _message.size() * sizeof(byte)); +// _message = std::move(asBytes(c)); +//} +// +//ECIESDecryptor::ECIESDecryptor(ECKeyPair* _k) +//{ +// m_decryptor.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); +// m_decryptor.AccessKey().SetPrivateExponent(_k->sec().GetPrivateExponent()); +//} +// +//bytes ECIESDecryptor::decrypt(bytesConstRef& _c) +//{ +// std::string p; +// StringSource ss(_c.data(), _c.size(), true, new PK_DecryptorFilter(pp::PRNG(), m_decryptor, new StringSink(p))); +// return std::move(asBytes(p)); +//} diff --git a/test/crypto.cpp b/test/crypto.cpp index ba5bbfa4b..48c6fc70c 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -38,22 +38,36 @@ using namespace CryptoPP; BOOST_AUTO_TEST_SUITE(devcrypto) -BOOST_AUTO_TEST_CASE(ecies) +BOOST_AUTO_TEST_CASE(eckeypair_encrypt) { ECKeyPair k = ECKeyPair::create(); - - string message("Now is the time for all good men to come to the aide of humanity."); - bytes b = bytesRef(message).toBytes(); - ECIESEncryptor(&k).encrypt(b); - - bytesConstRef br(&b); - bytes plain = ECIESDecryptor(&k).decrypt(br); - - // ideally, decryptor will go a step further, accept a bytesRef and zero input. - assert(plain != b); + string message("Now is the time for all good persons to come to the aide of humanity."); + string original = message; + + bytes b = asBytes(message); + k.encrypt(b); + assert(b != asBytes(original)); - // plaintext is same as output - assert(plain == bytesConstRef(message).toBytes()); + bytes p = k.decrypt(&b); + assert(p == asBytes(original)); +} + +BOOST_AUTO_TEST_CASE(ecies) +{ +// ECKeyPair k = ECKeyPair::create(); +// +// string message("Now is the time for all good persons to come to the aide of humanity."); +// bytes b = bytesRef(message).toBytes(); +// ECIESEncryptor(&k).encrypt(b); +// +// bytesConstRef br(&b); +// bytes plain = ECIESDecryptor(&k).decrypt(br); +// +// // ideally, decryptor will go a step further, accept a bytesRef and zero input. +// assert(plain != b); +// +// // plaintext is same as output +// assert(plain == bytesConstRef(message).toBytes()); } BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) @@ -73,9 +87,9 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) { cnote << "Testing cryptopp_ecies_message..."; - string const message("Now is the time for all good men to come to the aide of humanity."); + string const message("Now is the time for all good persons to come to the aide of humanity."); - ECIES::Decryptor localDecryptor(crypto::PRNG(), crypto::secp256k1()); + ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -83,31 +97,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(crypto::PRNG(), 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(crypto::PRNG(), 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::PRNG(), 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(crypto::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(crypto::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(crypto::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(crypto::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(crypto::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(crypto::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message); @@ -126,12 +140,12 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecdh_prime) ECDH::Domain dhLocal(curve); SecByteBlock privLocal(dhLocal.PrivateKeyLength()); SecByteBlock pubLocal(dhLocal.PublicKeyLength()); - dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal); + dhLocal.GenerateKeyPair(pp::PRNG(), privLocal, pubLocal); ECDH::Domain dhRemote(curve); SecByteBlock privRemote(dhRemote.PrivateKeyLength()); SecByteBlock pubRemote(dhRemote.PublicKeyLength()); - dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote); + dhRemote.GenerateKeyPair(pp::PRNG(), privRemote, pubRemote); assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); @@ -168,7 +182,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) byte ctr[ AES::BLOCKSIZE ]; rng.GenerateBlock( ctr, sizeof(ctr) ); - string text = "Now is the time for all good men to come to the aide of humanity."; + string text = "Now is the time for all good persons to come to the aide of humanity."; // c++11 ftw unsigned char const* in = (unsigned char*)&text[0]; unsigned char* out = (unsigned char*)&text[0];