diff --git a/src/Makefile.am b/src/Makefile.am index 357e562c69..d5a159b7f1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -499,6 +499,8 @@ crypto_libbitcoin_crypto_base_la_SOURCES = \ crypto/poly1305.cpp \ crypto/muhash.h \ crypto/muhash.cpp \ + crypto/rfc8439.h \ + crypto/rfc8439.cpp \ crypto/ripemd160.cpp \ crypto/ripemd160.h \ crypto/sha1.cpp \ diff --git a/src/crypto/rfc8439.cpp b/src/crypto/rfc8439.cpp new file mode 100644 index 0000000000..2fc90088ea --- /dev/null +++ b/src/crypto/rfc8439.cpp @@ -0,0 +1,45 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include + +#include + +inline size_t padded16_size(size_t len) { + return (len % 16 == 0) ? len : (len / 16 + 1) * 16; +} + +RFC8439Encrypted RFC8439Encrypt(Span aad, Span key, const std::array&iv, Span plaintext) { + RFC8439Encrypted ret; + + assert(key.size() == RFC8439_KEYLEN); + ChaCha20 c20{reinterpret_cast(key.data()), key.size()}; + + c20.SetRFC8439IV(iv); + c20.SeekRFC8439(0); + + std::array polykey; + c20.Keystream(reinterpret_cast(polykey.data()), POLY1305_KEYLEN); + + ret.ciphertext.resize(plaintext.size()); + c20.SeekRFC8439(1); + c20.Crypt(reinterpret_cast(plaintext.data()), reinterpret_cast(ret.ciphertext.data()), plaintext.size()); + + std::vector bytes_to_authenticate; + auto padded_aad_size = padded16_size(aad.size()); + auto padded_ciphertext_size = padded16_size(ret.ciphertext.size()); + bytes_to_authenticate.resize(padded_aad_size + padded_ciphertext_size + 8 + 8, std::byte{0x00}); + std::copy(aad.begin(), aad.end(), bytes_to_authenticate.begin()); + std::copy(ret.ciphertext.begin(), ret.ciphertext.end(), bytes_to_authenticate.begin() + padded_aad_size); + WriteLE64(reinterpret_cast(bytes_to_authenticate.data()) + padded_aad_size + padded_ciphertext_size, aad.size()); + WriteLE64(reinterpret_cast(bytes_to_authenticate.data()) + padded_aad_size + padded_ciphertext_size + 8, ret.ciphertext.size()); + + poly1305_auth(reinterpret_cast(ret.tag.data()), + reinterpret_cast(bytes_to_authenticate.data()), + bytes_to_authenticate.size(), + reinterpret_cast(polykey.data())); + return ret; +} diff --git a/src/crypto/rfc8439.h b/src/crypto/rfc8439.h new file mode 100644 index 0000000000..326f64e4bb --- /dev/null +++ b/src/crypto/rfc8439.h @@ -0,0 +1,24 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_RFC8439_H +#define BITCOIN_CRYPTO_RFC8439_H + +#include +#include + +#include +#include +#include + +constexpr static size_t RFC8439_KEYLEN = 32; + +struct RFC8439Encrypted { + std::vector ciphertext; + std::array tag; +}; + +RFC8439Encrypted RFC8439Encrypt(Span aad, Span key, const std::array& iv, Span plaintext); + +#endif // BITCOIN_CRYPTO_RFC8439_H diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 6db3b13550..5e2c14a7a7 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -994,4 +996,35 @@ BOOST_AUTO_TEST_CASE(muhash_tests) BOOST_CHECK_EQUAL(HexStr(out4), "3a31e6903aff0de9f62f9a9f7f8b861de76ce2cda09822b90014319ae5dc2271"); } +static void TestRFC8439AEAD(const std::string& hex_aad, const std::string& hex_key, const std::string& hex_iv, const std::string& hex_plaintext, const std::string& hex_expected_ciphertext, const std::string& hex_expected_auth_tag) { + auto aad = ParseHex(hex_aad); + auto key = ParseHex(hex_key); + auto iv = ParseHex(hex_iv); + std::array iv_arr; + memcpy(iv_arr.data(), iv.data(), 12); + auto plaintext = ParseHex(hex_plaintext); + auto ret = RFC8439Encrypt(MakeByteSpan(aad), MakeByteSpan(key), iv_arr, MakeByteSpan(plaintext)); + + BOOST_CHECK_EQUAL(HexStr(MakeByteSpan(ret.ciphertext)), hex_expected_ciphertext); + BOOST_CHECK_EQUAL(HexStr(MakeByteSpan(ret.tag)), hex_expected_auth_tag); +} + +BOOST_AUTO_TEST_CASE(rfc8439_tests) { + + // Test vector from https://datatracker.ietf.org/doc/html/rfc8439#section-2.8.2 + TestRFC8439AEAD("50515253c0c1c2c3c4c5c6c7", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "070000004041424344454647", + "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e", + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116", + "1ae10b594f09e26a7e902ecbd0600691"); + + // Test vector from https://datatracker.ietf.org/doc/html/rfc8439#appendix-A.5 + TestRFC8439AEAD("f33388860000000000004e91", + "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", + "000000000102030405060708", + "496e7465726e65742d4472616674732061726520647261667420646f63756d656e74732076616c696420666f722061206d6178696d756d206f6620736978206d6f6e74687320616e64206d617920626520757064617465642c207265706c616365642c206f72206f62736f6c65746564206279206f7468657220646f63756d656e747320617420616e792074696d652e20497420697320696e617070726f70726961746520746f2075736520496e7465726e65742d447261667473206173207265666572656e6365206d6174657269616c206f7220746f2063697465207468656d206f74686572207468616e206173202fe2809c776f726b20696e2070726f67726573732e2fe2809d", + "64a0861575861af460f062c79be643bd5e805cfd345cf389f108670ac76c8cb24c6cfc18755d43eea09ee94e382d26b0bdb7b73c321b0100d4f03b7f355894cf332f830e710b97ce98c8a84abd0b948114ad176e008d33bd60f982b1ff37c8559797a06ef4f0ef61c186324e2b3506383606907b6a7c02b0f9f6157b53c867e4b9166c767b804d46a59b5216cde7a4e99040c5a40433225ee282a1b0a06c523eaf4534d7f83fa1155b0047718cbc546a0d072b04b3564eea1b422273f548271a0bb2316053fa76991955ebd63159434ecebb4e466dae5a1073a6727627097a1049e617d91d361094fa68f0ff77987130305beaba2eda04df997b714d6c6f2c29a6ad5cb4022b02709b", + "eead9d67890cbb22392336fea1851f38"); +} BOOST_AUTO_TEST_SUITE_END()