88#include < crypto/common.h>
99#include < crypto/chacha20.h>
1010#include < support/cleanse.h>
11+ #include < span.h>
1112
1213#include < algorithm>
1314#include < string.h>
@@ -22,23 +23,24 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (
2223
2324#define REPEAT10 (a ) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while (0 )
2425
25- void ChaCha20Aligned::SetKey32 ( const unsigned char * k)
26+ void ChaCha20Aligned::SetKey (Span< const std::byte> key) noexcept
2627{
27- input[0 ] = ReadLE32 (k + 0 );
28- input[1 ] = ReadLE32 (k + 4 );
29- input[2 ] = ReadLE32 (k + 8 );
30- input[3 ] = ReadLE32 (k + 12 );
31- input[4 ] = ReadLE32 (k + 16 );
32- input[5 ] = ReadLE32 (k + 20 );
33- input[6 ] = ReadLE32 (k + 24 );
34- input[7 ] = ReadLE32 (k + 28 );
28+ assert (key.size () == KEYLEN);
29+ input[0 ] = ReadLE32 (UCharCast (key.data () + 0 ));
30+ input[1 ] = ReadLE32 (UCharCast (key.data () + 4 ));
31+ input[2 ] = ReadLE32 (UCharCast (key.data () + 8 ));
32+ input[3 ] = ReadLE32 (UCharCast (key.data () + 12 ));
33+ input[4 ] = ReadLE32 (UCharCast (key.data () + 16 ));
34+ input[5 ] = ReadLE32 (UCharCast (key.data () + 20 ));
35+ input[6 ] = ReadLE32 (UCharCast (key.data () + 24 ));
36+ input[7 ] = ReadLE32 (UCharCast (key.data () + 28 ));
3537 input[8 ] = 0 ;
3638 input[9 ] = 0 ;
3739 input[10 ] = 0 ;
3840 input[11 ] = 0 ;
3941}
4042
41- ChaCha20Aligned::ChaCha20Aligned ()
43+ ChaCha20Aligned::ChaCha20Aligned () noexcept
4244{
4345 memset (input, 0 , sizeof (input));
4446}
@@ -48,21 +50,25 @@ ChaCha20Aligned::~ChaCha20Aligned()
4850 memory_cleanse (input, sizeof (input));
4951}
5052
51- ChaCha20Aligned::ChaCha20Aligned (const unsigned char * key32)
53+ ChaCha20Aligned::ChaCha20Aligned (Span< const std::byte> key) noexcept
5254{
53- SetKey32 (key32 );
55+ SetKey (key );
5456}
5557
56- void ChaCha20Aligned::Seek64 (Nonce96 nonce, uint32_t block_counter)
58+ void ChaCha20Aligned::Seek (Nonce96 nonce, uint32_t block_counter) noexcept
5759{
5860 input[8 ] = block_counter;
5961 input[9 ] = nonce.first ;
6062 input[10 ] = nonce.second ;
6163 input[11 ] = nonce.second >> 32 ;
6264}
6365
64- inline void ChaCha20Aligned::Keystream64 ( unsigned char * c, size_t blocks)
66+ inline void ChaCha20Aligned::Keystream (Span<std::byte> output) noexcept
6567{
68+ unsigned char * c = UCharCast (output.data ());
69+ size_t blocks = output.size () / BLOCKLEN;
70+ assert (blocks * BLOCKLEN == output.size ());
71+
6672 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
6773 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
6874
@@ -154,12 +160,18 @@ inline void ChaCha20Aligned::Keystream64(unsigned char* c, size_t blocks)
154160 return ;
155161 }
156162 blocks -= 1 ;
157- c += 64 ;
163+ c += BLOCKLEN ;
158164 }
159165}
160166
161- inline void ChaCha20Aligned::Crypt64 ( const unsigned char * m, unsigned char * c, size_t blocks)
167+ inline void ChaCha20Aligned::Crypt (Span< const std::byte> in_bytes, Span<std::byte> out_bytes) noexcept
162168{
169+ assert (in_bytes.size () == out_bytes.size ());
170+ const unsigned char * m = UCharCast (in_bytes.data ());
171+ unsigned char * c = UCharCast (out_bytes.data ());
172+ size_t blocks = out_bytes.size () / BLOCKLEN;
173+ assert (blocks * BLOCKLEN == out_bytes.size ());
174+
163175 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
164176 uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
165177
@@ -268,70 +280,68 @@ inline void ChaCha20Aligned::Crypt64(const unsigned char* m, unsigned char* c, s
268280 return ;
269281 }
270282 blocks -= 1 ;
271- c += 64 ;
272- m += 64 ;
283+ c += BLOCKLEN ;
284+ m += BLOCKLEN ;
273285 }
274286}
275287
276- void ChaCha20::Keystream (unsigned char * c, size_t bytes)
288+ void ChaCha20::Keystream (Span<std::byte> out) noexcept
277289{
278- if (!bytes ) return ;
290+ if (out. empty () ) return ;
279291 if (m_bufleft) {
280- unsigned reuse = std::min<size_t >(m_bufleft, bytes );
281- memcpy (c, m_buffer + 64 - m_bufleft, reuse);
292+ unsigned reuse = std::min<size_t >(m_bufleft, out. size () );
293+ std::copy ( m_buffer. end () - m_bufleft, m_buffer. end () - m_bufleft + reuse, out. begin () );
282294 m_bufleft -= reuse;
283- bytes -= reuse;
284- c += reuse;
295+ out = out.subspan (reuse);
285296 }
286- if (bytes >= 64 ) {
287- size_t blocks = bytes / 64 ;
288- m_aligned.Keystream64 (c, blocks);
289- c += blocks * 64 ;
290- bytes -= blocks * 64 ;
297+ if (out.size () >= m_aligned.BLOCKLEN ) {
298+ size_t blocks = out.size () / m_aligned.BLOCKLEN ;
299+ m_aligned.Keystream (out.first (blocks * m_aligned.BLOCKLEN ));
300+ out = out.subspan (blocks * m_aligned.BLOCKLEN );
291301 }
292- if (bytes ) {
293- m_aligned.Keystream64 (m_buffer, 1 );
294- memcpy (c , m_buffer, bytes );
295- m_bufleft = 64 - bytes ;
302+ if (!out. empty () ) {
303+ m_aligned.Keystream (m_buffer);
304+ std::copy (m_buffer. begin () , m_buffer. begin () + out. size (), out. begin () );
305+ m_bufleft = m_aligned. BLOCKLEN - out. size () ;
296306 }
297307}
298308
299- void ChaCha20::Crypt (const unsigned char * m, unsigned char * c, size_t bytes)
309+ void ChaCha20::Crypt (Span< const std::byte> input, Span<std::byte> output) noexcept
300310{
301- if (!bytes) return ;
311+ assert (input.size () == output.size ());
312+
313+ if (!input.size ()) return ;
302314 if (m_bufleft) {
303- unsigned reuse = std::min<size_t >(m_bufleft, bytes );
315+ unsigned reuse = std::min<size_t >(m_bufleft, input. size () );
304316 for (unsigned i = 0 ; i < reuse; i++) {
305- c [i] = m [i] ^ m_buffer[64 - m_bufleft + i];
317+ output [i] = input [i] ^ m_buffer[m_aligned. BLOCKLEN - m_bufleft + i];
306318 }
307319 m_bufleft -= reuse;
308- bytes -= reuse;
309- c += reuse;
310- m += reuse;
320+ output = output.subspan (reuse);
321+ input = input.subspan (reuse);
311322 }
312- if (bytes >= 64 ) {
313- size_t blocks = bytes / 64 ;
314- m_aligned.Crypt64 (m, c, blocks);
315- c += blocks * 64 ;
316- m += blocks * 64 ;
317- bytes -= blocks * 64 ;
323+ if (input.size () >= m_aligned.BLOCKLEN ) {
324+ size_t blocks = input.size () / m_aligned.BLOCKLEN ;
325+ m_aligned.Crypt (input.first (blocks * m_aligned.BLOCKLEN ), output.first (blocks * m_aligned.BLOCKLEN ));
326+ output = output.subspan (blocks * m_aligned.BLOCKLEN );
327+ input = input.subspan (blocks * m_aligned.BLOCKLEN );
318328 }
319- if (bytes ) {
320- m_aligned.Keystream64 (m_buffer, 1 );
321- for (unsigned i = 0 ; i < bytes ; i++) {
322- c [i] = m [i] ^ m_buffer[i];
329+ if (!input. empty () ) {
330+ m_aligned.Keystream (m_buffer);
331+ for (unsigned i = 0 ; i < input. size () ; i++) {
332+ output [i] = input [i] ^ m_buffer[i];
323333 }
324- m_bufleft = 64 - bytes ;
334+ m_bufleft = m_aligned. BLOCKLEN - input. size () ;
325335 }
326336}
327337
328338ChaCha20::~ChaCha20 ()
329339{
330- memory_cleanse (m_buffer, sizeof ( m_buffer));
340+ memory_cleanse (m_buffer. data (), m_buffer. size ( ));
331341}
332342
333343FSChaCha20::FSChaCha20 (Span<const std::byte> key, uint32_t rekey_interval) noexcept :
334- m_chacha20(UCharCast( key.data()) ), m_rekey_interval(rekey_interval)
344+ m_chacha20(key), m_rekey_interval(rekey_interval)
335345{
336346 assert (key.size () == KEYLEN);
337347}
@@ -341,20 +351,20 @@ void FSChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noex
341351 assert (input.size () == output.size ());
342352
343353 // Invoke internal stream cipher for actual encryption/decryption.
344- m_chacha20.Crypt (UCharCast ( input. data ()), UCharCast ( output. data ()), input. size () );
354+ m_chacha20.Crypt (input, output);
345355
346356 // Rekey after m_rekey_interval encryptions/decryptions.
347357 if (++m_chunk_counter == m_rekey_interval) {
348358 // Get new key from the stream cipher.
349359 std::byte new_key[KEYLEN];
350- m_chacha20.Keystream (UCharCast ( new_key), sizeof (new_key) );
360+ m_chacha20.Keystream (new_key);
351361 // Update its key.
352- m_chacha20.SetKey32 ( UCharCast ( new_key) );
362+ m_chacha20.SetKey ( new_key);
353363 // Wipe the key (a copy remains inside m_chacha20, where it'll be wiped on the next rekey
354364 // or on destruction).
355365 memory_cleanse (new_key, sizeof (new_key));
356366 // Set the nonce for the new section of output.
357- m_chacha20.Seek64 ({0 , ++m_rekey_counter}, 0 );
367+ m_chacha20.Seek ({0 , ++m_rekey_counter}, 0 );
358368 // Reset the chunk counter.
359369 m_chunk_counter = 0 ;
360370 }
0 commit comments