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;
+};
+
+}
+}
+