8
8
#include < crypto/common.h>
9
9
#include < crypto/chacha20.h>
10
10
#include < support/cleanse.h>
11
+ #include < span.h>
11
12
12
13
#include < algorithm>
13
14
#include < string.h>
@@ -22,47 +23,47 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (
22
23
23
24
#define REPEAT10 (a ) do { {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; {a}; } while (0 )
24
25
25
- void ChaCha20Aligned::SetKey32 ( const unsigned char * k)
26
+ void ChaCha20Aligned::SetKey (Span< const std::byte> key) noexcept
26
27
{
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 ));
35
37
input[8 ] = 0 ;
36
38
input[9 ] = 0 ;
37
39
input[10 ] = 0 ;
38
40
input[11 ] = 0 ;
39
41
}
40
42
41
- ChaCha20Aligned::ChaCha20Aligned ()
42
- {
43
- memset (input, 0 , sizeof (input));
44
- }
45
-
46
43
ChaCha20Aligned::~ChaCha20Aligned ()
47
44
{
48
45
memory_cleanse (input, sizeof (input));
49
46
}
50
47
51
- ChaCha20Aligned::ChaCha20Aligned (const unsigned char * key32)
48
+ ChaCha20Aligned::ChaCha20Aligned (Span< const std::byte> key) noexcept
52
49
{
53
- SetKey32 (key32 );
50
+ SetKey (key );
54
51
}
55
52
56
- void ChaCha20Aligned::Seek64 (Nonce96 nonce, uint32_t block_counter)
53
+ void ChaCha20Aligned::Seek (Nonce96 nonce, uint32_t block_counter) noexcept
57
54
{
58
55
input[8 ] = block_counter;
59
56
input[9 ] = nonce.first ;
60
57
input[10 ] = nonce.second ;
61
58
input[11 ] = nonce.second >> 32 ;
62
59
}
63
60
64
- inline void ChaCha20Aligned::Keystream64 ( unsigned char * c, size_t blocks)
61
+ inline void ChaCha20Aligned::Keystream (Span<std::byte> output) noexcept
65
62
{
63
+ unsigned char * c = UCharCast (output.data ());
64
+ size_t blocks = output.size () / BLOCKLEN;
65
+ assert (blocks * BLOCKLEN == output.size ());
66
+
66
67
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
67
68
uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
68
69
@@ -154,12 +155,18 @@ inline void ChaCha20Aligned::Keystream64(unsigned char* c, size_t blocks)
154
155
return ;
155
156
}
156
157
blocks -= 1 ;
157
- c += 64 ;
158
+ c += BLOCKLEN ;
158
159
}
159
160
}
160
161
161
- inline void ChaCha20Aligned::Crypt64 ( const unsigned char * m, unsigned char * c, size_t blocks)
162
+ inline void ChaCha20Aligned::Crypt (Span< const std::byte> in_bytes, Span<std::byte> out_bytes) noexcept
162
163
{
164
+ assert (in_bytes.size () == out_bytes.size ());
165
+ const unsigned char * m = UCharCast (in_bytes.data ());
166
+ unsigned char * c = UCharCast (out_bytes.data ());
167
+ size_t blocks = out_bytes.size () / BLOCKLEN;
168
+ assert (blocks * BLOCKLEN == out_bytes.size ());
169
+
163
170
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
164
171
uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
165
172
@@ -268,70 +275,75 @@ inline void ChaCha20Aligned::Crypt64(const unsigned char* m, unsigned char* c, s
268
275
return ;
269
276
}
270
277
blocks -= 1 ;
271
- c += 64 ;
272
- m += 64 ;
278
+ c += BLOCKLEN ;
279
+ m += BLOCKLEN ;
273
280
}
274
281
}
275
282
276
- void ChaCha20::Keystream (unsigned char * c, size_t bytes)
283
+ void ChaCha20::Keystream (Span<std::byte> out) noexcept
277
284
{
278
- if (!bytes ) return ;
285
+ if (out. empty () ) return ;
279
286
if (m_bufleft) {
280
- unsigned reuse = std::min<size_t >(m_bufleft, bytes );
281
- memcpy (c, m_buffer + 64 - m_bufleft, reuse);
287
+ unsigned reuse = std::min<size_t >(m_bufleft, out. size () );
288
+ std::copy ( m_buffer. end () - m_bufleft, m_buffer. end () - m_bufleft + reuse, out. begin () );
282
289
m_bufleft -= reuse;
283
- bytes -= reuse;
284
- c += reuse;
290
+ out = out.subspan (reuse);
285
291
}
286
- if (bytes >= 64 ) {
287
- size_t blocks = bytes / 64 ;
288
- m_aligned.Keystream64 (c, blocks);
289
- c += blocks * 64 ;
290
- bytes -= blocks * 64 ;
292
+ if (out.size () >= m_aligned.BLOCKLEN ) {
293
+ size_t blocks = out.size () / m_aligned.BLOCKLEN ;
294
+ m_aligned.Keystream (out.first (blocks * m_aligned.BLOCKLEN ));
295
+ out = out.subspan (blocks * m_aligned.BLOCKLEN );
291
296
}
292
- if (bytes ) {
293
- m_aligned.Keystream64 (m_buffer, 1 );
294
- memcpy (c , m_buffer, bytes );
295
- m_bufleft = 64 - bytes ;
297
+ if (!out. empty () ) {
298
+ m_aligned.Keystream (m_buffer);
299
+ std::copy (m_buffer. begin () , m_buffer. begin () + out. size (), out. begin () );
300
+ m_bufleft = m_aligned. BLOCKLEN - out. size () ;
296
301
}
297
302
}
298
303
299
- void ChaCha20::Crypt (const unsigned char * m, unsigned char * c, size_t bytes)
304
+ void ChaCha20::Crypt (Span< const std::byte> input, Span<std::byte> output) noexcept
300
305
{
301
- if (!bytes) return ;
306
+ assert (input.size () == output.size ());
307
+
308
+ if (!input.size ()) return ;
302
309
if (m_bufleft) {
303
- unsigned reuse = std::min<size_t >(m_bufleft, bytes );
310
+ unsigned reuse = std::min<size_t >(m_bufleft, input. size () );
304
311
for (unsigned i = 0 ; i < reuse; i++) {
305
- c [i] = m [i] ^ m_buffer[64 - m_bufleft + i];
312
+ output [i] = input [i] ^ m_buffer[m_aligned. BLOCKLEN - m_bufleft + i];
306
313
}
307
314
m_bufleft -= reuse;
308
- bytes -= reuse;
309
- c += reuse;
310
- m += reuse;
315
+ output = output.subspan (reuse);
316
+ input = input.subspan (reuse);
311
317
}
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 ;
318
+ if (input.size () >= m_aligned.BLOCKLEN ) {
319
+ size_t blocks = input.size () / m_aligned.BLOCKLEN ;
320
+ m_aligned.Crypt (input.first (blocks * m_aligned.BLOCKLEN ), output.first (blocks * m_aligned.BLOCKLEN ));
321
+ output = output.subspan (blocks * m_aligned.BLOCKLEN );
322
+ input = input.subspan (blocks * m_aligned.BLOCKLEN );
318
323
}
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];
324
+ if (!input. empty () ) {
325
+ m_aligned.Keystream (m_buffer);
326
+ for (unsigned i = 0 ; i < input. size () ; i++) {
327
+ output [i] = input [i] ^ m_buffer[i];
323
328
}
324
- m_bufleft = 64 - bytes ;
329
+ m_bufleft = m_aligned. BLOCKLEN - input. size () ;
325
330
}
326
331
}
327
332
328
333
ChaCha20::~ChaCha20 ()
329
334
{
330
- memory_cleanse (m_buffer, sizeof (m_buffer));
335
+ memory_cleanse (m_buffer.data (), m_buffer.size ());
336
+ }
337
+
338
+ void ChaCha20::SetKey (Span<const std::byte> key) noexcept
339
+ {
340
+ m_aligned.SetKey (key);
341
+ m_bufleft = 0 ;
342
+ memory_cleanse (m_buffer.data (), m_buffer.size ());
331
343
}
332
344
333
345
FSChaCha20::FSChaCha20 (Span<const std::byte> key, uint32_t rekey_interval) noexcept :
334
- m_chacha20(UCharCast( key.data()) ), m_rekey_interval(rekey_interval)
346
+ m_chacha20(key), m_rekey_interval(rekey_interval)
335
347
{
336
348
assert (key.size () == KEYLEN);
337
349
}
@@ -341,20 +353,20 @@ void FSChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noex
341
353
assert (input.size () == output.size ());
342
354
343
355
// Invoke internal stream cipher for actual encryption/decryption.
344
- m_chacha20.Crypt (UCharCast ( input. data ()), UCharCast ( output. data ()), input. size () );
356
+ m_chacha20.Crypt (input, output);
345
357
346
358
// Rekey after m_rekey_interval encryptions/decryptions.
347
359
if (++m_chunk_counter == m_rekey_interval) {
348
360
// Get new key from the stream cipher.
349
361
std::byte new_key[KEYLEN];
350
- m_chacha20.Keystream (UCharCast ( new_key), sizeof (new_key) );
362
+ m_chacha20.Keystream (new_key);
351
363
// Update its key.
352
- m_chacha20.SetKey32 ( UCharCast ( new_key) );
364
+ m_chacha20.SetKey ( new_key);
353
365
// Wipe the key (a copy remains inside m_chacha20, where it'll be wiped on the next rekey
354
366
// or on destruction).
355
367
memory_cleanse (new_key, sizeof (new_key));
356
368
// Set the nonce for the new section of output.
357
- m_chacha20.Seek64 ({0 , ++m_rekey_counter}, 0 );
369
+ m_chacha20.Seek ({0 , ++m_rekey_counter}, 0 );
358
370
// Reset the chunk counter.
359
371
m_chunk_counter = 0 ;
360
372
}
0 commit comments