From d137581c7ff68ff7d7e43b106de430c001d81e6e Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 5 Mar 2015 03:07:14 +0100 Subject: [PATCH] authenticated capability (hello) and handshake authentication --- libp2p/Host.cpp | 303 +++++---------------------- libp2p/Host.h | 79 +------ libp2p/Peer.h | 3 +- libp2p/RLPxHandshake.cpp | 433 ++++++++++++++++++++++----------------- libp2p/RLPxHandshake.h | 54 +++-- libp2p/Session.cpp | 94 +-------- libp2p/Session.h | 2 +- test/rlpx.cpp | 2 +- 8 files changed, 343 insertions(+), 627 deletions(-) diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index 0062722c6..5fc6ce3b9 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -34,13 +34,12 @@ #include "Common.h" #include "Capability.h" #include "UPnP.h" +#include "RLPxHandshake.h" #include "Host.h" using namespace std; using namespace dev; using namespace dev::p2p; -#include "RLPxHandshake.h" - HostNodeTableHandler::HostNodeTableHandler(Host& _host): m_host(_host) {} void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType const& _e) @@ -157,23 +156,63 @@ unsigned Host::protocolVersion() const return 3; } -void Host::registerPeer(std::shared_ptr _s, CapDescs const& _caps) +bool Host::startPeerSession(Public const& _id, RLP const& _rlp, bi::tcp::socket *_socket) { + /// Get or create Peer + shared_ptr p; + p = m_peers[_id]; + if (!p) + { + p.reset(new Peer()); // this maybe redundant + p->id = _id; + } + p->m_lastDisconnect = NoDisconnect; + if (p->isOffline()) + p->m_lastConnected = std::chrono::system_clock::now(); + p->m_failedAttempts = 0; + // TODO: update pendingconns w/session-weak-ptr for graceful shutdown (otherwise this line isn't safe) + p->endpoint.tcp.address(_socket->remote_endpoint().address()); + + auto protocolVersion = _rlp[1].toInt(); + auto clientVersion = _rlp[2].toString(); + auto caps = _rlp[3].toVector(); + auto listenPort = _rlp[4].toInt(); + + // clang error (previously: ... << hex << caps ...) + // "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments" + stringstream capslog; + for (auto cap: caps) + capslog << "(" << cap.first << "," << dec << cap.second << ")"; + clog(NetMessageSummary) << "Hello: " << clientVersion << "V[" << protocolVersion << "]" << _id.abridged() << showbase << capslog.str() << dec << listenPort; + + // create session so disconnects are managed + auto ps = make_shared(this, move(*_socket), p, PeerSessionInfo({_id, clientVersion, _socket->remote_endpoint().address().to_string(), listenPort, chrono::steady_clock::duration(), _rlp[3].toSet(), 0, map()})); + if (protocolVersion != this->protocolVersion()) + { + ps->disconnect(IncompatibleProtocol); + return false; + } + { - clog(NetNote) << "p2p.host.peer.register" << _s->m_peer->id.abridged(); RecursiveGuard l(x_sessions); - // TODO: temporary loose-coupling; if m_peers already has peer, - // it is same as _s->m_peer. (fixing next PR) - if (!m_peers.count(_s->m_peer->id)) - m_peers[_s->m_peer->id] = _s->m_peer; - m_sessions[_s->m_peer->id] = _s; + if (m_sessions.count(_id) && !!m_sessions[_id].lock()) + { + // Already connected. + clog(NetWarn) << "Session already exists for peer with id" << _id.abridged(); + ps->disconnect(DuplicatePeer); + return false; + } + + clog(NetNote) << "p2p.host.peer.register" << _id.abridged(); + m_sessions[_id] = ps; } + ps->start(); unsigned o = (unsigned)UserPacket; - for (auto const& i: _caps) + for (auto const& i: caps) if (haveCapability(i)) { - _s->m_capabilities[i] = shared_ptr(m_capabilities[i]->newPeerCapability(_s.get(), o)); + ps->m_capabilities[i] = shared_ptr(m_capabilities[i]->newPeerCapability(ps.get(), o)); o += m_capabilities[i]->messageCount(); } } @@ -340,7 +379,7 @@ void Host::runAcceptor() { // doHandshake takes ownersihp of *s via std::move // incoming connection; we don't yet know nodeid - auto handshake = make_shared(this, s); + auto handshake = make_shared(this, s); handshake->start(); success = true; } @@ -374,244 +413,6 @@ void Host::runAcceptor() } } -void PeerHandshake::transition(boost::system::error_code _ech) -{ - if (_ech) - { - boost::system::error_code ec; - socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - if (socket->is_open()) - socket->close(); - return; - } - - auto self(shared_from_this()); - if (nextState == New) - { - nextState = AckAuth; - - clog(NetConnect) << "Authenticating connection for " << socket->remote_endpoint(); - - if (originated) - { - clog(NetConnect) << "devp2p.connect.egress sending auth"; - // egress: tx auth - asserts((bool)remote); - auth.resize(Signature::size + h256::size + Public::size + h256::size + 1); - bytesRef sig(&auth[0], Signature::size); - bytesRef hepubk(&auth[Signature::size], h256::size); - bytesRef pubk(&auth[Signature::size + h256::size], Public::size); - bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); - - // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) - crypto::ecdh::agree(host->m_alias.sec(), remote, ss); - sign(ecdhe.seckey(), ss ^ this->nonce).ref().copyTo(sig); - sha3(ecdhe.pubkey().ref(), hepubk); - host->m_alias.pub().ref().copyTo(pubk); - this->nonce.ref().copyTo(nonce); - auth[auth.size() - 1] = 0x0; - encryptECIES(remote, &auth, authCipher); - - ba::async_write(*socket, ba::buffer(authCipher), [this, self](boost::system::error_code ec, std::size_t) - { - transition(ec); - }); - } - else - { - clog(NetConnect) << "devp2p.connect.ingress recving auth"; - // ingress: rx auth - authCipher.resize(307); - ba::async_read(*socket, ba::buffer(authCipher, 307), [this, self](boost::system::error_code ec, std::size_t) - { - if (ec) - transition(ec); - else - { - if (!decryptECIES(host->m_alias.sec(), bytesConstRef(&authCipher), auth)) - { - clog(NetWarn) << "devp2p.connect.egress recving auth decrypt failed"; - nextState = Error; - transition(); - return; - } - - bytesConstRef sig(&auth[0], Signature::size); - bytesConstRef hepubk(&auth[Signature::size], h256::size); - bytesConstRef pubk(&auth[Signature::size + h256::size], Public::size); - bytesConstRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); - pubk.copyTo(remote.ref()); - nonce.copyTo(remoteNonce.ref()); - - crypto::ecdh::agree(host->m_alias.sec(), remote, ss); - remoteEphemeral = recover(*(Signature*)sig.data(), ss ^ remoteNonce); - assert(sha3(remoteEphemeral) == *(h256*)hepubk.data()); - transition(); - } - }); - } - } - else if (nextState == AckAuth) - { - nextState = Authenticating; - - if (originated) - { - clog(NetConnect) << "devp2p.connect.egress recving ack"; - // egress: rx ack - ackCipher.resize(210); - ba::async_read(*socket, ba::buffer(ackCipher, 210), [this, self](boost::system::error_code ec, std::size_t) - { - if (ec) - transition(ec); - else - { - if (!decryptECIES(host->m_alias.sec(), bytesConstRef(&ackCipher), ack)) - { - clog(NetWarn) << "devp2p.connect.egress recving ack decrypt failed"; - nextState = Error; - transition(); - return; - } - - bytesConstRef(&ack).cropped(0, Public::size).copyTo(remoteEphemeral.ref()); - bytesConstRef(&ack).cropped(Public::size, h256::size).copyTo(remoteNonce.ref()); - transition(); - } - }); - } - else - { - clog(NetConnect) << "devp2p.connect.ingress sending ack"; - // ingress: tx ack - ack.resize(Public::size + h256::size + 1); - bytesRef epubk(&ack[0], Public::size); - bytesRef nonce(&ack[Public::size], h256::size); - ecdhe.pubkey().ref().copyTo(epubk); - this->nonce.ref().copyTo(nonce); - ack[ack.size() - 1] = 0x0; - encryptECIES(remote, &ack, ackCipher); - ba::async_write(*socket, ba::buffer(ackCipher), [this, self](boost::system::error_code ec, std::size_t) - { - transition(ec); - }); - } - } - else if (nextState == Authenticating) - { - if (originated) - clog(NetConnect) << "devp2p.connect.egress sending magic sequence"; - else - clog(NetConnect) << "devp2p.connect.ingress sending magic sequence"; - - PeerSecrets* k = new PeerSecrets; - bytes keyMaterialBytes(512); - bytesRef keyMaterial(&keyMaterialBytes); - - ecdhe.agree(remoteEphemeral, ess); - ess.ref().copyTo(keyMaterial.cropped(0, h256::size)); - ss.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - // auto token = sha3(ssA); - k->encryptK = sha3(keyMaterial); - k->encryptK.ref().copyTo(keyMaterial.cropped(h256::size, h256::size)); - k->macK = sha3(keyMaterial); - - // Initiator egress-mac: sha3(mac-secret^recipient-nonce || auth-sent-init) - // ingress-mac: sha3(mac-secret^initiator-nonce || auth-recvd-ack) - // Recipient egress-mac: sha3(mac-secret^initiator-nonce || auth-sent-ack) - // ingress-mac: sha3(mac-secret^recipient-nonce || auth-recvd-init) - - bytes const& egressCipher = originated ? authCipher : ackCipher; - keyMaterialBytes.resize(h256::size + egressCipher.size()); - keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); - (k->macK ^ remoteNonce).ref().copyTo(keyMaterial); - bytesConstRef(&egressCipher).copyTo(keyMaterial.cropped(h256::size, egressCipher.size())); - k->egressMac = sha3(keyMaterial); - - bytes const& ingressCipher = originated ? ackCipher : authCipher; - keyMaterialBytes.resize(h256::size + ingressCipher.size()); - keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); - (k->macK ^ nonce).ref().copyTo(keyMaterial); - bytesConstRef(&ingressCipher).copyTo(keyMaterial.cropped(h256::size, ingressCipher.size())); - k->ingressMac = sha3(keyMaterial); - - - - - // This test will be replaced with protocol-capabilities information (was Hello packet) - // TESTING: send encrypt magic sequence - bytes magic {0x22,0x40,0x08,0x91}; - - - // rlpx encrypt - encryptSymNoAuth(k->encryptK, &magic, k->magicCipherAndMac, h128()); - k->magicCipherAndMac.resize(k->magicCipherAndMac.size() + 32); - sha3mac(k->egressMac.ref(), &magic, k->egressMac.ref()); - k->egressMac.ref().copyTo(bytesRef(&k->magicCipherAndMac).cropped(k->magicCipherAndMac.size() - 32, 32)); - - - - clog(NetConnect) << "devp2p.connect.egress txrx magic sequence"; - k->recvdMagicCipherAndMac.resize(k->magicCipherAndMac.size()); - - ba::async_write(*socket, ba::buffer(k->magicCipherAndMac), [this, self, k, magic](boost::system::error_code ec, std::size_t) - { - if (ec) - { - delete k; - transition(ec); - return; - } - - ba::async_read(*socket, ba::buffer(k->recvdMagicCipherAndMac, k->magicCipherAndMac.size()), [this, self, k, magic](boost::system::error_code ec, std::size_t) - { - if (originated) - clog(NetNote) << "devp2p.connect.egress recving magic sequence"; - else - clog(NetNote) << "devp2p.connect.ingress recving magic sequence"; - - if (ec) - { - delete k; - transition(ec); - return; - } - - /// capabilities handshake (encrypted magic sequence is placeholder) - bytes decryptedMagic; - decryptSymNoAuth(k->encryptK, h128(), &k->recvdMagicCipherAndMac, decryptedMagic); - if (decryptedMagic[0] == 0x22 && decryptedMagic[1] == 0x40 && decryptedMagic[2] == 0x08 && decryptedMagic[3] == 0x91) - { - shared_ptr p; - p = host->m_peers[remote]; - if (!p) - { - p.reset(new Peer()); - p->id = remote; - } - p->endpoint.tcp.address(socket->remote_endpoint().address()); - p->m_lastDisconnect = NoDisconnect; - p->m_lastConnected = std::chrono::system_clock::now(); - p->m_failedAttempts = 0; - - auto ps = std::make_shared(host, move(*socket), p); - ps->start(); - } - - // todo: PeerSession will take ownership of k and use it to encrypt wireline. - delete k; - }); - }); - } - else - { - clog(NetConnect) << "Disconnecting " << socket->remote_endpoint() << " (Authentication Failed)"; - boost::system::error_code ec; - socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - socket->close(); - } -} - string Host::pocHost() { vector strs; @@ -699,7 +500,7 @@ void Host::connect(std::shared_ptr const& _p) else { clog(NetConnect) << "Connected to" << _p->id.abridged() << "@" << _p->peerEndpoint(); - auto handshake = make_shared(this, s, _p->id); + auto handshake = make_shared(this, s, _p->id); handshake->start(); } Guard l(x_pendingNodeConns); diff --git a/libp2p/Host.h b/libp2p/Host.h index c34ec9f21..1d17d4518 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -77,9 +77,7 @@ private: class Host: public Worker { friend class HostNodeTableHandler; - - friend struct PeerHandshake; - friend struct RLPXHandshake; + friend class RLPXHandshake; friend class Session; friend class HostCapabilityFace; @@ -110,8 +108,6 @@ public: CapDescs caps() const { CapDescs ret; for (auto const& i: m_capabilities) ret.push_back(i.first); return ret; } template std::shared_ptr cap() const { try { return std::static_pointer_cast(m_capabilities.at(std::make_pair(T::staticName(), T::staticVersion()))); } catch (...) { return nullptr; } } - bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } - void addNode(NodeId const& _node, std::string const& _addr, unsigned short _tcpPort, unsigned short _udpPort); /// Set ideal number of peers. @@ -149,7 +145,8 @@ public: NodeId id() const { return m_alias.pub(); } - void registerPeer(std::shared_ptr _s, CapDescs const& _caps); + /// Validates and starts peer session, taking ownership of _socket. Disconnects and returns false upon error. + bool startPeerSession(Public const& _id, RLP const& _hello, bi::tcp::socket *_socket); protected: void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e); @@ -158,6 +155,8 @@ protected: void restoreNetwork(bytesConstRef _b); private: + bool havePeerSession(NodeId _id) { RecursiveGuard l(x_sessions); return m_sessions.count(_id) ? !!m_sessions[_id].lock() : false; } + /// Populate m_peerAddresses with available public addresses. void determinePublic(std::string const& _publicAddress, bool _upnp); @@ -234,73 +233,5 @@ private: bool m_accepting = false; }; -/** - * @brief Key material and derived secrets for TCP peer connection. - */ -struct PeerSecrets -{ - friend struct PeerHandshake; - friend struct RLPXHandshake; - -protected: - Secret encryptK; - Secret macK; - h256 egressMac; - h256 ingressMac; - - bytes magicCipherAndMac; - bytes recvdMagicCipherAndMac; -}; - -struct PeerHandshake: public std::enable_shared_from_this -{ - friend class Host; - enum State - { - Error = -1, - New, // New->AckAuth [egress: tx auth, ingress: rx auth] - AckAuth, // AckAuth->Authenticating [egress: rx ack, ingress: tx ack] - Authenticating, // Authenticating [tx caps, rx caps, authenticate] - }; - - /// Handshake for ingress connection. Takes ownership of socket. - PeerHandshake(Host* _host, bi::tcp::socket* _socket): host(_host), socket(std::move(_socket)), originated(false) { crypto::Nonce::get().ref().copyTo(nonce.ref()); } - - /// Handshake for egress connection to _remote. Takes ownership of socket. - PeerHandshake(Host* _host, bi::tcp::socket* _socket, NodeId _remote): host(_host), socket(std::move(_socket)), originated(true), remote(_remote) { crypto::Nonce::get().ref().copyTo(nonce.ref()); } - - ~PeerHandshake() { delete socket; } - -protected: - void start() { transition(); } - -private: - void transition(boost::system::error_code _ech = boost::system::error_code()); - - /// Current state of handshake. - State nextState = New; - - Host* host; - - /// Node id of remote host for socket. - NodeId remote; - - bi::tcp::socket* socket; - bool originated = false; - - bytes auth; - bytes authCipher; - bytes ack; - bytes ackCipher; - Secret ss; - Secret ess; - - crypto::ECDHE ecdhe; - h256 nonce; - - Public remoteEphemeral; - h256 remoteNonce; -}; - } } diff --git a/libp2p/Peer.h b/libp2p/Peer.h index e9b45845b..743d941db 100644 --- a/libp2p/Peer.h +++ b/libp2p/Peer.h @@ -55,8 +55,7 @@ class Peer: public Node friend class Session; /// Allows Session to update score and rating. friend class Host; /// For Host: saveNetwork(), restoreNetwork() - friend struct PeerHandshake; - friend struct RLPXHandshake; + friend class RLPXHandshake; public: bool isOffline() const { return !m_session.lock(); } diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index 18db43577..77bc64e1b 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -28,7 +28,7 @@ using namespace dev; using namespace dev::p2p; using namespace CryptoPP; -RLPXFrameIO::RLPXFrameIO(RLPXHandshake& _init): m_macEnc() +RLPXFrameIO::RLPXFrameIO(RLPXHandshake const& _init): m_socket(_init.socket) { // we need: // originated? @@ -36,7 +36,7 @@ RLPXFrameIO::RLPXFrameIO(RLPXHandshake& _init): m_macEnc() // authCipher // ackCipher - bytes keyMaterialBytes(512); + bytes keyMaterialBytes(64); bytesRef keyMaterial(&keyMaterialBytes); // shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || initiator-nonce)) @@ -44,23 +44,24 @@ RLPXFrameIO::RLPXFrameIO(RLPXHandshake& _init): m_macEnc() _init.ecdhe.agree(_init.remoteEphemeral, ephemeralShared); ephemeralShared.ref().copyTo(keyMaterial.cropped(0, h256::size)); h512 nonceMaterial; - h256& leftNonce = _init.originated ? _init.remoteNonce : _init.nonce; - h256& rightNonce = _init.originated ? _init.nonce : _init.remoteNonce; + h256 const& leftNonce = _init.originated ? _init.remoteNonce : _init.nonce; + h256 const& rightNonce = _init.originated ? _init.nonce : _init.remoteNonce; leftNonce.ref().copyTo(nonceMaterial.ref().cropped(0, h256::size)); rightNonce.ref().copyTo(nonceMaterial.ref().cropped(h256::size, h256::size)); auto outRef(keyMaterial.cropped(h256::size, h256::size)); sha3(nonceMaterial.ref(), outRef); // output h(nonces) sha3(keyMaterial, outRef); // output shared-secret - // token: sha3(outRef) + // token: sha3(outRef, bytesRef(&token)); -> Host (to be saved to disk) // aes-secret = sha3(ecdhe-shared-secret || shared-secret) sha3(keyMaterial, outRef); // output aes-secret - m_frameEnc.SetKey(outRef.data(), h256::size); + m_frameEnc.SetKeyWithIV(outRef.data(), h128::size, h128().data()); + m_frameDec.SetKeyWithIV(outRef.data(), h128::size, h128().data()); // mac-secret = sha3(ecdhe-shared-secret || aes-secret) sha3(keyMaterial, outRef); // output mac-secret - m_macEnc.SetKey(outRef.data(), h256::size); + m_macEnc.SetKey(outRef.data(), h128::size); // Initiator egress-mac: sha3(mac-secret^recipient-nonce || auth-sent-init) // ingress-mac: sha3(mac-secret^initiator-nonce || auth-recvd-ack) @@ -75,7 +76,7 @@ RLPXFrameIO::RLPXFrameIO(RLPXHandshake& _init): m_macEnc() m_egressMac.Update(keyMaterial.data(), keyMaterial.size()); // recover mac-secret by re-xoring remoteNonce - (*(h256*)outRef.data() ^ _init.remoteNonce ^ _init.nonce).ref().copyTo(keyMaterial); + (*(h256*)keyMaterial.data() ^ _init.remoteNonce ^ _init.nonce).ref().copyTo(keyMaterial); bytes const& ingressCipher = _init.originated ? _init.ackCipher : _init.authCipher; keyMaterialBytes.resize(h256::size + ingressCipher.size()); keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size()); @@ -83,25 +84,60 @@ RLPXFrameIO::RLPXFrameIO(RLPXHandshake& _init): m_macEnc() m_ingressMac.Update(keyMaterial.data(), keyMaterial.size()); } -void RLPXFrameIO::writeFullPacketFrame(bytesConstRef _packet) +void RLPXFrameIO::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes) { + // _packet = type || rlpList() + + // current/old packet format: prep(_s).appendList(_args + 1).append((unsigned)_id); RLPStream header; + header.appendRaw(bytes({byte(_packet.size() >> 16), byte(_packet.size() >> 8), byte(_packet.size())})); + // zeroHeader: []byte{0xC2, 0x80, 0x80}. Should be rlpList(protocolType,seqId,totalPacketSize). + header.appendRaw(bytes({0xc2,0x80,0x80})); -} - -void RLPXFrameIO::writeHeader(bi::tcp::socket* _socket, h128 const& _header) -{ + // TODO: SECURITY check that header is <= 16 bytes + bytes headerWithMac; + header.swapOut(headerWithMac); + headerWithMac.resize(32); + m_frameEnc.ProcessData(headerWithMac.data(), headerWithMac.data(), 16); + updateEgressMACWithHeader(bytesConstRef(&headerWithMac).cropped(0, 16)); + egressDigest().ref().copyTo(bytesRef(&headerWithMac).cropped(h128::size,h128::size)); + + auto padding = (16 - (_packet.size() % 16)) % 16; + o_bytes.swap(headerWithMac); + o_bytes.resize(32 + _packet.size() + padding + h128::size); + bytesRef packetRef(o_bytes.data() + 32, _packet.size()); + m_frameEnc.ProcessData(packetRef.data(), _packet.data(), _packet.size()); + bytesRef paddingRef(o_bytes.data() + 32 + _packet.size(), padding); + if (padding) + m_frameEnc.ProcessData(paddingRef.data(), paddingRef.data(), padding); + bytesRef packetWithPaddingRef(o_bytes.data() + 32, _packet.size() + padding); + updateEgressMACWithEndOfFrame(packetWithPaddingRef); + bytesRef macRef(o_bytes.data() + 32 + _packet.size() + padding, h128::size); + egressDigest().ref().copyTo(macRef); + clog(NetConnect) << "SENT FRAME " << _packet.size() << *(h128*)macRef.data(); + clog(NetConnect) << "FRAME TAIL " << *(h128*)(o_bytes.data() + 32 + _packet.size() + padding); } -void RLPXFrameIO::write(bi::tcp::socket* _socket, bytesConstRef _in, bool _eof) +bool RLPXFrameIO::authAndDecryptHeader(h256& io) { - + updateIngressMACWithHeader(io.ref()); + bytesConstRef macRef = io.ref().cropped(h128::size, h128::size); + if (*(h128*)macRef.data() != ingressDigest()) + return false; + m_frameDec.ProcessData(io.data(), io.data(), 16); + return true; } -bool RLPXFrameIO::read(bytesConstRef _in, bytes& o_out) +bool RLPXFrameIO::authAndDecryptFrame(bytesRef io) { - + bytesRef cipherText(io.cropped(0, io.size() - h128::size)); + updateIngressMACWithEndOfFrame(cipherText); + bytesConstRef frameMac(io.data() + io.size() - h128::size, h128::size); + if (*(h128*)frameMac.data() != ingressDigest()) + return false; + m_frameDec.ProcessData(io.data(), io.data(), io.size() - h128::size); + return true; } h128 RLPXFrameIO::egressDigest() @@ -120,9 +156,8 @@ h128 RLPXFrameIO::ingressDigest() return move(digest); } -void RLPXFrameIO::updateEgressMACWithHeader(h128 const& _headerCipher) +void RLPXFrameIO::updateEgressMACWithHeader(bytesConstRef _headerCipher) { - m_egressMac.Update(_headerCipher.data(), h128::size); updateMAC(m_egressMac, *(h128*)_headerCipher.data()); } @@ -130,11 +165,16 @@ void RLPXFrameIO::updateEgressMACWithEndOfFrame(bytesConstRef _cipher) { m_egressMac.Update(_cipher.data(), _cipher.size()); updateMAC(m_egressMac); + { + SHA3_256 prev(m_egressMac); + h128 digest; + prev.TruncatedFinal(digest.data(), h128::size); + clog(NetConnect) << "EGRESS FRAMEMAC " << _cipher.size() << digest; + } } void RLPXFrameIO::updateIngressMACWithHeader(bytesConstRef _headerCipher) { - m_ingressMac.Update(_headerCipher.data(), h128::size); updateMAC(m_ingressMac, *(h128*)_headerCipher.data()); } @@ -142,6 +182,12 @@ void RLPXFrameIO::updateIngressMACWithEndOfFrame(bytesConstRef _cipher) { m_ingressMac.Update(_cipher.data(), _cipher.size()); updateMAC(m_ingressMac); + { + SHA3_256 prev(m_ingressMac); + h128 digest; + prev.TruncatedFinal(digest.data(), h128::size); + clog(NetConnect) << "INGRESS FRAMEMAC " << _cipher.size() << digest; + } } void RLPXFrameIO::updateMAC(SHA3_256& _mac, h128 const& _seed) @@ -155,12 +201,13 @@ void RLPXFrameIO::updateMAC(SHA3_256& _mac, h128 const& _seed) encDigest ^= (!!_seed ? _seed : prevDigestOut); // update mac for final digest - _mac.Update(encDigest.data(), h256::size); + _mac.Update(encDigest.data(), h128::size); } -void RLPXHandshake::generateAuth() +void RLPXHandshake::writeAuth() { + clog(NetConnect) << "p2p.connect.egress sending auth to " << socket->remote_endpoint(); auth.resize(Signature::size + h256::size + Public::size + h256::size + 1); bytesRef sig(&auth[0], Signature::size); bytesRef hepubk(&auth[Signature::size], h256::size); @@ -168,211 +215,227 @@ void RLPXHandshake::generateAuth() bytesRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); // E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0) -//crypto::ecdh::agree(host->m_alias.sec(), remote, ss); -//sign(ecdhe.seckey(), ss ^ this->nonce).ref().copyTo(sig); + Secret staticShared; + crypto::ecdh::agree(host->m_alias.sec(), remote, staticShared); + sign(ecdhe.seckey(), staticShared ^ this->nonce).ref().copyTo(sig); sha3(ecdhe.pubkey().ref(), hepubk); host->m_alias.pub().ref().copyTo(pubk); this->nonce.ref().copyTo(nonce); auth[auth.size() - 1] = 0x0; encryptECIES(remote, &auth, authCipher); + + auto self(shared_from_this()); + ba::async_write(*socket, ba::buffer(authCipher), [this, self](boost::system::error_code ec, std::size_t) + { + transition(ec); + }); } -void RLPXHandshake::generateAck() +void RLPXHandshake::writeAck() { + clog(NetConnect) << "p2p.connect.ingress sending ack to " << socket->remote_endpoint(); + ack.resize(Public::size + h256::size + 1); + bytesRef epubk(&ack[0], Public::size); + bytesRef nonce(&ack[Public::size], h256::size); + ecdhe.pubkey().ref().copyTo(epubk); + this->nonce.ref().copyTo(nonce); + ack[ack.size() - 1] = 0x0; + encryptECIES(remote, &ack, ackCipher); + auto self(shared_from_this()); + ba::async_write(*socket, ba::buffer(ackCipher), [this, self](boost::system::error_code ec, std::size_t) + { + transition(ec); + }); } -bool RLPXHandshake::decodeAuth() +void RLPXHandshake::readAuth() { - if (!decryptECIES(host->m_alias.sec(), bytesConstRef(&authCipher), auth)) - return false; - - bytesConstRef sig(&auth[0], Signature::size); - bytesConstRef hepubk(&auth[Signature::size], h256::size); - bytesConstRef pubk(&auth[Signature::size + h256::size], Public::size); - bytesConstRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); - pubk.copyTo(remote.ref()); - nonce.copyTo(remoteNonce.ref()); - -//crypto::ecdh::agree(host->m_alias.sec(), remote, ss); -//remoteEphemeral = recover(*(Signature*)sig.data(), ss ^ remoteNonce); - assert(sha3(remoteEphemeral) == *(h256*)hepubk.data()); - return true; + clog(NetConnect) << "p2p.connect.ingress recving auth from " << socket->remote_endpoint(); + authCipher.resize(307); + auto self(shared_from_this()); + ba::async_read(*socket, ba::buffer(authCipher, 307), [this, self](boost::system::error_code ec, std::size_t) + { + if (ec) + transition(ec); + else if (decryptECIES(host->m_alias.sec(), bytesConstRef(&authCipher), auth)) + { + bytesConstRef sig(&auth[0], Signature::size); + bytesConstRef hepubk(&auth[Signature::size], h256::size); + bytesConstRef pubk(&auth[Signature::size + h256::size], Public::size); + bytesConstRef nonce(&auth[Signature::size + h256::size + Public::size], h256::size); + pubk.copyTo(remote.ref()); + nonce.copyTo(remoteNonce.ref()); + + Secret sharedSecret; + crypto::ecdh::agree(host->m_alias.sec(), remote, sharedSecret); + remoteEphemeral = recover(*(Signature*)sig.data(), sharedSecret ^ remoteNonce); + assert(sha3(remoteEphemeral) == *(h256*)hepubk.data()); + transition(); + } + else + { + clog(NetWarn) << "p2p.connect.egress recving auth decrypt failed for" << socket->remote_endpoint(); + nextState = Error; + transition(); + } + }); } -bool RLPXHandshake::decodeAck() +void RLPXHandshake::readAck() { - + clog(NetConnect) << "p2p.connect.egress recving ack from " << socket->remote_endpoint(); + ackCipher.resize(210); + auto self(shared_from_this()); + ba::async_read(*socket, ba::buffer(ackCipher, 210), [this, self](boost::system::error_code ec, std::size_t) + { + if (ec) + transition(ec); + else if (decryptECIES(host->m_alias.sec(), bytesConstRef(&ackCipher), ack)) + { + bytesConstRef(&ack).cropped(0, Public::size).copyTo(remoteEphemeral.ref()); + bytesConstRef(&ack).cropped(Public::size, h256::size).copyTo(remoteNonce.ref()); + transition(); + } + else + { + clog(NetWarn) << "p2p.connect.egress recving ack decrypt failed for " << socket->remote_endpoint(); + nextState = Error; + transition(); + } + }); } -/// used for protocol handshake -bytes RLPXHandshake::frame(bytesConstRef _packet) +void RLPXHandshake::error() { - + clog(NetConnect) << "Disconnecting " << socket->remote_endpoint() << " (Handshake Failed)"; + boost::system::error_code ec; + socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + if (socket->is_open()) + socket->close(); } void RLPXHandshake::transition(boost::system::error_code _ech) { if (_ech || nextState == Error) - { - clog(NetConnect) << "Disconnecting " << socket->remote_endpoint() << " (Handshake Failed)"; - boost::system::error_code ec; - socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - if (socket->is_open()) - socket->close(); - return; - } + return error(); auto self(shared_from_this()); if (nextState == New) { nextState = AckAuth; - - clog(NetConnect) << "Authenticating connection for " << socket->remote_endpoint(); - if (originated) - { - clog(NetConnect) << "p2p.connect.egress sending auth"; - generateAuth(); - ba::async_write(*socket, ba::buffer(authCipher), [this, self](boost::system::error_code ec, std::size_t) - { - transition(ec); - }); - } + writeAuth(); else - { - clog(NetConnect) << "p2p.connect.ingress recving auth"; - authCipher.resize(321); - ba::async_read(*socket, ba::buffer(authCipher, 321), [this, self](boost::system::error_code ec, std::size_t) - { - if (ec) - transition(ec); - else if (decodeAuth()) - transition(); - else - { - clog(NetWarn) << "p2p.connect.egress recving auth decrypt failed"; - nextState = Error; - transition(); - return; - } - }); - } + readAuth(); } else if (nextState == AckAuth) { - nextState = Authenticating; - + nextState = WriteHello; if (originated) - { - clog(NetConnect) << "p2p.connect.egress recving ack"; - // egress: rx ack - ackCipher.resize(225); - ba::async_read(*socket, ba::buffer(ackCipher, 225), [this, self](boost::system::error_code ec, std::size_t) - { - if (ec) - transition(ec); - else - { - if (!decryptECIES(host->m_alias.sec(), bytesConstRef(&ackCipher), ack)) - { - clog(NetWarn) << "p2p.connect.egress recving ack decrypt failed"; - nextState = Error; - transition(); - return; - } - - bytesConstRef(&ack).cropped(0, Public::size).copyTo(remoteEphemeral.ref()); - bytesConstRef(&ack).cropped(Public::size, h256::size).copyTo(remoteNonce.ref()); - transition(); - } - }); - } + readAck(); else - { - clog(NetConnect) << "p2p.connect.ingress sending ack"; - // ingress: tx ack - ack.resize(Public::size + h256::size + 1); - bytesRef epubk(&ack[0], Public::size); - bytesRef nonce(&ack[Public::size], h256::size); - ecdhe.pubkey().ref().copyTo(epubk); - this->nonce.ref().copyTo(nonce); - ack[ack.size() - 1] = 0x0; - encryptECIES(remote, &ack, ackCipher); - ba::async_write(*socket, ba::buffer(ackCipher), [this, self](boost::system::error_code ec, std::size_t) - { - transition(ec); - }); - } + writeAck(); } - else if (nextState == Authenticating) + else if (nextState == WriteHello) { + nextState = ReadHello; + if (originated) - clog(NetConnect) << "p2p.connect.egress sending magic sequence"; + clog(NetConnect) << "p2p.connect.egress sending capabilities handshake"; else - clog(NetConnect) << "p2p.connect.ingress sending magic sequence"; + clog(NetConnect) << "p2p.connect.ingress sending capabilities handshake"; - RLPXFrameIO* io = new RLPXFrameIO(*this); + io = new RLPXFrameIO(*this); + + // old packet format + // 5 arguments, HelloPacket + RLPStream s; + s.appendList(5 + 1).append((unsigned)0) + << host->protocolVersion() + << host->m_clientVersion + << host->caps() + << host->m_tcpPublic.port() + << host->id(); + bytes packet; + s.swapOut(packet); + io->writeSingleFramePacket(&packet, handshakeOutBuffer); + ba::async_write(*socket, ba::buffer(handshakeOutBuffer), [this, self](boost::system::error_code ec, std::size_t) + { + transition(ec); + }); + } + else if (nextState == ReadHello) + { + // Authenticate and decrypt initial hello frame with initial RLPXFrameIO + // and request host to start session. + nextState = StartSession; -// // This test will be replaced with protocol-capabilities information (was Hello packet) -// // TESTING: send encrypt magic sequence -// bytes magic {0x22,0x40,0x08,0x91}; -// // rlpx encrypt -// encryptSymNoAuth(k->encryptK, &magic, k->magicCipherAndMac, h128()); -// k->magicCipherAndMac.resize(k->magicCipherAndMac.size() + 32); -// sha3mac(k->egressMac.ref(), &magic, k->egressMac.ref()); -// k->egressMac.ref().copyTo(bytesRef(&k->magicCipherAndMac).cropped(k->magicCipherAndMac.size() - 32, 32)); -// -// clog(NetConnect) << "p2p.connect.egress txrx magic sequence"; -// k->recvdMagicCipherAndMac.resize(k->magicCipherAndMac.size()); -// -// ba::async_write(*socket, ba::buffer(k->magicCipherAndMac), [this, self, k, magic](boost::system::error_code ec, std::size_t) -// { -// if (ec) -// { -// delete k; -// transition(ec); -// return; -// } -// -// ba::async_read(*socket, ba::buffer(k->recvdMagicCipherAndMac, k->magicCipherAndMac.size()), [this, self, k, magic](boost::system::error_code ec, std::size_t) -// { -// if (originated) -// clog(NetNote) << "p2p.connect.egress recving magic sequence"; -// else -// clog(NetNote) << "p2p.connect.ingress recving magic sequence"; -// -// if (ec) -// { -// delete k; -// transition(ec); -// return; -// } -// -// /// capabilities handshake (encrypted magic sequence is placeholder) -// bytes decryptedMagic; -// decryptSymNoAuth(k->encryptK, h128(), &k->recvdMagicCipherAndMac, decryptedMagic); -// if (decryptedMagic[0] == 0x22 && decryptedMagic[1] == 0x40 && decryptedMagic[2] == 0x08 && decryptedMagic[3] == 0x91) -// { - shared_ptr p; - p = host->m_peers[remote]; - if (!p) + // read frame header + handshakeInBuffer.resize(h256::size); + ba::async_read(*socket, boost::asio::buffer(handshakeInBuffer, h256::size), [this,self](boost::system::error_code ec, std::size_t length) + { + if (ec) + transition(ec); + else + { + /// authenticate and decrypt header + if (!io->authAndDecryptHeader(*(h256*)handshakeInBuffer.data())) + { + nextState = Error; + transition(); + return; + } + + clog(NetNote) << (originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "recvd hello header"; + + /// check frame size + bytes& header = handshakeInBuffer; + uint32_t frameSize = (uint32_t)(header[2]) | (uint32_t)(header[1])<<8 | (uint32_t)(header[0])<<16; + if (frameSize > 1024) + { + // all future frames: 16777216 + clog(NetWarn) << (originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame is too large"; + nextState = Error; + transition(); + return; + } + + /// rlp of header has protocol-type, sequence-id[, total-packet-size] + bytes headerRLP(header.size() - 3 - h128::size); + bytesConstRef(&header).cropped(3).copyTo(&headerRLP); + + /// read padded frame and mac + handshakeInBuffer.resize(frameSize + ((16 - (frameSize % 16)) % 16) + h128::size); + ba::async_read(*socket, boost::asio::buffer(handshakeInBuffer, handshakeInBuffer.size()), [this, self, headerRLP](boost::system::error_code ec, std::size_t length) + { + if (ec) + transition(ec); + else { - p.reset(new Peer()); - p->id = remote; + if (!io->authAndDecryptFrame(bytesRef(&handshakeInBuffer))) + { + clog(NetWarn) << (originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: decrypt failed"; + nextState = Error; + transition(); + return; + } + + RLP rlp(handshakeInBuffer); + auto packetType = (PacketType)rlp[0].toInt(); + if (packetType != 0) + { + clog(NetWarn) << (originated ? "p2p.connect.egress" : "p2p.connect.ingress") << "hello frame: invalid packet type"; + nextState = Error; + transition(); + return; + } + + // todo: handover RLPFrameIO + host->startPeerSession(remote, rlp, socket); } - p->endpoint.tcp.address(socket->remote_endpoint().address()); - p->m_lastDisconnect = NoDisconnect; - p->m_lastConnected = std::chrono::system_clock::now(); - p->m_failedAttempts = 0; - - auto ps = std::make_shared(host, move(*socket), p); - ps->start(); -// } - - // todo: PeerSession will take ownership of k and use it to encrypt wireline. - delete io; -// }); -// }); + }); + } + }); } } diff --git a/libp2p/RLPxHandshake.h b/libp2p/RLPxHandshake.h index a0b739660..2f8cc9094 100644 --- a/libp2p/RLPxHandshake.h +++ b/libp2p/RLPxHandshake.h @@ -40,21 +40,21 @@ class RLPXHandshake; class RLPXFrameIO { public: - RLPXFrameIO(RLPXHandshake& _init); + RLPXFrameIO(RLPXHandshake const& _init); - void writeFullPacketFrame(bytesConstRef _packet); - - void writeHeader(bi::tcp::socket* _socket, h128 const& _header); - - void write(bi::tcp::socket* _socket, bytesConstRef _in, bool _eof = false); + void writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes); + + /// Authenticates and decrypts header in-place. + bool authAndDecryptHeader(h256& io_cipherWithMac); - bool read(bytesConstRef _in, bytes& o_out); + /// Authenticates and decrypts frame in-place. + bool authAndDecryptFrame(bytesRef io_cipherWithMac); h128 egressDigest(); h128 ingressDigest(); - void updateEgressMACWithHeader(h128 const& _headerCipher); + void updateEgressMACWithHeader(bytesConstRef _headerCipher); void updateEgressMACWithEndOfFrame(bytesConstRef _cipher); @@ -66,21 +66,28 @@ private: void updateMAC(CryptoPP::SHA3_256& _mac, h128 const& _seed = h128()); CryptoPP::CTR_Mode::Encryption m_frameEnc; + CryptoPP::CTR_Mode::Encryption m_frameDec; CryptoPP::ECB_Mode::Encryption m_macEnc; CryptoPP::SHA3_256 m_egressMac; CryptoPP::SHA3_256 m_ingressMac; + + bi::tcp::socket* m_socket; }; -struct RLPXHandshake: public std::enable_shared_from_this +// TODO: change properties to m_ +class RLPXHandshake: public std::enable_shared_from_this { +public: friend class RLPXFrameIO; - friend class Host; + enum State { Error = -1, New, // New->AckAuth [egress: tx auth, ingress: rx auth] - AckAuth, // AckAuth->Authenticating [egress: rx ack, ingress: tx ack] - Authenticating, // Authenticating [tx caps, rx caps, authenticate] + AckAuth, // AckAuth->WriteHello [egress: rx ack, ingress: tx ack] + WriteHello, // WriteHello [tx caps, rx caps, writehello] + ReadHello, + StartSession }; /// Handshake for ingress connection. Takes ownership of socket. @@ -91,20 +98,18 @@ struct RLPXHandshake: public std::enable_shared_from_this ~RLPXHandshake() { delete socket; } -protected: void start() { transition(); } - void generateAuth(); - bool decodeAuth(); +protected: + void writeAuth(); + void readAuth(); - void generateAck(); - bool decodeAck(); + void writeAck(); + void readAck(); - bytes frame(bytesConstRef _packet); - -private: + void error(); void transition(boost::system::error_code _ech = boost::system::error_code()); - + /// Current state of handshake. State nextState = New; @@ -121,12 +126,17 @@ private: bytes authCipher; bytes ack; bytes ackCipher; - + bytes handshakeOutBuffer; + bytes handshakeInBuffer; + crypto::ECDHE ecdhe; h256 nonce; Public remoteEphemeral; h256 remoteNonce; + + /// Frame IO is used to read frame for last step of handshake authentication. + std::unique_ptr io; }; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 6ff765cf6..a9d50f6e7 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -36,11 +36,11 @@ using namespace dev::p2p; #endif #define clogS(X) dev::LogOutputStream(false) << "| " << std::setw(2) << m_socket.native_handle() << "] " -Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& _n): +Session::Session(Host* _s, bi::tcp::socket _socket, std::shared_ptr const& _n, PeerSessionInfo _info): m_server(_s), - m_socket(std::move(_socket)), + m_socket(move(_socket)), m_peer(_n), - m_info({NodeId(), "?", m_socket.remote_endpoint().address().to_string(), 0, chrono::steady_clock::duration(0), CapDescSet(), 0, map()}), + m_info(_info), m_ping(chrono::steady_clock::time_point::max()) { m_lastReceived = m_connect = chrono::steady_clock::now(); @@ -151,86 +151,6 @@ bool Session::interpret(RLP const& _r) switch ((PacketType)_r[0].toInt()) { - case HelloPacket: - { - // TODO: P2P first pass, implement signatures. if signature fails, drop connection. if egress, flag node's endpoint as stale. - // Move auth to Host so we consolidate authentication logic and eschew peer deduplication logic. - // Move all node-lifecycle information into Host. - // Finalize peer-lifecycle properties vs node lifecycle. - - m_protocolVersion = _r[1].toInt(); - auto clientVersion = _r[2].toString(); - auto caps = _r[3].toVector(); - auto listenPort = _r[4].toInt(); - auto id = _r[5].toHash(); - - // clang error (previously: ... << hex << caps ...) - // "'operator<<' should be declared prior to the call site or in an associated namespace of one of its arguments" - stringstream capslog; - for (auto cap: caps) - capslog << "(" << cap.first << "," << dec << cap.second << ")"; - - clogS(NetMessageSummary) << "Hello: " << clientVersion << "V[" << m_protocolVersion << "]" << id.abridged() << showbase << capslog.str() << dec << listenPort; - - if (m_server->id() == id) - { - // Already connected. - clogS(NetWarn) << "Connected to ourself under a false pretext. We were told this peer was id" << id.abridged(); - disconnect(LocalIdentity); - return true; - } - - // if peer and connection have id, check for UnexpectedIdentity - if (!id) - { - disconnect(NullIdentity); - return true; - } - else if (!m_peer->id) - { - m_peer->id = id; - m_peer->endpoint.tcp.port(listenPort); - } - else if (m_peer->id != id) - { - // TODO p2p: FIXME. Host should catch this and reattempt adding node to table. - m_peer->id = id; - m_peer->m_score = 0; - m_peer->m_rating = 0; -// disconnect(UnexpectedIdentity); -// return true; - } - - if (m_server->havePeerSession(id)) - { - // Already connected. - clogS(NetWarn) << "Already connected to a peer with id" << id.abridged(); - // Possible that two nodes continually connect to each other with exact same timing. - this_thread::sleep_for(chrono::milliseconds(rand() % 100)); - disconnect(DuplicatePeer); - return true; - } - - if (m_peer->isOffline()) - m_peer->m_lastConnected = chrono::system_clock::now(); - - if (m_protocolVersion != m_server->protocolVersion()) - { - disconnect(IncompatibleProtocol); - return true; - } - - m_info.clientVersion = clientVersion; - m_info.host = m_socket.remote_endpoint().address().to_string(); - m_info.port = listenPort; - m_info.lastPing = std::chrono::steady_clock::duration(); - m_info.caps = _r[3].toSet(); - m_info.socket = (unsigned)m_socket.native_handle(); - m_info.notes = map(); - - m_server->registerPeer(shared_from_this(), caps); - break; - } case DisconnectPacket: { string reason = "Unspecified"; @@ -478,14 +398,6 @@ void Session::disconnect(DisconnectReason _reason) void Session::start() { - RLPStream s; - prep(s, HelloPacket, 5) - << m_server->protocolVersion() - << m_server->m_clientVersion - << m_server->caps() - << m_server->m_tcpPublic.port() - << m_server->id(); - sealAndSend(s); ping(); doRead(); } diff --git a/libp2p/Session.h b/libp2p/Session.h index 4d55e7d9d..bfb7a2d60 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -51,7 +51,7 @@ class Session: public std::enable_shared_from_this friend class HostCapabilityFace; public: - Session(Host* _server, bi::tcp::socket _socket, std::shared_ptr const& _n); + Session(Host* _server, bi::tcp::socket _socket, std::shared_ptr const& _n, PeerSessionInfo _info); virtual ~Session(); void start(); diff --git a/test/rlpx.cpp b/test/rlpx.cpp index d845911f4..1cdde4320 100644 --- a/test/rlpx.cpp +++ b/test/rlpx.cpp @@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(test_secrets_cpp_vectors) bytes macSecret(32); outRef.copyTo(&macSecret); BOOST_REQUIRE(macSecret == fromHex("2ec149072353d54437422837c886b0538a9206e6c559f6b4a55f65a866867723")); - m_macEnc.SetKey(outRef.data(), h256::size); + m_macEnc.SetKey(outRef.data(), h128::size); // Initiator egress-mac: sha3(mac-secret^recipient-nonce || auth-sent-init) // ingress-mac: sha3(mac-secret^initiator-nonce || auth-recvd-ack)