diff --git a/CodingStandards.txt b/CodingStandards.txt index e1313e2fd..672a20958 100644 --- a/CodingStandards.txt +++ b/CodingStandards.txt @@ -72,8 +72,8 @@ All other entities' first alpha is lower case. 4. Variable prefixes: a. Leading underscore "_" to parameter names (both normal and template). -- Exception: "o_parameterName" when it is used exclusively for output. See 7(f). -- Exception: "io_parameterName" when it is used for both input and output. See 7(f). +- Exception: "o_parameterName" when it is used exclusively for output. See 6(f). +- Exception: "io_parameterName" when it is used for both input and output. See 6(f). b. Leading "c_" to const variables (unless part of an external API). c. Leading "g_" to global (non-const) variables. d. Leading "s_" to static (non-const, non-global) variables. diff --git a/libdevcrypto/Common.cpp b/libdevcrypto/Common.cpp index 482a63cfc..6d57bf2b2 100644 --- a/libdevcrypto/Common.cpp +++ b/libdevcrypto/Common.cpp @@ -22,6 +22,7 @@ #include "Common.h" #include #include +#include "EC.h" #include "SHA3.h" using namespace std; using namespace dev; @@ -108,16 +109,20 @@ KeyPair KeyPair::fromEncryptedSeed(bytesConstRef _seed, std::string const& _pass return KeyPair(sha3(aesDecrypt(_seed, _password))); } -void dev::encrypt(Public _k, bytesConstRef _plain, bytes& _cipher) +void dev::encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher) { - (void)_k; - _cipher = _plain.toBytes(); + bytes io = _plain.toBytes(); + crypto::encrypt(_k, io); + o_cipher = std::move(io); } -bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& _plain) +bool dev::decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plaintext) { - (void)_k; - _plain = _cipher.toBytes(); + bytes io = _cipher.toBytes(); + crypto::decrypt(_k, io); + if (io.empty()) + return false; + o_plaintext = std::move(io); return true; } diff --git a/libdevcrypto/Common.h b/libdevcrypto/Common.h index 9d642201a..7f2a8192e 100644 --- a/libdevcrypto/Common.h +++ b/libdevcrypto/Common.h @@ -57,9 +57,16 @@ using Secrets = h256s; /// @returns 0 if it's not a valid secret key. Address toAddress(Secret _secret); +/// Encrypts plain text using Public key. void encrypt(Public _k, bytesConstRef _plain, bytes& o_cipher); -bool decrypt(Secret _k, bytesConstRef _cipher, bytes& o_plain); + +/// 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); + +/// Returns siganture of message hash. Signature sign(Secret _k, h256 _message); /// Simple class that represents a "key pair". diff --git a/libdevcrypto/CryptoHeaders.h b/libdevcrypto/CryptoHeaders.h deleted file mode 100644 index 333c03a2f..000000000 --- a/libdevcrypto/CryptoHeaders.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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 CryptoHeaders.h - * @author Tim Hughes - * @date 2014 - */ -#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 -#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 -#include -#include -#include -#include -#pragma warning(pop) -#pragma GCC diagnostic pop diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp new file mode 100644 index 000000000..cabcfd45a --- /dev/null +++ b/libdevcrypto/CryptoPP.cpp @@ -0,0 +1,74 @@ +/* + 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 CryptoPP.cpp + * @author Alex Leverington + * @date 2014 + */ + +#include "CryptoPP.h" + +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +ECP::Point pp::PointFromPublic(Public const& _p) +{ + ECP::Point p; + CryptoPP::DL_PublicKey_EC pub; + pub.AccessGroupParameters().Initialize(pp::secp256k1()); + + 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); +} + +Integer pp::ExponentFromSecret(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) +{ + CryptoPP::DL_PrivateKey_EC k; + k.AccessGroupParameters().Initialize(secp256k1()); + k.SetPrivateExponent(_e); + + CryptoPP::DL_PublicKey_EC p; + p.AccessGroupParameters().Initialize(secp256k1()); + 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); +} diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h new file mode 100644 index 000000000..d7e4181ee --- /dev/null +++ b/libdevcrypto/CryptoPP.h @@ -0,0 +1,85 @@ +/* + 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 CryptoPP.h + * @author Alex Leverington + * @date 2014 + * + * CryptoPP headers and helper methods + */ + +#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 +#pragma GCC diagnostic ignored "-Wunused-function" +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) +#pragma GCC diagnostic pop +#include "Common.h" + +namespace dev +{ +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); + +/// Conversion from bytes to cryptopp exponent +CryptoPP::Integer ExponentFromSecret(Secret const& _s); + +/// Conversion from cryptopp exponent Integer to bytes +void PublicFromExponent(CryptoPP::Integer const& _k, Public& _s); + +/// Conversion from cryptopp public key to bytes +void PublicFromDL_PublicKey_EC(CryptoPP::DL_PublicKey_EC const& _k, Public& _p); + +/// Conversion from cryptopp private key to bytes +void SecretFromDL_PrivateKey_EC(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s); + +} +} +} + diff --git a/libdevcrypto/EC.cpp b/libdevcrypto/EC.cpp new file mode 100644 index 000000000..b38703ac3 --- /dev/null +++ b/libdevcrypto/EC.cpp @@ -0,0 +1,73 @@ +/* + 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 + * + * Shared EC classes and functions. + */ + +#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 "CryptoPP.h" +#include "SHA3.h" +#include "EC.h" + +// CryptoPP and dev conflict so dev and pp namespace are used explicitly +using namespace std; +using namespace dev; +using namespace dev::crypto; +using namespace CryptoPP; + +void dev::crypto::encrypt(Public const& _key, bytes& io_cipher) +{ + ECIES::Encryptor e; + e.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); + e.AccessKey().SetPublicElement(pp::PointFromPublic(_key)); + 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()); + bzero(io_cipher.data(), io_cipher.size()); + io_cipher = std::move(c); +} + +void dev::crypto::decrypt(Secret const& _k, bytes& io_text) +{ + CryptoPP::ECIES::Decryptor d; + d.AccessKey().AccessGroupParameters().Initialize(pp::secp256k1()); + d.AccessKey().SetPrivateExponent(pp::ExponentFromSecret(_k)); + 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()); + assert(r.messageLength); + io_text.resize(r.messageLength); + io_text = std::move(p); +} + diff --git a/libdevcrypto/EC.h b/libdevcrypto/EC.h new file mode 100644 index 000000000..cf6714faf --- /dev/null +++ b/libdevcrypto/EC.h @@ -0,0 +1,41 @@ +/* + 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 + * + * Shared EC classes and functions. + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace crypto +{ + +/// Encrypts text (in place). +void encrypt(Public const& _k, bytes& io_cipher); + +/// Decrypts text (in place). +void decrypt(Secret const& _k, bytes& io_text); + +} +} + diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index d72f5bbd4..b3a6e5955 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -20,7 +20,7 @@ */ #include "SHA3.h" -#include "CryptoHeaders.h" +#include "CryptoPP.h" using namespace std; using namespace dev; diff --git a/libdevcrypto/SHA3MAC.cpp b/libdevcrypto/SHA3MAC.cpp new file mode 100644 index 000000000..5c74edd7e --- /dev/null +++ b/libdevcrypto/SHA3MAC.cpp @@ -0,0 +1,39 @@ +/* + 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 + * + * SHA3 MAC + */ + +#include "CryptoPP.h" +#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..4b2d06eac --- /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 + * + * SHA3 MAC + */ + +#pragma once + +#include +#include + +namespace dev +{ +namespace crypto +{ + +void sha3mac(bytesConstRef _secret, bytesConstRef _plain, bytesRef _output); + +} +} + diff --git a/libethcore/ProofOfWork.cpp b/libethcore/ProofOfWork.cpp index 7d3916fd3..bfb8942cc 100644 --- a/libethcore/ProofOfWork.cpp +++ b/libethcore/ProofOfWork.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include "ProofOfWork.h" using namespace std; diff --git a/test/TestHelperCrypto.h b/test/TestHelperCrypto.h index cdc22ec31..01e97c21f 100644 --- a/test/TestHelperCrypto.h +++ b/test/TestHelperCrypto.h @@ -21,23 +21,7 @@ #pragma once -//#include - -#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 -#include -#pragma warning(pop) -#pragma GCC diagnostic pop +#include using namespace std; using namespace CryptoPP; diff --git a/test/crypto.cpp b/test/crypto.cpp index e71ee2285..0d3b6202f 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -27,37 +27,163 @@ #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(common_encrypt_decrypt) { + string message("Now is the time for all good persons to come to the aide of humanity."); + bytes m = asBytes(message); + bytesConstRef bcr(&m); + + KeyPair k = KeyPair::create(); + bytes cipher; + encrypt(k.pub(), bcr, cipher); + assert(cipher != asBytes(message) && cipher.size() > 0); + + bytes plain; + decrypt(k.sec(), bytesConstRef(&cipher), plain); + + assert(asString(plain) == message); + assert(plain == asBytes(message)); +} -inline CryptoPP::AutoSeededRandomPool& PRNG() { - static CryptoPP::AutoSeededRandomPool prng; - return prng; +BOOST_AUTO_TEST_CASE(cryptopp_vs_secp256k1) +{ + ECIES::Decryptor d(pp::PRNG(), pp::secp256k1()); + ECIES::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + + Public p; + pp::PublicFromDL_PublicKey_EC(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::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + assert(s != previous); + + Public p; + pp::PublicFromDL_PublicKey_EC(e.GetKey(), p); + + assert(dev::toAddress(s) == right160(dev::sha3(p.ref()))); + } } + +BOOST_AUTO_TEST_CASE(cryptopp_keys_cryptor_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()); + // 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); + + // 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::Encryptor e(d.GetKey()); + + Secret s; + pp::SecretFromDL_PrivateKey_EC(d.GetKey(), s); + Public p; + pp::PublicFromDL_PublicKey_EC(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); } -using namespace CryptoPP; +BOOST_AUTO_TEST_CASE(ecies_eckeypair) +{ + KeyPair k = KeyPair::create(); + + string message("Now is the time for all good persons to come to the aide of humanity."); + string original = message; + + bytes b = asBytes(message); + encrypt(k.pub(), b); + assert(b != asBytes(original)); -BOOST_AUTO_TEST_SUITE(crypto) + decrypt(k.sec(), b); + assert(b == asBytes(original)); +} + +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) { 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."); - AutoSeededRandomPool prng; - - ECIES::Decryptor localDecryptor(prng, ASN1::secp256r1()); + ECIES::Decryptor localDecryptor(pp::PRNG(), pp::secp256k1()); SavePrivateKey(localDecryptor.GetPrivateKey()); ECIES::Encryptor localEncryptor(localDecryptor); @@ -65,31 +191,31 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) ECIES::Decryptor futureDecryptor; LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(prng, 3); + futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG(), 3); ECIES::Encryptor futureEncryptor; LoadPublicKey(futureEncryptor.AccessPublicKey()); - futureEncryptor.GetPublicKey().ThrowIfInvalid(prng, 3); + futureEncryptor.GetPublicKey().ThrowIfInvalid(pp::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(pp::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(pp::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(pp::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(pp::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(pp::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(pp::PRNG(), localDecryptor, new StringSink(plainLocalFromFuture) ) ); assert(plainLocal == message); @@ -98,98 +224,112 @@ BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) assert(plainLocalFromFuture == plainLocal); } -BOOST_AUTO_TEST_CASE(cryptopp_ecdh_prime) +BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) { - cnote << "Testing cryptopp_ecdh_prime..."; + const int aesKeyLen = 16; + assert(sizeof(char) == sizeof(byte)); - using namespace CryptoPP; - OID curve = ASN1::secp256r1(); - - ECDH::Domain dhLocal(curve); - SecByteBlock privLocal(dhLocal.PrivateKeyLength()); - SecByteBlock pubLocal(dhLocal.PublicKeyLength()); - dhLocal.GenerateKeyPair(dev::crypto::PRNG(), privLocal, pubLocal); + // generate test key + AutoSeededRandomPool rng; + SecByteBlock key(0x00, aesKeyLen); + rng.GenerateBlock(key, key.size()); - ECDH::Domain dhRemote(curve); - SecByteBlock privRemote(dhRemote.PrivateKeyLength()); - SecByteBlock pubRemote(dhRemote.PublicKeyLength()); - dhRemote.GenerateKeyPair(dev::crypto::PRNG(), privRemote, pubRemote); + // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr + byte ctr[AES::BLOCKSIZE]; + rng.GenerateBlock(ctr, sizeof(ctr)); - assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); + 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]; + string original = text; - // local: send public to remote; remote: send public to local + string cipherCopy; + try + { + CTR_Mode::Encryption e; + e.SetKeyWithIV(key, key.size(), ctr); + e.ProcessData(out, in, text.size()); + assert(text != original); + cipherCopy = text; + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - // Local - SecByteBlock sharedLocal(dhLocal.AgreedValueLength()); - assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote)); + try + { + CTR_Mode< AES >::Decryption d; + d.SetKeyWithIV(key, key.size(), ctr); + d.ProcessData(out, in, text.size()); + assert(text == original); + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - // Remote - SecByteBlock sharedRemote(dhRemote.AgreedValueLength()); - assert(dhRemote.Agree(sharedRemote, privRemote, pubLocal)); - // Test - Integer ssLocal, ssRemote; - ssLocal.Decode(sharedLocal.BytePtr(), sharedLocal.SizeInBytes()); - ssRemote.Decode(sharedRemote.BytePtr(), sharedRemote.SizeInBytes()); + // reencrypt ciphertext... + try + { + assert(cipherCopy != text); + in = (unsigned char*)&cipherCopy[0]; + out = (unsigned char*)&cipherCopy[0]; + + CTR_Mode::Encryption e; + e.SetKeyWithIV(key, key.size(), ctr); + e.ProcessData(out, in, text.size()); + + // yep, ctr mode. + assert(cipherCopy == original); + } + catch(CryptoPP::Exception& e) + { + cerr << e.what() << endl; + } - assert(ssLocal != 0); - assert(ssLocal == ssRemote); } -BOOST_AUTO_TEST_CASE(cryptopp_ecdh_aes128_cbc_noauth) +BOOST_AUTO_TEST_CASE(cryptopp_aes128_cbc) { - // 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 + const int aesKeyLen = 16; + assert(sizeof(char) == sizeof(byte)); + AutoSeededRandomPool rng; + SecByteBlock key(0x00, aesKeyLen); + rng.GenerateBlock(key, key.size()); -} + // Generate random IV + byte iv[AES::BLOCKSIZE]; + rng.GenerateBlock(iv, AES::BLOCKSIZE); -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: - // ... -} + string string128("AAAAAAAAAAAAAAAA"); + string plainOriginal = string128; + CryptoPP::CBC_Mode::Encryption cbcEncryption(key, key.size(), iv); + cbcEncryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); + assert(string128 != plainOriginal); + + CBC_Mode::Decryption cbcDecryption(key, key.size(), iv); + cbcDecryption.ProcessData((byte*)&string128[0], (byte*)&string128[0], string128.size()); + assert(plainOriginal == string128); + + + // plaintext whose size isn't divisible by block size must use stream filter for padding + string string192("AAAAAAAAAAAAAAAABBBBBBBB"); + plainOriginal = string192; + + string cipher; + StreamTransformationFilter* aesStream = new StreamTransformationFilter(cbcEncryption, new StringSink(cipher)); + StringSource source(string192, true, aesStream); + assert(cipher.size() == 32); + + cbcDecryption.ProcessData((byte*)&cipher[0], (byte*)&string192[0], cipher.size()); + assert(string192 == plainOriginal); +} + BOOST_AUTO_TEST_CASE(eth_keypairs) { cnote << "Testing Crypto...";