88#include < crypto/common.h>
99#include < crypto/chacha20.h>
1010
11+ #include < algorithm>
1112#include < string.h>
1213
1314constexpr static inline uint32_t rotl32 (uint32_t v, int c) { return (v << c) | (v >> (32 - c)); }
@@ -23,7 +24,7 @@ constexpr static inline uint32_t rotl32(uint32_t v, int c) { return (v << c) | (
2324static const unsigned char sigma[] = " expand 32-byte k" ;
2425static const unsigned char tau[] = " expand 16-byte k" ;
2526
26- void ChaCha20 ::SetKey (const unsigned char * k, size_t keylen)
27+ void ChaCha20Aligned ::SetKey (const unsigned char * k, size_t keylen)
2728{
2829 const unsigned char *constants;
2930
@@ -51,37 +52,34 @@ void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
5152 input[15 ] = 0 ;
5253}
5354
54- ChaCha20::ChaCha20 ()
55+ ChaCha20Aligned::ChaCha20Aligned ()
5556{
5657 memset (input, 0 , sizeof (input));
5758}
5859
59- ChaCha20::ChaCha20 (const unsigned char * k, size_t keylen)
60+ ChaCha20Aligned::ChaCha20Aligned (const unsigned char * k, size_t keylen)
6061{
6162 SetKey (k, keylen);
6263}
6364
64- void ChaCha20 ::SetIV (uint64_t iv)
65+ void ChaCha20Aligned ::SetIV (uint64_t iv)
6566{
6667 input[14 ] = iv;
6768 input[15 ] = iv >> 32 ;
6869}
6970
70- void ChaCha20 ::Seek (uint64_t pos)
71+ void ChaCha20Aligned ::Seek (uint64_t pos)
7172{
7273 input[12 ] = pos;
7374 input[13 ] = pos >> 32 ;
7475}
7576
76- void ChaCha20::Keystream (unsigned char * c, size_t bytes )
77+ inline void ChaCha20Aligned::Keystream64 (unsigned char * c, size_t blocks )
7778{
7879 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
7980 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
80- unsigned char *ctarget = nullptr ;
81- unsigned char tmp[64 ];
82- unsigned int i;
8381
84- if (!bytes ) return ;
82+ if (!blocks ) return ;
8583
8684 j0 = input[0 ];
8785 j1 = input[1 ];
@@ -101,10 +99,6 @@ void ChaCha20::Keystream(unsigned char* c, size_t bytes)
10199 j15 = input[15 ];
102100
103101 for (;;) {
104- if (bytes < 64 ) {
105- ctarget = c;
106- c = tmp;
107- }
108102 x0 = j0;
109103 x1 = j1;
110104 x2 = j2;
@@ -171,28 +165,22 @@ void ChaCha20::Keystream(unsigned char* c, size_t bytes)
171165 WriteLE32 (c + 56 , x14);
172166 WriteLE32 (c + 60 , x15);
173167
174- if (bytes <= 64 ) {
175- if (bytes < 64 ) {
176- for (i = 0 ;i < bytes;++i) ctarget[i] = c[i];
177- }
168+ if (blocks == 1 ) {
178169 input[12 ] = j12;
179170 input[13 ] = j13;
180171 return ;
181172 }
182- bytes -= 64 ;
173+ blocks -= 1 ;
183174 c += 64 ;
184175 }
185176}
186177
187- void ChaCha20::Crypt (const unsigned char * m, unsigned char * c, size_t bytes )
178+ inline void ChaCha20Aligned::Crypt64 (const unsigned char * m, unsigned char * c, size_t blocks )
188179{
189180 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
190181 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
191- unsigned char *ctarget = nullptr ;
192- unsigned char tmp[64 ];
193- unsigned int i;
194182
195- if (!bytes ) return ;
183+ if (!blocks ) return ;
196184
197185 j0 = input[0 ];
198186 j1 = input[1 ];
@@ -212,14 +200,6 @@ void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
212200 j15 = input[15 ];
213201
214202 for (;;) {
215- if (bytes < 64 ) {
216- // if m has fewer than 64 bytes available, copy m to tmp and
217- // read from tmp instead
218- for (i = 0 ;i < bytes;++i) tmp[i] = m[i];
219- m = tmp;
220- ctarget = c;
221- c = tmp;
222- }
223203 x0 = j0;
224204 x1 = j1;
225205 x2 = j2;
@@ -303,16 +283,48 @@ void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
303283 WriteLE32 (c + 56 , x14);
304284 WriteLE32 (c + 60 , x15);
305285
306- if (bytes <= 64 ) {
307- if (bytes < 64 ) {
308- for (i = 0 ;i < bytes;++i) ctarget[i] = c[i];
309- }
286+ if (blocks == 1 ) {
310287 input[12 ] = j12;
311288 input[13 ] = j13;
312289 return ;
313290 }
314- bytes -= 64 ;
291+ blocks -= 1 ;
315292 c += 64 ;
316293 m += 64 ;
317294 }
318295}
296+
297+ void ChaCha20::Keystream (unsigned char * c, size_t bytes)
298+ {
299+ if (!bytes) return ;
300+ if (bytes >= 64 ) {
301+ size_t blocks = bytes / 64 ;
302+ m_aligned.Keystream64 (c, blocks);
303+ c += blocks * 64 ;
304+ bytes -= blocks * 64 ;
305+ }
306+ if (bytes) {
307+ unsigned char buffer[64 ];
308+ m_aligned.Keystream64 (buffer, 1 );
309+ memcpy (c, buffer, bytes);
310+ }
311+ }
312+
313+ void ChaCha20::Crypt (const unsigned char * m, unsigned char * c, size_t bytes)
314+ {
315+ if (!bytes) return ;
316+ if (bytes >= 64 ) {
317+ size_t blocks = bytes / 64 ;
318+ m_aligned.Crypt64 (m, c, blocks);
319+ c += blocks * 64 ;
320+ m += blocks * 64 ;
321+ bytes -= blocks * 64 ;
322+ }
323+ if (bytes) {
324+ unsigned char buffer[64 ];
325+ m_aligned.Keystream64 (buffer, 1 );
326+ for (unsigned i = 0 ; i < bytes; i++) {
327+ c[i] = m[i] ^ buffer[i];
328+ }
329+ }
330+ }
0 commit comments