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,23 +23,24 @@ 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 ()
43
+ ChaCha20Aligned::ChaCha20Aligned () noexcept
42
44
{
43
45
memset (input, 0 , sizeof (input));
44
46
}
@@ -48,21 +50,25 @@ ChaCha20Aligned::~ChaCha20Aligned()
48
50
memory_cleanse (input, sizeof (input));
49
51
}
50
52
51
- ChaCha20Aligned::ChaCha20Aligned (const unsigned char * key32)
53
+ ChaCha20Aligned::ChaCha20Aligned (Span< const std::byte> key) noexcept
52
54
{
53
- SetKey32 (key32 );
55
+ SetKey (key );
54
56
}
55
57
56
- void ChaCha20Aligned::Seek64 (Nonce96 nonce, uint32_t block_counter)
58
+ void ChaCha20Aligned::Seek (Nonce96 nonce, uint32_t block_counter) noexcept
57
59
{
58
60
input[8 ] = block_counter;
59
61
input[9 ] = nonce.first ;
60
62
input[10 ] = nonce.second ;
61
63
input[11 ] = nonce.second >> 32 ;
62
64
}
63
65
64
- inline void ChaCha20Aligned::Keystream64 ( unsigned char * c, size_t blocks)
66
+ inline void ChaCha20Aligned::Keystream (Span<std::byte> output) noexcept
65
67
{
68
+ unsigned char * c = UCharCast (output.data ());
69
+ size_t blocks = output.size () / BLOCKLEN;
70
+ assert (blocks * BLOCKLEN == output.size ());
71
+
66
72
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
67
73
uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
68
74
@@ -154,12 +160,18 @@ inline void ChaCha20Aligned::Keystream64(unsigned char* c, size_t blocks)
154
160
return ;
155
161
}
156
162
blocks -= 1 ;
157
- c += 64 ;
163
+ c += BLOCKLEN ;
158
164
}
159
165
}
160
166
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
162
168
{
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
+
163
175
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
164
176
uint32_t j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
165
177
@@ -268,70 +280,68 @@ inline void ChaCha20Aligned::Crypt64(const unsigned char* m, unsigned char* c, s
268
280
return ;
269
281
}
270
282
blocks -= 1 ;
271
- c += 64 ;
272
- m += 64 ;
283
+ c += BLOCKLEN ;
284
+ m += BLOCKLEN ;
273
285
}
274
286
}
275
287
276
- void ChaCha20::Keystream (unsigned char * c, size_t bytes)
288
+ void ChaCha20::Keystream (Span<std::byte> out) noexcept
277
289
{
278
- if (!bytes ) return ;
290
+ if (out. empty () ) return ;
279
291
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 () );
282
294
m_bufleft -= reuse;
283
- bytes -= reuse;
284
- c += reuse;
295
+ out = out.subspan (reuse);
285
296
}
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 );
291
301
}
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 () ;
296
306
}
297
307
}
298
308
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
300
310
{
301
- if (!bytes) return ;
311
+ assert (input.size () == output.size ());
312
+
313
+ if (!input.size ()) return ;
302
314
if (m_bufleft) {
303
- unsigned reuse = std::min<size_t >(m_bufleft, bytes );
315
+ unsigned reuse = std::min<size_t >(m_bufleft, input. size () );
304
316
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];
306
318
}
307
319
m_bufleft -= reuse;
308
- bytes -= reuse;
309
- c += reuse;
310
- m += reuse;
320
+ output = output.subspan (reuse);
321
+ input = input.subspan (reuse);
311
322
}
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 );
318
328
}
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];
323
333
}
324
- m_bufleft = 64 - bytes ;
334
+ m_bufleft = m_aligned. BLOCKLEN - input. size () ;
325
335
}
326
336
}
327
337
328
338
ChaCha20::~ChaCha20 ()
329
339
{
330
- memory_cleanse (m_buffer, sizeof ( m_buffer));
340
+ memory_cleanse (m_buffer. data (), m_buffer. size ( ));
331
341
}
332
342
333
343
FSChaCha20::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)
335
345
{
336
346
assert (key.size () == KEYLEN);
337
347
}
@@ -341,20 +351,20 @@ void FSChaCha20::Crypt(Span<const std::byte> input, Span<std::byte> output) noex
341
351
assert (input.size () == output.size ());
342
352
343
353
// 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);
345
355
346
356
// Rekey after m_rekey_interval encryptions/decryptions.
347
357
if (++m_chunk_counter == m_rekey_interval) {
348
358
// Get new key from the stream cipher.
349
359
std::byte new_key[KEYLEN];
350
- m_chacha20.Keystream (UCharCast ( new_key), sizeof (new_key) );
360
+ m_chacha20.Keystream (new_key);
351
361
// Update its key.
352
- m_chacha20.SetKey32 ( UCharCast ( new_key) );
362
+ m_chacha20.SetKey ( new_key);
353
363
// Wipe the key (a copy remains inside m_chacha20, where it'll be wiped on the next rekey
354
364
// or on destruction).
355
365
memory_cleanse (new_key, sizeof (new_key));
356
366
// 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 );
358
368
// Reset the chunk counter.
359
369
m_chunk_counter = 0 ;
360
370
}
0 commit comments