From 55561363db6ed37a1d70f6afdb8aae035d13d535 Mon Sep 17 00:00:00 2001 From: subtly Date: Sat, 18 Oct 2014 05:11:36 +0200 Subject: [PATCH] basic ecies class --- libdevcrypto/EC.cpp | 49 ++++++++++++++++++ libdevcrypto/EC.h | 78 ++++++++++++++++++++++++++++ libdevcrypto/ECIES.cpp | 58 +++++++++++++++++++++ libdevcrypto/ECIES.h | 79 +++++++++++++++++++++++++++++ libdevcrypto/SHA3MAC.cpp | 48 ++++++++++++++++++ libdevcrypto/SHA3MAC.h | 38 ++++++++++++++ test/TestHelperCrypto.h | 2 - test/crypto.cpp | 106 ++++++++++++--------------------------- 8 files changed, 381 insertions(+), 77 deletions(-) create mode 100644 libdevcrypto/EC.cpp create mode 100644 libdevcrypto/EC.h create mode 100644 libdevcrypto/ECIES.cpp create mode 100644 libdevcrypto/ECIES.h create mode 100644 libdevcrypto/SHA3MAC.cpp create mode 100644 libdevcrypto/SHA3MAC.h diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp new file mode 100644 index 000000000..519c59305 --- /dev/null +++ b/libdevcrypto/EC.cpp @@ -0,0 +1,49 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file EC.cpp + * @author Alex Leverington + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#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 "EC.H" + +using namespace std; +using namespace dev::crypto; +using namespace CryptoPP; + +ECKeyPair ECKeyPair::create() +{ + ECKeyPair k; + ECIES::Decryptor d(PRNG(), secp256k1()); + k.m_sec = d.GetKey(); + ECIES::Encryptor e(d); + k.m_pub = e.GetKey(); + return k; +} \ No newline at end of file diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h new file mode 100644 index 000000000..2ef9fd1d7 --- /dev/null +++ b/libdevcrypto/EC.h @@ -0,0 +1,78 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file EC.h + * @author Alex Leverington + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#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" +#pragma GCC diagnostic ignored "-Wunused-function" +#include +#include +#include +#include +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +inline CryptoPP::AutoSeededRandomPool& PRNG() +{ + static CryptoPP::AutoSeededRandomPool prng; + return prng; +} + +inline CryptoPP::OID secp256k1() +{ + return CryptoPP::ASN1::secp256k1(); +} + +class ECKeyPair +{ +public: + static ECKeyPair create(); + CryptoPP::DL_PublicKey_EC pub() { return m_pub; } // deprecate + CryptoPP::DL_PrivateKey_EC sec() { return m_sec; } // deprecate + +private: + ECKeyPair() {} + CryptoPP::DL_PublicKey_EC m_pub; + CryptoPP::DL_PrivateKey_EC m_sec; +}; + +//class ECDHE; +//bytes ECSign(KeyPair, bytesConstRef); +//bool ECVerify(Public, bytesConstRef); + +} +} diff --git a/libdevcrypto/ECIES.cpp b/libdevcrypto/ECIES.cpp new file mode 100644 index 000000000..d52dd35fd --- /dev/null +++ b/libdevcrypto/ECIES.cpp @@ -0,0 +1,58 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file ECIES.cpp + * @author Alex Leverington + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#include "EC.h" +#include "ECIES.h" + +using namespace std; +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(bytesRef(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(bytesRef(p).toBytes()); +} + diff --git a/libdevcrypto/ECIES.h b/libdevcrypto/ECIES.h new file mode 100644 index 000000000..a8331f5a8 --- /dev/null +++ b/libdevcrypto/ECIES.h @@ -0,0 +1,79 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file ECIES.h + * @author Alex Leverington + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#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 +#include +#include +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +/** + * @brief ECIES Encryption + */ +class ECIESEncryptor +{ +public: + ECIESEncryptor(ECKeyPair* _k); + + /// Encrypt _message. (object will be resized and replaced with cipher) + void encrypt(bytes& _message); + +private: + CryptoPP::ECIES::Encryptor m_encryptor; +}; + +/** + * @brief ECIES Decryption + */ +class ECIESDecryptor +{ +public: + ECIESDecryptor(ECKeyPair* _k); + + /// Decrypt cipher to plain. + bytes decrypt(bytesConstRef& _c); + +private: + CryptoPP::ECIES::Decryptor m_decryptor; +}; + +} +} \ No newline at end of file diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp new file mode 100644 index 000000000..d50f07e73 --- /dev/null +++ b/libdevcrypto/SHA3MAC.cpp @@ -0,0 +1,48 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file SHA3MAC.cpp + * @author Alex Leverington + * @date 2014 + */ + +#pragma GCC diagnostic ignored "-Wunused-function" +#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 "SHA3MAC.h" + +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output) +{ + CryptoPP::SHA3_256 ctx; + 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/libdevcrypto/SHA3MAC.h b/libdevcrypto/SHA3MAC.h new file mode 100644 index 000000000..4a49f95f1 --- /dev/null +++ b/libdevcrypto/SHA3MAC.h @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . + */ +/** @file SHA3MAC.h + * @author Alex Leverington + * @date 2014 + * + * Ethereum-specific data structures & algorithms. + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace crypto +{ + +void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output); + +} +} + diff --git a/test/TestHelperCrypto.h b/test/TestHelperCrypto.h index 57e4e4201..24104f118 100644 --- a/test/TestHelperCrypto.h +++ b/test/TestHelperCrypto.h @@ -21,8 +21,6 @@ #pragma once -//#include - #pragma warning(push) #pragma warning(disable:4100 4244) #pragma GCC diagnostic push diff --git a/test/crypto.cpp b/test/crypto.cpp index 1c5b9a308..428fcb270 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -27,27 +27,38 @@ #include #include #include +#include +#include #include "TestHelperCrypto.h" using namespace std; using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; -namespace dev -{ -namespace crypto +BOOST_AUTO_TEST_SUITE(devcrypto) + +BOOST_AUTO_TEST_CASE(ecies) { + ECKeyPair k = ECKeyPair::create(); + + string message("Now is the time for all good men to come to the aide of humanity."); + bytes b = bytesConstRef(message).toBytes(); + ECIESEncryptor(&k).encrypt(b); -inline CryptoPP::AutoSeededRandomPool& PRNG() { - static CryptoPP::AutoSeededRandomPool prng; - return prng; -} + bytesConstRef br(&b); + bytes plain = ECIESDecryptor(&k).decrypt(br); + assert(plain == bytesConstRef(message).toBytes()); } -} - -using namespace CryptoPP; -BOOST_AUTO_TEST_SUITE(crypto) +BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) +{ + // New connections require new ECDH keypairs + // Every new connection requires a new EC keypair + // Every new trust requires a new EC keypair + // All connections should share seed for PRF (or PRNG) for nonces +} BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) { @@ -55,9 +66,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) string const message("Now is the time for all good men to come to the aide of humanity."); - AutoSeededRandomPool prng; - - ECIES::Decryptor localDecryptor(prng, ASN1::secp256r1()); + ECIES::Decryptor localDecryptor(crypto::PRNG(), crypto::secp256k1()); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -65,31 +74,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(crypto::PRNG(), 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(crypto::PRNG(), 3); // encrypt/decrypt with local string cipherLocal; - StringSource ss1 (message, true, new PK_EncryptorFilter(prng, localEncryptor, new StringSink(cipherLocal) ) ); + StringSource ss1 (message, true, new PK_EncryptorFilter(crypto::PRNG(), localEncryptor, new StringSink(cipherLocal) ) ); string plainLocal; - StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocal) ) ); + StringSource ss2 (cipherLocal, true, new PK_DecryptorFilter(crypto::PRNG(), localDecryptor, new StringSink(plainLocal) ) ); // encrypt/decrypt with future string cipherFuture; - StringSource ss3 (message, true, new PK_EncryptorFilter(prng, futureEncryptor, new StringSink(cipherFuture) ) ); + StringSource ss3 (message, true, new PK_EncryptorFilter(crypto::PRNG(), futureEncryptor, new StringSink(cipherFuture) ) ); string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFuture) ) ); + StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(crypto::PRNG(), futureDecryptor, new StringSink(plainFuture) ) ); // decrypt local w/future string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(prng, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(crypto::PRNG(), futureDecryptor, new StringSink(plainFutureFromLocal) ) ); // decrypt future w/local string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(prng, localDecryptor, new StringSink(plainLocalFromFuture) ) ); + StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(crypto::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message); @@ -173,60 +182,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); assert(string192 == plainOriginal); } - -BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth) -{ - // ECDH gives 256-bit shared while aes uses 128-bits - // Use first 128-bits of shared secret as symmetric key - // IV is 0 - // New connections require new ECDH keypairs -} - -BOOST_AUTO_TEST_CASE(cryptopp_eth_fbba) -{ - // Initial Authentication: - // - // New/Known Peer: - // pubkeyL = knownR? ? myKnown : myECDH - // pubkeyR = knownR? ? theirKnown : theirECDH - // - // Initial message = hmac(k=sha3(shared-secret[128..255]), address(pubkeyL)) || ECIES encrypt(pubkeyR, pubkeyL) - // - // Key Exchange (this could occur after handshake messages): - // If peers do not know each other they will need to exchange public keys. - // - // Drop ECDH (this could occur after handshake messages): - // After authentication and/or key exchange, both sides generate shared key - // from their 'known' keys and use this to encrypt all future messages. - // - // v2: If one side doesn't trust the other then a single-use key maybe sent. - // This will need to be tracked for future connections; when non-trusting peer - // wants to trust the other, it can request that it's old, 'new', public key be - // accepted. And, if the peer *really* doesn't trust the other side, it can request - // that a new, 'new', public key be accepted. - // - // Handshake (all or nothing, padded): - // All Peers (except blacklisted): - // - // - // New Peer: - // - // - // Known Untrusted Peer: - // - // - // Known Trusted Peer: - // - // - // Blacklisted Peeer: - // Already dropped by now. - // - // - // MAC: - // ... -} - BOOST_AUTO_TEST_CASE(eth_keypairs) { cnote << "Testing Crypto...";