From 3842c3c9bd4e349ad2bce0efa5672473f80d7ace Mon Sep 17 00:00:00 2001 From: subtly Date: Tue, 11 Nov 2014 18:31:23 +0100 Subject: ecdh, ecdhe, initial aes classes --- TestHelperCrypto.h | 51 ------------------- crypto.cpp | 143 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 89 insertions(+), 105 deletions(-) delete mode 100644 TestHelperCrypto.h diff --git a/TestHelperCrypto.h b/TestHelperCrypto.h deleted file mode 100644 index 01e97c21..00000000 --- a/TestHelperCrypto.h +++ /dev/null @@ -1,51 +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 TestHelperCrypto.h - * @author Alex Leverington - * @date 2014 - */ - -#pragma once - -#include - -using namespace std; -using namespace CryptoPP; - -void SavePrivateKey(const PrivateKey& key, const string& file = "ecies.private.key") -{ - FileSink sink(file.c_str()); - key.Save(sink); -} - -void SavePublicKey(const PublicKey& key, const string& file = "ecies.public.key") -{ - FileSink sink(file.c_str()); - key.Save(sink); -} - -void LoadPrivateKey(PrivateKey& key, const string& file = "ecies.private.key") -{ - FileSource source(file.c_str(), true); - key.Load(source); -} - -void LoadPublicKey(PublicKey& key, const string& file = "ecies.public.key") -{ - FileSource source(file.c_str(), true); - key.Load(source); -} diff --git a/crypto.cpp b/crypto.cpp index 06e55658..a84c1fbb 100644 --- a/crypto.cpp +++ b/crypto.cpp @@ -27,9 +27,10 @@ #include #include #include -#include #include -#include "TestHelperCrypto.h" +#include +#include +#include using namespace std; using namespace dev; @@ -40,7 +41,7 @@ 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."); + string message("Now is the time for all good persons to come to the aid of humanity."); bytes m = asBytes(message); bytesConstRef bcr(&m); @@ -267,7 +268,7 @@ 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 message("Now is the time for all good persons to come to the aid of humanity."); string original = message; bytes b = asBytes(message); @@ -278,61 +279,87 @@ BOOST_AUTO_TEST_CASE(ecies_eckeypair) BOOST_REQUIRE(b == asBytes(original)); } -BOOST_AUTO_TEST_CASE(ecdhe_aes128_ctr_sha3mac) +BOOST_AUTO_TEST_CASE(ecdh) { - // 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 + cnote << "Testing ecdh..."; + + ECDH::Domain dhLocal(pp::secp256k1Curve); + SecByteBlock privLocal(dhLocal.PrivateKeyLength()); + SecByteBlock pubLocal(dhLocal.PublicKeyLength()); + dhLocal.GenerateKeyPair(pp::PRNG, privLocal, pubLocal); + + ECDH::Domain dhRemote(pp::secp256k1Curve); + SecByteBlock privRemote(dhRemote.PrivateKeyLength()); + SecByteBlock pubRemote(dhRemote.PublicKeyLength()); + dhRemote.GenerateKeyPair(pp::PRNG, privRemote, pubRemote); + assert(dhLocal.AgreedValueLength() == dhRemote.AgreedValueLength()); + // local: send public to remote; remote: send public to local + + // Local + SecByteBlock sharedLocal(dhLocal.AgreedValueLength()); + assert(dhLocal.Agree(sharedLocal, privLocal, pubRemote)); + + // 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()); + + assert(ssLocal != 0); + assert(ssLocal == ssRemote); + + + // Now use our keys + KeyPair a = KeyPair::create(); + byte puba[65] = {0x04}; + memcpy(&puba[1], a.pub().data(), 64); + + KeyPair b = KeyPair::create(); + byte pubb[65] = {0x04}; + memcpy(&pubb[1], b.pub().data(), 64); + + ECDH::Domain dhA(pp::secp256k1Curve); + Secret shared; + BOOST_REQUIRE(dhA.Agree(shared.data(), a.sec().data(), pubb)); + BOOST_REQUIRE(shared); } -BOOST_AUTO_TEST_CASE(cryptopp_ecies_message) +BOOST_AUTO_TEST_CASE(ecdhe) { - cnote << "Testing 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::secp256k1Curve); - SavePrivateKey(localDecryptor.GetPrivateKey()); + cnote << "Testing ecdhe..."; - ECIES::Encryptor localEncryptor(localDecryptor); - SavePublicKey(localEncryptor.GetPublicKey()); - - ECIES::Decryptor futureDecryptor; - LoadPrivateKey(futureDecryptor.AccessPrivateKey()); - futureDecryptor.GetPrivateKey().ThrowIfInvalid(pp::PRNG, 3); + ECDHE a, b; + BOOST_CHECK_NE(a.pubkey(), b.pubkey()); - ECIES::Encryptor futureEncryptor; - LoadPublicKey(futureEncryptor.AccessPublicKey()); - 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) ) ); - string 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) ) ); - string plainFuture; - StringSource ss4 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFuture) ) ); + ECDHE local; + ECDHE remote; - // decrypt local w/future - string plainFutureFromLocal; - StringSource ss5 (cipherLocal, true, new PK_DecryptorFilter(pp::PRNG, futureDecryptor, new StringSink(plainFutureFromLocal) ) ); + // local tx pubkey -> remote + Secret sremote; + remote.agree(local.pubkey(), sremote); - // decrypt future w/local - string plainLocalFromFuture; - StringSource ss6 (cipherFuture, true, new PK_DecryptorFilter(pp::PRNG, localDecryptor, new StringSink(plainLocalFromFuture) ) ); + // remote tx pbukey -> local + Secret slocal; + local.agree(remote.pubkey(), slocal); + + BOOST_REQUIRE(sremote); + BOOST_REQUIRE(slocal); + BOOST_REQUIRE_EQUAL(sremote, slocal); +} + +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_REQUIRE(plainLocal == message); - BOOST_REQUIRE(plainFuture == plainLocal); - BOOST_REQUIRE(plainFutureFromLocal == plainLocal); - BOOST_REQUIRE(plainLocalFromFuture == plainLocal); } BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) @@ -346,21 +373,29 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) rng.GenerateBlock(key, key.size()); // cryptopp uses IV as nonce/counter which is same as using nonce w/0 ctr - byte ctr[AES::BLOCKSIZE]; - rng.GenerateBlock(ctr, sizeof(ctr)); + FixedHash ctr; + rng.GenerateBlock(ctr.data(), sizeof(ctr)); + + // used for decrypt + FixedHash ctrcopy(ctr); - string text = "Now is the time for all good persons to come to the aide of humanity."; - // c++11 ftw + string text = "Now is the time for all good persons to come to the aid of humanity."; unsigned char const* in = (unsigned char*)&text[0]; unsigned char* out = (unsigned char*)&text[0]; string original = text; + string doublespeak = text + text; string cipherCopy; try { CTR_Mode::Encryption e; - e.SetKeyWithIV(key, key.size(), ctr); + e.SetKeyWithIV(key, key.size(), ctr.data()); + + // 68 % 255 should be difference of counter e.ProcessData(out, in, text.size()); + + (u128)ctr += (u128)(text.size() % 16); + BOOST_REQUIRE(text != original); cipherCopy = text; } @@ -372,7 +407,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) try { CTR_Mode< AES >::Decryption d; - d.SetKeyWithIV(key, key.size(), ctr); + d.SetKeyWithIV(key, key.size(), ctrcopy.data()); d.ProcessData(out, in, text.size()); BOOST_REQUIRE(text == original); } @@ -390,7 +425,7 @@ BOOST_AUTO_TEST_CASE(cryptopp_aes128_ctr) out = (unsigned char*)&cipherCopy[0]; CTR_Mode::Encryption e; - e.SetKeyWithIV(key, key.size(), ctr); + e.SetKeyWithIV(key, key.size(), ctrcopy.data()); e.ProcessData(out, in, text.size()); // yep, ctr mode. -- cgit