RLPXFrameCoder.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file RLPXFrameCoder.cpp
  15. * @author Alex Leverington <nessence@gmail.com>
  16. * @date 2015
  17. */
  18. #include "RLPXFrameCoder.h"
  19. #include <libdevcore/Assertions.h>
  20. #include "RLPxHandshake.h"
  21. #include "RLPXPacket.h"
  22. using namespace std;
  23. using namespace dev;
  24. using namespace dev::p2p;
  25. using namespace CryptoPP;
  26. RLPXFrameInfo::RLPXFrameInfo(bytesConstRef _header):
  27. length((_header[0] * 256 + _header[1]) * 256 + _header[2]),
  28. padding((16 - (length % 16)) % 16),
  29. data(_header.cropped(3).toBytes()),
  30. header(RLP(data, RLP::ThrowOnFail | RLP::FailIfTooSmall)),
  31. protocolId(header[0].toInt<uint16_t>()),
  32. multiFrame(header.itemCount() > 1),
  33. sequenceId(multiFrame ? header[1].toInt<uint16_t>() : 0),
  34. totalLength(header.itemCount() == 3 ? header[2].toInt<uint32_t>() : 0)
  35. {}
  36. RLPXFrameCoder::RLPXFrameCoder(RLPXHandshake const& _init)
  37. {
  38. setup(_init.m_originated, _init.m_remoteEphemeral, _init.m_remoteNonce, _init.m_ecdhe, _init.m_nonce, &_init.m_ackCipher, &_init.m_authCipher);
  39. }
  40. RLPXFrameCoder::RLPXFrameCoder(bool _originated, h512 const& _remoteEphemeral, h256 const& _remoteNonce, crypto::ECDHE const& _ecdhe, h256 const& _nonce, bytesConstRef _ackCipher, bytesConstRef _authCipher)
  41. {
  42. setup(_originated, _remoteEphemeral, _remoteNonce, _ecdhe, _nonce, _ackCipher, _authCipher);
  43. }
  44. void RLPXFrameCoder::setup(bool _originated, h512 const& _remoteEphemeral, h256 const& _remoteNonce, crypto::ECDHE const& _ecdhe, h256 const& _nonce, bytesConstRef _ackCipher, bytesConstRef _authCipher)
  45. {
  46. bytes keyMaterialBytes(64);
  47. bytesRef keyMaterial(&keyMaterialBytes);
  48. // shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || initiator-nonce))
  49. Secret ephemeralShared;
  50. _ecdhe.agree(_remoteEphemeral, ephemeralShared);
  51. ephemeralShared.ref().copyTo(keyMaterial.cropped(0, h256::size));
  52. h512 nonceMaterial;
  53. h256 const& leftNonce = _originated ? _remoteNonce : _nonce;
  54. h256 const& rightNonce = _originated ? _nonce : _remoteNonce;
  55. leftNonce.ref().copyTo(nonceMaterial.ref().cropped(0, h256::size));
  56. rightNonce.ref().copyTo(nonceMaterial.ref().cropped(h256::size, h256::size));
  57. auto outRef(keyMaterial.cropped(h256::size, h256::size));
  58. sha3(nonceMaterial.ref(), outRef); // output h(nonces)
  59. sha3(keyMaterial, outRef); // output shared-secret
  60. // token: sha3(outRef, bytesRef(&token)); -> m_host (to be saved to disk)
  61. // aes-secret = sha3(ecdhe-shared-secret || shared-secret)
  62. sha3(keyMaterial, outRef); // output aes-secret
  63. m_frameEncKey.resize(h256::size);
  64. memcpy(m_frameEncKey.data(), outRef.data(), h256::size);
  65. m_frameDecKey.resize(h256::size);
  66. memcpy(m_frameDecKey.data(), outRef.data(), h256::size);
  67. h128 iv;
  68. m_frameEnc.SetKeyWithIV(m_frameEncKey, h256::size, iv.data());
  69. m_frameDec.SetKeyWithIV(m_frameDecKey, h256::size, iv.data());
  70. // mac-secret = sha3(ecdhe-shared-secret || aes-secret)
  71. sha3(keyMaterial, outRef); // output mac-secret
  72. m_macEncKey.resize(h256::size);
  73. memcpy(m_macEncKey.data(), outRef.data(), h256::size);
  74. m_macEnc.SetKey(m_macEncKey, h256::size);
  75. // Initiator egress-mac: sha3(mac-secret^recipient-nonce || auth-sent-init)
  76. // ingress-mac: sha3(mac-secret^initiator-nonce || auth-recvd-ack)
  77. // Recipient egress-mac: sha3(mac-secret^initiator-nonce || auth-sent-ack)
  78. // ingress-mac: sha3(mac-secret^recipient-nonce || auth-recvd-init)
  79. (*(h256*)outRef.data() ^ _remoteNonce).ref().copyTo(keyMaterial);
  80. bytesConstRef egressCipher = _originated ? _authCipher : _ackCipher;
  81. keyMaterialBytes.resize(h256::size + egressCipher.size());
  82. keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
  83. egressCipher.copyTo(keyMaterial.cropped(h256::size, egressCipher.size()));
  84. m_egressMac.Update(keyMaterial.data(), keyMaterial.size());
  85. // recover mac-secret by re-xoring remoteNonce
  86. (*(h256*)keyMaterial.data() ^ _remoteNonce ^ _nonce).ref().copyTo(keyMaterial);
  87. bytesConstRef ingressCipher = _originated ? _ackCipher : _authCipher;
  88. keyMaterialBytes.resize(h256::size + ingressCipher.size());
  89. keyMaterial.retarget(keyMaterialBytes.data(), keyMaterialBytes.size());
  90. ingressCipher.copyTo(keyMaterial.cropped(h256::size, ingressCipher.size()));
  91. m_ingressMac.Update(keyMaterial.data(), keyMaterial.size());
  92. }
  93. void RLPXFrameCoder::writeFrame(uint16_t _protocolType, bytesConstRef _payload, bytes& o_bytes)
  94. {
  95. RLPStream header;
  96. uint32_t len = (uint32_t)_payload.size();
  97. header.appendRaw(bytes({byte((len >> 16) & 0xff), byte((len >> 8) & 0xff), byte(len & 0xff)}));
  98. header.appendList(1) << _protocolType;
  99. writeFrame(header, _payload, o_bytes);
  100. }
  101. void RLPXFrameCoder::writeFrame(uint16_t _protocolType, uint16_t _seqId, bytesConstRef _payload, bytes& o_bytes)
  102. {
  103. RLPStream header;
  104. uint32_t len = (uint32_t)_payload.size();
  105. header.appendRaw(bytes({byte((len >> 16) & 0xff), byte((len >> 8) & 0xff), byte(len & 0xff)}));
  106. header.appendList(2) << _protocolType << _seqId;
  107. writeFrame(header, _payload, o_bytes);
  108. }
  109. void RLPXFrameCoder::writeFrame(uint16_t _protocolType, uint16_t _seqId, uint32_t _totalSize, bytesConstRef _payload, bytes& o_bytes)
  110. {
  111. RLPStream header;
  112. uint32_t len = (uint32_t)_payload.size();
  113. header.appendRaw(bytes({byte((len >> 16) & 0xff), byte((len >> 8) & 0xff), byte(len & 0xff)}));
  114. header.appendList(3) << _protocolType << _seqId << _totalSize;
  115. writeFrame(header, _payload, o_bytes);
  116. }
  117. void RLPXFrameCoder::writeFrame(RLPStream const& _header, bytesConstRef _payload, bytes& o_bytes)
  118. {
  119. // TODO: SECURITY check header values && header <= 16 bytes
  120. bytes headerWithMac(h256::size);
  121. bytesConstRef(&_header.out()).copyTo(bytesRef(&headerWithMac));
  122. m_frameEnc.ProcessData(headerWithMac.data(), headerWithMac.data(), 16);
  123. updateEgressMACWithHeader(bytesConstRef(&headerWithMac).cropped(0, 16));
  124. egressDigest().ref().copyTo(bytesRef(&headerWithMac).cropped(h128::size,h128::size));
  125. auto padding = (16 - (_payload.size() % 16)) % 16;
  126. o_bytes.swap(headerWithMac);
  127. o_bytes.resize(32 + _payload.size() + padding + h128::size);
  128. bytesRef packetRef(o_bytes.data() + 32, _payload.size());
  129. m_frameEnc.ProcessData(packetRef.data(), _payload.data(), _payload.size());
  130. bytesRef paddingRef(o_bytes.data() + 32 + _payload.size(), padding);
  131. if (padding)
  132. m_frameEnc.ProcessData(paddingRef.data(), paddingRef.data(), padding);
  133. bytesRef packetWithPaddingRef(o_bytes.data() + 32, _payload.size() + padding);
  134. updateEgressMACWithFrame(packetWithPaddingRef);
  135. bytesRef macRef(o_bytes.data() + 32 + _payload.size() + padding, h128::size);
  136. egressDigest().ref().copyTo(macRef);
  137. }
  138. void RLPXFrameCoder::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes)
  139. {
  140. RLPStream header;
  141. uint32_t len = (uint32_t)_packet.size();
  142. header.appendRaw(bytes({byte((len >> 16) & 0xff), byte((len >> 8) & 0xff), byte(len & 0xff)}));
  143. header.appendRaw(bytes({0xc2,0x80,0x80}));
  144. writeFrame(header, _packet, o_bytes);
  145. }
  146. bool RLPXFrameCoder::authAndDecryptHeader(bytesRef io)
  147. {
  148. asserts(io.size() == h256::size);
  149. updateIngressMACWithHeader(io);
  150. bytesConstRef macRef = io.cropped(h128::size, h128::size);
  151. h128 expected = ingressDigest();
  152. if (*(h128*)macRef.data() != expected)
  153. return false;
  154. m_frameDec.ProcessData(io.data(), io.data(), h128::size);
  155. return true;
  156. }
  157. bool RLPXFrameCoder::authAndDecryptFrame(bytesRef io)
  158. {
  159. bytesRef cipherText(io.cropped(0, io.size() - h128::size));
  160. updateIngressMACWithFrame(cipherText);
  161. bytesConstRef frameMac(io.data() + io.size() - h128::size, h128::size);
  162. if (*(h128*)frameMac.data() != ingressDigest())
  163. return false;
  164. m_frameDec.ProcessData(io.data(), io.data(), io.size() - h128::size);
  165. return true;
  166. }
  167. #if defined(__GNUC__)
  168. // Do not warn about uses of functions (see Function Attributes), variables
  169. // (see Variable Attributes), and types (see Type Attributes) marked as
  170. // deprecated by using the deprecated attribute.
  171. //
  172. // Specifically we are suppressing the warnings from the deprecation
  173. // attributes added to the SHA3_256 and SHA3_512 classes in CryptoPP
  174. // after the 5.6.3 release.
  175. //
  176. // From that header file ...
  177. //
  178. // "The Crypto++ SHA-3 implementation dates back to January 2013 when NIST
  179. // selected Keccak as SHA-3. In August 2015 NIST finalized SHA-3, and it
  180. // was a modified version of the Keccak selection. Crypto++ 5.6.2 through
  181. // 5.6.4 provides the pre-FIPS 202 version of SHA-3; while Crypto++ 5.7
  182. // and above provides the FIPS 202 version of SHA-3.
  183. //
  184. // See also http://en.wikipedia.org/wiki/SHA-3
  185. //
  186. // This means that we will never be able to move to the CryptoPP-5.7.x
  187. // series of releases, because Ethereum requires Keccak, not the final
  188. // SHA-3 standard algorithm. We are planning to migrate cpp-ethereum
  189. // off CryptoPP anyway, so this is unlikely to be a long-standing issue.
  190. //
  191. // https://github.com/ethereum/cpp-ethereum/issues/3088
  192. //
  193. #pragma GCC diagnostic push
  194. #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  195. #endif // defined(__GNUC__)
  196. h128 RLPXFrameCoder::egressDigest()
  197. {
  198. SHA3_256 h(m_egressMac);
  199. h128 digest;
  200. h.TruncatedFinal(digest.data(), h128::size);
  201. return digest;
  202. }
  203. h128 RLPXFrameCoder::ingressDigest()
  204. {
  205. SHA3_256 h(m_ingressMac);
  206. h128 digest;
  207. h.TruncatedFinal(digest.data(), h128::size);
  208. return digest;
  209. }
  210. void RLPXFrameCoder::updateEgressMACWithHeader(bytesConstRef _headerCipher)
  211. {
  212. updateMAC(m_egressMac, _headerCipher.cropped(0, 16));
  213. }
  214. void RLPXFrameCoder::updateEgressMACWithFrame(bytesConstRef _cipher)
  215. {
  216. m_egressMac.Update(_cipher.data(), _cipher.size());
  217. updateMAC(m_egressMac);
  218. }
  219. void RLPXFrameCoder::updateIngressMACWithHeader(bytesConstRef _headerCipher)
  220. {
  221. updateMAC(m_ingressMac, _headerCipher.cropped(0, 16));
  222. }
  223. void RLPXFrameCoder::updateIngressMACWithFrame(bytesConstRef _cipher)
  224. {
  225. m_ingressMac.Update(_cipher.data(), _cipher.size());
  226. updateMAC(m_ingressMac);
  227. }
  228. void RLPXFrameCoder::updateMAC(SHA3_256& _mac, bytesConstRef _seed)
  229. {
  230. if (_seed.size() && _seed.size() != h128::size)
  231. asserts(false);
  232. SHA3_256 prevDigest(_mac);
  233. h128 encDigest(h128::size);
  234. prevDigest.TruncatedFinal(encDigest.data(), h128::size);
  235. h128 prevDigestOut = encDigest;
  236. {
  237. Guard l(x_macEnc);
  238. m_macEnc.ProcessData(encDigest.data(), encDigest.data(), 16);
  239. }
  240. if (_seed.size())
  241. encDigest ^= *(h128*)_seed.data();
  242. else
  243. encDigest ^= *(h128*)prevDigestOut.data();
  244. // update mac for final digest
  245. _mac.Update(encDigest.data(), h128::size);
  246. }
  247. #if defined(__GNUC__)
  248. #pragma GCC diagnostic pop
  249. #endif // defined(__GNUC__)