Skip to content

Commit

Permalink
Working RFC8439 implementation (saving)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruv committed May 13, 2022
1 parent 958dd32 commit bb1a1ee
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
45 changes: 45 additions & 0 deletions src/crypto/rfc8439.cpp
Original file line number Diff line number Diff line change
@@ -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 <crypto/rfc8439.h>
#include <crypto/chacha20.h>
#include <crypto/common.h>

#include <cstring>

inline size_t padded16_size(size_t len) {
return (len % 16 == 0) ? len : (len / 16 + 1) * 16;
}

RFC8439Encrypted RFC8439Encrypt(Span<const std::byte> aad, Span<const std::byte> key, const std::array<std::byte, 12>&iv, Span<const std::byte> plaintext) {
RFC8439Encrypted ret;

assert(key.size() == RFC8439_KEYLEN);
ChaCha20 c20{reinterpret_cast<const unsigned char*>(key.data()), key.size()};

c20.SetRFC8439IV(iv);
c20.SeekRFC8439(0);

std::array<std::byte, POLY1305_KEYLEN> polykey;
c20.Keystream(reinterpret_cast<unsigned char*>(polykey.data()), POLY1305_KEYLEN);

ret.ciphertext.resize(plaintext.size());
c20.SeekRFC8439(1);
c20.Crypt(reinterpret_cast<const unsigned char*>(plaintext.data()), reinterpret_cast<unsigned char*>(ret.ciphertext.data()), plaintext.size());

std::vector<std::byte> 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<unsigned char*>(bytes_to_authenticate.data()) + padded_aad_size + padded_ciphertext_size, aad.size());
WriteLE64(reinterpret_cast<unsigned char*>(bytes_to_authenticate.data()) + padded_aad_size + padded_ciphertext_size + 8, ret.ciphertext.size());

poly1305_auth(reinterpret_cast<unsigned char*>(ret.tag.data()),
reinterpret_cast<const unsigned char*>(bytes_to_authenticate.data()),
bytes_to_authenticate.size(),
reinterpret_cast<const unsigned char*>(polykey.data()));
return ret;
}
24 changes: 24 additions & 0 deletions src/crypto/rfc8439.h
Original file line number Diff line number Diff line change
@@ -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 <crypto/poly1305.h>
#include <span.h>

#include <array>
#include <cstddef>
#include <vector>

constexpr static size_t RFC8439_KEYLEN = 32;

struct RFC8439Encrypted {
std::vector<std::byte> ciphertext;
std::array<std::byte, POLY1305_TAGLEN> tag;
};

RFC8439Encrypted RFC8439Encrypt(Span<const std::byte> aad, Span<const std::byte> key, const std::array<std::byte, 12>& iv, Span<const std::byte> plaintext);

#endif // BITCOIN_CRYPTO_RFC8439_H
33 changes: 33 additions & 0 deletions src/test/crypto_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
#include <crypto/hmac_sha256.h>
#include <crypto/hmac_sha512.h>
#include <crypto/poly1305.h>
#include <crypto/rfc8439.h>
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
#include <crypto/sha3.h>
#include <crypto/sha512.h>
#include <crypto/muhash.h>
#include <random.h>
#include <span.h>
#include <streams.h>
#include <test/util/setup_common.h>
#include <util/strencodings.h>
Expand Down Expand Up @@ -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<std::byte, 12> 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()

0 comments on commit bb1a1ee

Please sign in to comment.