diff --git a/libdevcrypto/AES.cpp b/libdevcrypto/AES.cpp new file mode 100644 index 000000000..109ba9646 --- /dev/null +++ b/libdevcrypto/AES.cpp @@ -0,0 +1,23 @@ +/* + 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 AES.cpp + * @author Alex Leverington + * @date 2014 + */ + +#include "AES.h" + diff --git a/libdevcrypto/AES.h b/libdevcrypto/AES.h new file mode 100644 index 000000000..95525685b --- /dev/null +++ b/libdevcrypto/AES.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 AES.h + * @author Alex Leverington + * @date 2014 + * + * AES + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace crypto +{ +namespace aes +{ + +using Secret128 = FixedHash<16>; +enum StreamType { Encrypt, Decrypt }; + +/** + * @brief Encrypted stream + */ +class Stream +{ +public: + Stream(StreamType _t, Secret128 _encS, bool _zero = true): m_type(_t), m_zeroInput(_zero), m_encSecret(_encS) {}; + + virtual void update(bytesRef io_bytes) {}; + + /// Move ciphertext to _bytes. + virtual size_t streamOut(bytes& o_bytes) {}; + +private: + StreamType m_type; + bool m_zeroInput; + Secret128 m_encSecret; + bytes m_text; +}; + +/** + * @brief Encrypted stream with inband SHA3 mac at specific interval. + */ +class AuthenticatedStream: public Stream +{ +public: + AuthenticatedStream(StreamType _t, Secret128 _encS, Secret128 _macS, unsigned _interval, bool _zero = true): Stream(_t, _encS, _zero), m_macSecret(_macS) { m_macInterval = _interval; } + + AuthenticatedStream(StreamType _t, Secret const& _s, unsigned _interval, bool _zero = true): Stream(_t, Secret128(_s), _zero), m_macSecret(FixedHash<16>(_s[0]+16)) { m_macInterval = _interval; } + + /// Adjust mac interval. Next mac will be xored with value. + void adjustInterval(unsigned _interval) { m_macInterval = _interval; }; + +private: + std::atomic m_macInterval; + Secret128 m_macSecret; +}; + +} +} +} \ No newline at end of file diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 1b51d5bd5..87859ef9c 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -31,6 +31,7 @@ using namespace CryptoPP; void pp::exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& _p) { bytes prefixedKey(_k.GetGroupParameters().GetEncodedElementSize(true)); + secp256k1Params.GetCurve().EncodePoint(prefixedKey.data(), _k.GetPublicElement(), false); assert(Public::size + 1 == _k.GetGroupParameters().GetEncodedElementSize(true)); @@ -42,4 +43,11 @@ void pp::exponentToPublic(Integer const& _e, Public& _p) CryptoPP::DL_PublicKey_EC pk; pk.Initialize(secp256k1Params, secp256k1Params.ExponentiateBase(_e)); pp::exportPublicKey(pk, _p); -} \ No newline at end of file +} + +void pp::ecdhAgree(Secret _s, Public _r, h256& o_s) +{ + ECDH::Domain d(secp256k1Curve); + assert(d.AgreedValueLength() == sizeof(o_s)); + d.Agree(o_s.data(), _s.data(), _r.data()); +} diff --git a/libdevcrypto/CryptoPP.h b/libdevcrypto/CryptoPP.h index dc5d6a610..daf26bc3f 100644 --- a/libdevcrypto/CryptoPP.h +++ b/libdevcrypto/CryptoPP.h @@ -76,7 +76,9 @@ void exportPublicKey(CryptoPP::DL_PublicKey_EC const& _k, Public& static void exportPrivateKey(CryptoPP::DL_PrivateKey_EC const& _k, Secret& _s) { _k.GetPrivateExponent().Encode(_s.data(), Secret::size); } void exponentToPublic(Integer const& _e, Public& _p); - + +void ecdhAgree(Secret _s, Public _r, h256& o_s); + template void initializeDLScheme(Secret const& _s, T& io_operator) { io_operator.AccessKey().Initialize(pp::secp256k1Params, secretToExponent(_s)); } diff --git a/libdevcrypto/ECDHE.cpp b/libdevcrypto/ECDHE.cpp new file mode 100644 index 000000000..d785f467e --- /dev/null +++ b/libdevcrypto/ECDHE.cpp @@ -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 ECDHE.cpp + * @author Alex Leverington + * @date 2014 + */ + +#include "SHA3.h" +#include "SHA3MAC.h" +#include "CryptoPP.h" +#include "ECDHE.h" + +using namespace std; +using namespace dev; +using namespace dev::crypto; +using namespace dev::crypto::pp; + +void ECDHE::agree(Public _remote) +{ + m_remoteEphemeral = _remote; + ecdhAgree(m_ephemeral.sec(), m_remoteEphemeral, m_sharedSecret); +} + +void ECDHEKeyExchange::exchange(bytes& o_exchange) +{ + if (!m_sharedSecret) + // didn't agree on public remote + BOOST_THROW_EXCEPTION(InvalidState()); + + Public encpk = m_known.first|m_remoteEphemeral; + bytes exchange(encpk.asBytes()); + + // This is the public key which we would like the remote to use, + // which maybe different than previously-known public key. + // Here we would pick an appropriate alias or generate a new one, + // but for now, we use static alias passed to constructor. + // + Public p; + pp::exponentToPublic(pp::secretToExponent(m_alias.m_secret), p); + exchange.resize(exchange.size() + sizeof(p)); + memcpy(exchange.data() - sizeof(p), p.data(), sizeof(p)); + + // protocol parameters; should be fixed size + bytes v(asBytes("\x80")); + exchange.resize(exchange.size() + v.size()); + memcpy(exchange.data() - v.size(), v.data(), v.size()); + + h256 auth; + sha3mac(m_alias.m_secret.ref(), m_sharedSecret.ref(), auth.ref()); + Signature sig = crypto::sign(m_alias.m_secret, auth); + exchange.resize(exchange.size() + sizeof(sig)); + memcpy(exchange.data() - sizeof(sig), sig.data(), sizeof(sig)); + + aes::AuthenticatedStream aes(aes::Encrypt, m_sharedSecret, 0); + h256 prefix(sha3((h256)(m_known.second|m_remoteEphemeral))); + aes.update(prefix.ref()); + + encrypt(encpk, exchange); + aes.update(&exchange); + + aes.streamOut(o_exchange); +} + + + diff --git a/libdevcrypto/ECDHE.h b/libdevcrypto/ECDHE.h new file mode 100644 index 000000000..11a5afa5c --- /dev/null +++ b/libdevcrypto/ECDHE.h @@ -0,0 +1,102 @@ +/* + 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 ECDHE.h + * @author Alex Leverington + * @date 2014 + * + * Elliptic curve Diffie-Hellman ephemeral key exchange + */ + +#pragma once + +#include "AES.h" +#include "EC.h" + +namespace dev +{ +namespace crypto +{ + +typedef std::pair AliasSession; + +class Alias +{ + friend class ECDHEKeyExchange; // todo: remove +public: + Alias(Secret _s): m_secret(_s) {}; + + AliasSession session(Address _a) { return m_sessions.count(_a) ? AliasSession() : m_sessions.find(_a)->second; } + +private: + std::map m_sessions; + Secret m_secret; +}; + +/** + * @brief Derive DH shared secret from EC keypairs. + */ +class ECDHE +{ +public: + /// Constructor (pass public key for ingress exchange). + ECDHE(): m_ephemeral(KeyPair::create()) {}; + + /// Public key sent to remote. + Public pubkey() { return m_ephemeral.pub(); } + + /// Provide public key for dh agreement to generated shared secret. + void agree(Public _remoteEphemeral); + +protected: + KeyPair m_ephemeral; ///< Ephemeral keypair; generated. + Public m_remoteEphemeral; ///< Public key of remote; parameter. + Secret m_sharedSecret; ///< Derived secret; derived by agree. +}; + +/** + * @brief Secure exchange of static keys. + * Key exchange is encrypted with public key of remote and then encrypted by block cipher. For a blind remote the ecdhe public key is used to encrypt exchange, and for a known remote the known public key is used. The block cipher key is derived from ecdhe shared secret. + * + * Usage: Agree -> Exchange -> Authenticate + */ +class ECDHEKeyExchange: public ECDHE +{ +public: + /// Exchange with unknown remote (pass public key for ingress exchange) + ECDHEKeyExchange(Alias& _k): m_alias(_k) {}; + + /// Exchange with known remote + ECDHEKeyExchange(Alias& _k, AliasSession _known): m_alias(_k), m_known(_known) {}; + + /// @returns encrypted payload of key exchange + void exchange(bytes& o_exchange); + + /// Decrypt payload, check mac, check trust, decrypt exchange, authenticate exchange, verify version, verify signature, and if no failure occurs, update or creats trust and derive session-shared-secret. + bool authenticate(bytes _exchangeIn); + +private: + Alias m_alias; + AliasSession m_known; + Secret m_sharedAliasSecret; + + FixedHash<16> m_sharedC; + FixedHash<16> m_sharedM; +}; + +} +} +