77#include < crypto/chacha20.h>
88#include < crypto/common.h>
99
10+ #include < algorithm>
1011#include < cstring>
1112
1213#ifndef RFC8439_TIMINGSAFE_BCMP
@@ -57,19 +58,40 @@ std::array<std::byte, POLY1305_KEYLEN> GetPoly1305Key(ChaCha20& c20)
5758 return polykey;
5859}
5960
60- void RFC8439Crypt (ChaCha20& c20, const std::vector<Span<const std::byte>>& in_bytes, Span<std::byte> out_bytes)
61+ void RFC8439Crypt (ChaCha20& c20, const std::vector<Span<const std::byte>>& in_bytes, std::vector< Span<std::byte>>& out_bytes)
6162{
62- size_t total_bytes = 0 ;
63- for (auto in: in_bytes) {
64- total_bytes += in.size ();
63+ size_t total_in_bytes = 0 ;
64+ for (auto in : in_bytes) {
65+ total_in_bytes += in.size ();
6566 }
66- assert (total_bytes <= out_bytes.size ());
67- c20.SeekRFC8439 (1 );
67+ size_t total_out_bytes = 0 ;
68+ for (auto out : out_bytes) {
69+ total_out_bytes += out.size ();
70+ }
71+ assert (total_in_bytes <= total_out_bytes);
6872
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+ c20.SeekRFC8439 (1 );
74+ size_t in_idx{0 }, in_chunk_pos{0 }, out_idx{0 }, out_chunk_pos{0 };
75+ while (in_idx < in_bytes.size ()) {
76+ auto in_chunk = in_bytes[in_idx];
77+ auto out_chunk = out_bytes[out_idx];
78+ auto read_pos = in_chunk.begin () + in_chunk_pos;
79+ auto write_pos = out_chunk.begin () + out_chunk_pos;
80+ auto num_bytes = std::min (in_chunk.size () - in_chunk_pos, out_chunk.size () - out_chunk_pos);
81+
82+ c20.Crypt (reinterpret_cast <const unsigned char *>(read_pos), reinterpret_cast <unsigned char *>(write_pos), num_bytes);
83+ in_chunk_pos += num_bytes;
84+ out_chunk_pos += num_bytes;
85+
86+ if (in_chunk_pos >= in_chunk.size ()) {
87+ in_idx++;
88+ in_chunk_pos = 0 ;
89+ }
90+
91+ if (out_chunk_pos >= out_chunk.size ()) {
92+ out_idx++;
93+ out_chunk_pos = 0 ;
94+ }
7395 }
7496}
7597
@@ -88,16 +110,24 @@ void RFC8439Encrypt(const Span<const std::byte> aad, const Span<const std::byte>
88110 }
89111
90112 assert (output.size () >= total_bytes + POLY1305_TAGLEN);
91- RFC8439Crypt (c20, plaintexts, output);
113+
114+ std::vector<Span<std::byte>> outs{output};
115+ RFC8439Crypt (c20, plaintexts, outs);
92116 ComputeRFC8439Tag (polykey, aad,
93117 {output.data (), total_bytes},
94118 {output.data () + total_bytes, POLY1305_TAGLEN});
95119}
96120
97- 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 )
121+ 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, std::vector< Span<std::byte>>& plaintexts )
98122{
99123 assert (key.size () == RFC8439_KEYLEN);
100- assert (plaintext.size () >= input.size () - POLY1305_TAGLEN);
124+
125+ size_t total_bytes = 0 ;
126+ for (auto plaintext: plaintexts) {
127+ total_bytes += plaintext.size ();
128+ }
129+
130+ assert (total_bytes >= input.size () - POLY1305_TAGLEN);
101131
102132 ChaCha20 c20{reinterpret_cast <const unsigned char *>(key.data ()), key.size ()};
103133 c20.SetRFC8439Nonce (nonce);
@@ -113,6 +143,6 @@ bool RFC8439Decrypt(const Span<const std::byte> aad, const Span<const std::byte>
113143 }
114144
115145 std::vector<Span<const std::byte>> ins{{input.data (), input.size () - POLY1305_TAGLEN}};
116- RFC8439Crypt (c20, ins, plaintext );
146+ RFC8439Crypt (c20, ins, plaintexts );
117147 return true ;
118148}
0 commit comments