/* 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 "CryptoPP.h" #include "ECDHE.h" using namespace std; using namespace dev; using namespace dev::crypto; static Secp256k1 s_secp256k1; void ECDHE::agree(Public const& _remote, Secret& o_sharedSecret) { if (m_remoteEphemeral) // agreement can only occur once BOOST_THROW_EXCEPTION(InvalidState()); m_remoteEphemeral = _remote; s_secp256k1.agree(m_ephemeral.sec(), m_remoteEphemeral, o_sharedSecret); } void ECDHEKeyExchange::agree(Public const& _remoteEphemeral) { s_secp256k1.agree(m_ephemeral.sec(), _remoteEphemeral, m_ephemeralSecret); } void ECDHEKeyExchange::exchange(bytes& o_exchange) { if (!m_ephemeralSecret) // didn't agree on public remote BOOST_THROW_EXCEPTION(InvalidState()); // The key exchange payload is in two parts and is encrypted // using ephemeral keypair. // // The first part is the 'prefix' which is a zero-knowledge proof // allowing the remote to resume or emplace a previous session. // If a session previously exists: // prefix is sha3(token) // todo: ephemeral entropy from both sides // If a session doesn't exist: // prefix is sha3mac(m_ephemeralSecret, // // The second part is encrypted using the public key which relates to the prefix. 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 the previously-known public key. // // Here we should pick an appropriate alias or generate a new one, // but for now, we use static alias passed to constructor. // Public p; s_secp256k1.toPublic(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_ephemeralSecret.ref(), auth.ref()); Signature sig = s_secp256k1.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_ephemeralSecret, 0); h256 prefix(sha3((h256)(m_known.second|m_remoteEphemeral))); aes.update(prefix.ref()); s_secp256k1.encrypt(encpk, exchange); aes.update(&exchange); aes.streamOut(o_exchange); }