Skip to content

Commit 980985f

Browse files
committed
RFC8439Encrypt can take multiple plaintexts
1 parent 64cd5d3 commit 980985f

File tree

6 files changed

+35
-31
lines changed

6 files changed

+35
-31
lines changed

src/bench/rfc8439.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ std::array<std::byte, 12> nonce = {std::byte{0x00}, std::byte{0x01}, std::byte{0
2424

2525
static void RFC8439_AEAD(benchmark::Bench& bench, size_t plaintext_size, bool include_decryption)
2626
{
27-
std::vector<std::byte> plaintext_in(plaintext_size, std::byte{0x00});
27+
const std::vector<std::byte> plaintext_in(plaintext_size, std::byte{0x00});
28+
std::vector<Span<const std::byte>> ins{plaintext_in};
2829
std::vector<std::byte> output(plaintext_size + POLY1305_TAGLEN, std::byte{0x00});
2930

3031
bench.batch(plaintext_size).unit("byte").run([&] {
31-
RFC8439Encrypt(aad, zero_key, nonce, plaintext_in, output);
32+
RFC8439Encrypt(aad, zero_key, nonce, ins, output);
3233

3334
if (include_decryption) {
3435
std::vector<std::byte> decrypted_plaintext(plaintext_size);

src/crypto/bip324_suite.cpp

+3-15
Original file line numberDiff line numberDiff line change
@@ -72,25 +72,13 @@ bool BIP324CipherSuite::Crypt(const Span<const std::byte> input, Span<std::byte>
7272
uint32_t ciphertext_len = BIP324_HEADER_LEN + input.size();
7373
WriteLE32(reinterpret_cast<unsigned char*>(&ciphertext_len), ciphertext_len);
7474

75-
std::vector<std::byte> input_vec;
76-
input_vec.resize(BIP324_HEADER_LEN + input.size());
77-
78-
79-
// TODO: this can be optimized by changing the RFC8439Encrypt interface to accept a list of inputs.
80-
// But, at the moment, there's a potential bug in out ChaCha20 implementation for plaintexts that
81-
// are not a multiple of 64 bytes -- the rest of the "block" is discarded. An update is in progress
82-
// which will help here.
83-
memcpy(input_vec.data(), &flags, BIP324_HEADER_LEN);
84-
if (!input.empty()) {
85-
memcpy(input_vec.data() + BIP324_HEADER_LEN, input.data(), input.size());
86-
}
87-
88-
8975
auto write_pos = output.data();
9076
fsc20.Crypt({reinterpret_cast<std::byte*>(&ciphertext_len), BIP324_LENGTH_FIELD_LEN},
9177
{write_pos, BIP324_LENGTH_FIELD_LEN});
9278
write_pos += BIP324_LENGTH_FIELD_LEN;
93-
RFC8439Encrypt({}, payload_key, nonce, input_vec, {write_pos, BIP324_HEADER_LEN + input.size() + RFC8439_TAGLEN});
79+
80+
std::vector<Span<const std::byte>> ins{Span{reinterpret_cast<std::byte*>(&flags), BIP324_HEADER_LEN}, input};
81+
RFC8439Encrypt({}, payload_key, nonce, ins, {write_pos, BIP324_HEADER_LEN + input.size() + RFC8439_TAGLEN});
9482
} else {
9583
// we must use BIP324CipherSuite::DecryptLength before calling BIP324CipherSuite::Crypt
9684
// input is encrypted (header + payload) and the mac tag

src/crypto/rfc8439.cpp

+24-9
Original file line numberDiff line numberDiff line change
@@ -57,27 +57,41 @@ std::array<std::byte, POLY1305_KEYLEN> GetPoly1305Key(ChaCha20& c20)
5757
return polykey;
5858
}
5959

60-
void RFC8439Crypt(ChaCha20& c20, const Span<const std::byte> in_bytes, Span<std::byte> out_bytes)
60+
void RFC8439Crypt(ChaCha20& c20, const std::vector<Span<const std::byte>>& in_bytes, Span<std::byte> out_bytes)
6161
{
62-
assert(in_bytes.size() <= out_bytes.size());
62+
size_t total_bytes = 0;
63+
for (auto in: in_bytes) {
64+
total_bytes += in.size();
65+
}
66+
assert(total_bytes <= out_bytes.size());
6367
c20.SeekRFC8439(1);
64-
c20.Crypt(reinterpret_cast<const unsigned char*>(in_bytes.data()), reinterpret_cast<unsigned char*>(out_bytes.data()), in_bytes.size());
68+
69+
auto write_pos = out_bytes.data();
70+
for (auto in: in_bytes) {
71+
c20.Crypt(reinterpret_cast<const unsigned char*>(in.data()), reinterpret_cast<unsigned char*>(write_pos), in.size());
72+
write_pos += in.size();
73+
}
6574
}
6675

67-
void RFC8439Encrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const Span<const std::byte> plaintext, Span<std::byte> output)
76+
void RFC8439Encrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const std::vector<Span<const std::byte>>& plaintexts, Span<std::byte> output)
6877
{
6978
assert(key.size() == RFC8439_KEYLEN);
70-
assert(output.size() >= plaintext.size() + POLY1305_TAGLEN);
7179

7280
ChaCha20 c20{reinterpret_cast<const unsigned char*>(key.data()), key.size()};
7381
c20.SetRFC8439Nonce(nonce);
7482

7583
std::array<std::byte, POLY1305_KEYLEN> polykey{GetPoly1305Key(c20)};
7684

77-
RFC8439Crypt(c20, plaintext, output);
85+
size_t total_bytes = 0;
86+
for (auto plaintext: plaintexts) {
87+
total_bytes += plaintext.size();
88+
}
89+
90+
assert(output.size() >= total_bytes + POLY1305_TAGLEN);
91+
RFC8439Crypt(c20, plaintexts, output);
7892
ComputeRFC8439Tag(polykey, aad,
79-
{output.data(), plaintext.size()},
80-
{output.data() + plaintext.size(), POLY1305_TAGLEN});
93+
{output.data(), total_bytes},
94+
{output.data() + total_bytes, POLY1305_TAGLEN});
8195
}
8296

8397
bool RFC8439Decrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const Span<const std::byte> input, Span<std::byte> plaintext)
@@ -98,6 +112,7 @@ bool RFC8439Decrypt(const Span<const std::byte> aad, const Span<const std::byte>
98112
return false;
99113
}
100114

101-
RFC8439Crypt(c20, {input.data(), input.size() - POLY1305_TAGLEN}, plaintext);
115+
std::vector<Span<const std::byte>> ins{{input.data(), input.size() - POLY1305_TAGLEN}};
116+
RFC8439Crypt(c20, ins, plaintext);
102117
return true;
103118
}

src/crypto/rfc8439.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
constexpr static size_t RFC8439_KEYLEN = 32;
1616
constexpr static size_t RFC8439_TAGLEN = POLY1305_TAGLEN;
1717

18-
void RFC8439Encrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const Span<const std::byte> plaintext, Span<std::byte> output);
18+
void RFC8439Encrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const std::vector<Span<const std::byte>>& plaintexts, Span<std::byte> output);
1919

2020
// returns false if authentication fails
2121
bool RFC8439Decrypt(const Span<const std::byte> aad, const Span<const std::byte> key, const std::array<std::byte, 12>& nonce, const Span<const std::byte> input, Span<std::byte> plaintext);

src/test/crypto_tests.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -808,8 +808,6 @@ static void TestBIP324CipherSuite(const std::string& hex_input, const std::strin
808808

809809
BOOST_AUTO_TEST_CASE(bip324_cipher_suite_testvectors)
810810
{
811-
/* test bip324 cipher suite */
812-
813811
// encrypting an empty message should result in 20 bytes:
814812
// 3 bytes of encrypted length, 1 byte header and 16 bytes MAC
815813
TestBIP324CipherSuite(/* plaintext */ "",
@@ -1081,8 +1079,9 @@ static void TestRFC8439AEAD(const std::string& hex_aad, const std::string& hex_k
10811079
std::array<std::byte, 12> nonce_arr;
10821080
memcpy(nonce_arr.data(), nonce.data(), 12);
10831081
auto plaintext = ParseHex(hex_plaintext);
1082+
std::vector<Span<const std::byte>> ins{MakeByteSpan(plaintext)};
10841083
std::vector<std::byte> output(plaintext.size() + POLY1305_TAGLEN, std::byte{0x00});
1085-
RFC8439Encrypt(MakeByteSpan(aad), MakeByteSpan(key), nonce_arr, MakeByteSpan(plaintext), output);
1084+
RFC8439Encrypt(MakeByteSpan(aad), MakeByteSpan(key), nonce_arr, ins, output);
10861085

10871086
BOOST_CHECK_EQUAL(HexStr({output.data(), output.size() - POLY1305_TAGLEN}), hex_expected_ciphertext);
10881087
BOOST_CHECK_EQUAL(HexStr({output.data() + output.size() - POLY1305_TAGLEN, POLY1305_TAGLEN}), hex_expected_auth_tag);

src/test/fuzz/crypto_rfc8439.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ FUZZ_TARGET(crypto_rfc8439)
3030
auto plaintext = fdp.ConsumeBytes<std::byte>(plaintext_len);
3131
plaintext.resize(plaintext_len);
3232

33+
std::vector<Span<const std::byte>> ins{plaintext};
3334
std::vector<std::byte> output(plaintext.size() + POLY1305_TAGLEN, std::byte{0x00});
34-
RFC8439Encrypt(aad, key, nonce, plaintext, output);
35+
RFC8439Encrypt(aad, key, nonce, ins, output);
3536

3637
auto bit_flip_attack = !plaintext.empty() && fdp.ConsumeBool();
3738
if (bit_flip_attack) {

0 commit comments

Comments
 (0)