Line data Source code
1 : /* chacha20.c - Bernstein's ChaCha20 cipher
2 : * Copyright (C) 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser general Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : *
19 : * For a description of the algorithm, see:
20 : * http://cr.yp.to/chacha.html
21 : */
22 :
23 : /* The code is based on salsa20.c and public-domain ChaCha implementations:
24 : * chacha-ref.c version 20080118
25 : * D. J. Bernstein
26 : * Public domain.
27 : * and
28 : * Andrew Moon
29 : * https://github.com/floodyberry/chacha-opt
30 : */
31 :
32 :
33 : #include <config.h>
34 : #include <stdio.h>
35 : #include <stdlib.h>
36 : #include <string.h>
37 : #include "types.h"
38 : #include "g10lib.h"
39 : #include "cipher.h"
40 : #include "bufhelp.h"
41 :
42 :
43 : #define CHACHA20_MIN_KEY_SIZE 16 /* Bytes. */
44 : #define CHACHA20_MAX_KEY_SIZE 32 /* Bytes. */
45 : #define CHACHA20_BLOCK_SIZE 64 /* Bytes. */
46 : #define CHACHA20_MIN_IV_SIZE 8 /* Bytes. */
47 : #define CHACHA20_MAX_IV_SIZE 12 /* Bytes. */
48 : #define CHACHA20_CTR_SIZE 16 /* Bytes. */
49 : #define CHACHA20_INPUT_LENGTH (CHACHA20_BLOCK_SIZE / 4)
50 :
51 : /* USE_SSE2 indicates whether to compile with Intel SSE2 code. */
52 : #undef USE_SSE2
53 : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
54 : defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
55 : # define USE_SSE2 1
56 : #endif
57 :
58 : /* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */
59 : #undef USE_SSSE3
60 : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
61 : defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
62 : defined(HAVE_GCC_INLINE_ASM_SSSE3)
63 : # define USE_SSSE3 1
64 : #endif
65 :
66 : /* USE_AVX2 indicates whether to compile with Intel AVX2 code. */
67 : #undef USE_AVX2
68 : #if defined(__x86_64__) && (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
69 : defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)) && \
70 : defined(ENABLE_AVX2_SUPPORT)
71 : # define USE_AVX2 1
72 : #endif
73 :
74 : /* USE_NEON indicates whether to enable ARM NEON assembly code. */
75 : #undef USE_NEON
76 : #ifdef ENABLE_NEON_SUPPORT
77 : # if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \
78 : && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \
79 : && defined(HAVE_GCC_INLINE_ASM_NEON)
80 : # define USE_NEON 1
81 : # endif
82 : #endif /*ENABLE_NEON_SUPPORT*/
83 :
84 :
85 : struct CHACHA20_context_s;
86 :
87 :
88 : /* Assembly implementations use SystemV ABI, ABI conversion and additional
89 : * stack to store XMM6-XMM15 needed on Win64. */
90 : #undef ASM_FUNC_ABI
91 : #undef ASM_EXTRA_STACK
92 : #if (defined(USE_SSE2) || defined(USE_SSSE3) || defined(USE_AVX2)) && \
93 : defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)
94 : # define ASM_FUNC_ABI __attribute__((sysv_abi))
95 : # define ASM_EXTRA_STACK (10 * 16)
96 : #else
97 : # define ASM_FUNC_ABI
98 : # define ASM_EXTRA_STACK 0
99 : #endif
100 :
101 :
102 : typedef unsigned int (* chacha20_blocks_t)(u32 *state, const byte *src,
103 : byte *dst,
104 : size_t bytes) ASM_FUNC_ABI;
105 :
106 : typedef struct CHACHA20_context_s
107 : {
108 : u32 input[CHACHA20_INPUT_LENGTH];
109 : u32 pad[CHACHA20_INPUT_LENGTH];
110 : chacha20_blocks_t blocks;
111 : unsigned int unused; /* bytes in the pad. */
112 : } CHACHA20_context_t;
113 :
114 :
115 : #ifdef USE_SSE2
116 :
117 : unsigned int _gcry_chacha20_amd64_sse2_blocks(u32 *state, const byte *in,
118 : byte *out,
119 : size_t bytes) ASM_FUNC_ABI;
120 :
121 : #endif /* USE_SSE2 */
122 :
123 : #ifdef USE_SSSE3
124 :
125 : unsigned int _gcry_chacha20_amd64_ssse3_blocks(u32 *state, const byte *in,
126 : byte *out,
127 : size_t bytes) ASM_FUNC_ABI;
128 :
129 : #endif /* USE_SSSE3 */
130 :
131 : #ifdef USE_AVX2
132 :
133 : unsigned int _gcry_chacha20_amd64_avx2_blocks(u32 *state, const byte *in,
134 : byte *out,
135 : size_t bytes) ASM_FUNC_ABI;
136 :
137 : #endif /* USE_AVX2 */
138 :
139 : #ifdef USE_NEON
140 :
141 : unsigned int _gcry_chacha20_armv7_neon_blocks(u32 *state, const byte *in,
142 : byte *out,
143 : size_t bytes) ASM_FUNC_ABI;
144 :
145 : #endif /* USE_NEON */
146 :
147 :
148 : static void chacha20_setiv (void *context, const byte * iv, size_t ivlen);
149 : static const char *selftest (void);
150 :
151 :
152 :
153 : #define QROUND(a,b,c,d) \
154 : do { \
155 : a += b; d = rol(d ^ a, 16); \
156 : c += d; b = rol(b ^ c, 12); \
157 : a += b; d = rol(d ^ a, 8); \
158 : c += d; b = rol(b ^ c, 7); \
159 : } while (0)
160 :
161 : #define QOUT(ai, bi, ci, di) \
162 : DO_OUT(ai); DO_OUT(bi); DO_OUT(ci); DO_OUT(di)
163 :
164 :
165 : #ifndef USE_SSE2
166 : ASM_FUNC_ABI static unsigned int
167 : chacha20_blocks (u32 *state, const byte *src, byte *dst, size_t bytes)
168 : {
169 : u32 pad[CHACHA20_INPUT_LENGTH];
170 : u32 inp[CHACHA20_INPUT_LENGTH];
171 : unsigned int i;
172 :
173 : /* Note: 'bytes' must be multiple of 64 and not zero. */
174 :
175 : inp[0] = state[0];
176 : inp[1] = state[1];
177 : inp[2] = state[2];
178 : inp[3] = state[3];
179 : inp[4] = state[4];
180 : inp[5] = state[5];
181 : inp[6] = state[6];
182 : inp[7] = state[7];
183 : inp[8] = state[8];
184 : inp[9] = state[9];
185 : inp[10] = state[10];
186 : inp[11] = state[11];
187 : inp[12] = state[12];
188 : inp[13] = state[13];
189 : inp[14] = state[14];
190 : inp[15] = state[15];
191 :
192 : do
193 : {
194 : /* First round. */
195 : pad[0] = inp[0];
196 : pad[4] = inp[4];
197 : pad[8] = inp[8];
198 : pad[12] = inp[12];
199 : QROUND (pad[0], pad[4], pad[8], pad[12]);
200 : pad[1] = inp[1];
201 : pad[5] = inp[5];
202 : pad[9] = inp[9];
203 : pad[13] = inp[13];
204 : QROUND (pad[1], pad[5], pad[9], pad[13]);
205 : pad[2] = inp[2];
206 : pad[6] = inp[6];
207 : pad[10] = inp[10];
208 : pad[14] = inp[14];
209 : QROUND (pad[2], pad[6], pad[10], pad[14]);
210 : pad[3] = inp[3];
211 : pad[7] = inp[7];
212 : pad[11] = inp[11];
213 : pad[15] = inp[15];
214 : QROUND (pad[3], pad[7], pad[11], pad[15]);
215 :
216 : QROUND (pad[0], pad[5], pad[10], pad[15]);
217 : QROUND (pad[1], pad[6], pad[11], pad[12]);
218 : QROUND (pad[2], pad[7], pad[8], pad[13]);
219 : QROUND (pad[3], pad[4], pad[9], pad[14]);
220 :
221 : for (i = 2; i < 20 - 2; i += 2)
222 : {
223 : QROUND (pad[0], pad[4], pad[8], pad[12]);
224 : QROUND (pad[1], pad[5], pad[9], pad[13]);
225 : QROUND (pad[2], pad[6], pad[10], pad[14]);
226 : QROUND (pad[3], pad[7], pad[11], pad[15]);
227 :
228 : QROUND (pad[0], pad[5], pad[10], pad[15]);
229 : QROUND (pad[1], pad[6], pad[11], pad[12]);
230 : QROUND (pad[2], pad[7], pad[8], pad[13]);
231 : QROUND (pad[3], pad[4], pad[9], pad[14]);
232 : }
233 :
234 : QROUND (pad[0], pad[4], pad[8], pad[12]);
235 : QROUND (pad[1], pad[5], pad[9], pad[13]);
236 : QROUND (pad[2], pad[6], pad[10], pad[14]);
237 : QROUND (pad[3], pad[7], pad[11], pad[15]);
238 :
239 : if (src)
240 : {
241 : #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, \
242 : (pad[idx] + inp[idx]) ^ \
243 : buf_get_le32(src + (idx) * 4))
244 : /* Last round. */
245 : QROUND (pad[0], pad[5], pad[10], pad[15]);
246 : QOUT(0, 5, 10, 15);
247 : QROUND (pad[1], pad[6], pad[11], pad[12]);
248 : QOUT(1, 6, 11, 12);
249 : QROUND (pad[2], pad[7], pad[8], pad[13]);
250 : QOUT(2, 7, 8, 13);
251 : QROUND (pad[3], pad[4], pad[9], pad[14]);
252 : QOUT(3, 4, 9, 14);
253 : #undef DO_OUT
254 : }
255 : else
256 : {
257 : #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, pad[idx] + inp[idx])
258 : /* Last round. */
259 : QROUND (pad[0], pad[5], pad[10], pad[15]);
260 : QOUT(0, 5, 10, 15);
261 : QROUND (pad[1], pad[6], pad[11], pad[12]);
262 : QOUT(1, 6, 11, 12);
263 : QROUND (pad[2], pad[7], pad[8], pad[13]);
264 : QOUT(2, 7, 8, 13);
265 : QROUND (pad[3], pad[4], pad[9], pad[14]);
266 : QOUT(3, 4, 9, 14);
267 : #undef DO_OUT
268 : }
269 :
270 : /* Update counter. */
271 : inp[13] += (!++inp[12]);
272 :
273 : bytes -= CHACHA20_BLOCK_SIZE;
274 : dst += CHACHA20_BLOCK_SIZE;
275 : src += (src) ? CHACHA20_BLOCK_SIZE : 0;
276 : }
277 : while (bytes >= CHACHA20_BLOCK_SIZE);
278 :
279 : state[12] = inp[12];
280 : state[13] = inp[13];
281 :
282 : /* burn_stack */
283 : return (2 * CHACHA20_INPUT_LENGTH * sizeof(u32) + 6 * sizeof(void *));
284 : }
285 : #endif /*!USE_SSE2*/
286 :
287 : #undef QROUND
288 : #undef QOUT
289 :
290 :
291 : static unsigned int
292 0 : chacha20_core(u32 *dst, struct CHACHA20_context_s *ctx)
293 : {
294 0 : return ctx->blocks(ctx->input, NULL, (byte *)dst, CHACHA20_BLOCK_SIZE)
295 0 : + ASM_EXTRA_STACK;
296 : }
297 :
298 :
299 : static void
300 0 : chacha20_keysetup (CHACHA20_context_t * ctx, const byte * key,
301 : unsigned int keylen)
302 : {
303 : /* These constants are the little endian encoding of the string
304 : "expand 32-byte k". For the 128 bit variant, the "32" in that
305 : string will be fixed up to "16". */
306 0 : ctx->input[0] = 0x61707865; /* "apxe" */
307 0 : ctx->input[1] = 0x3320646e; /* "3 dn" */
308 0 : ctx->input[2] = 0x79622d32; /* "yb-2" */
309 0 : ctx->input[3] = 0x6b206574; /* "k et" */
310 :
311 0 : ctx->input[4] = buf_get_le32 (key + 0);
312 0 : ctx->input[5] = buf_get_le32 (key + 4);
313 0 : ctx->input[6] = buf_get_le32 (key + 8);
314 0 : ctx->input[7] = buf_get_le32 (key + 12);
315 :
316 0 : if (keylen == CHACHA20_MAX_KEY_SIZE) /* 256 bits */
317 : {
318 0 : ctx->input[8] = buf_get_le32 (key + 16);
319 0 : ctx->input[9] = buf_get_le32 (key + 20);
320 0 : ctx->input[10] = buf_get_le32 (key + 24);
321 0 : ctx->input[11] = buf_get_le32 (key + 28);
322 : }
323 : else /* 128 bits */
324 : {
325 0 : ctx->input[8] = ctx->input[4];
326 0 : ctx->input[9] = ctx->input[5];
327 0 : ctx->input[10] = ctx->input[6];
328 0 : ctx->input[11] = ctx->input[7];
329 :
330 0 : ctx->input[1] -= 0x02000000; /* Change to "1 dn". */
331 0 : ctx->input[2] += 0x00000004; /* Change to "yb-6". */
332 : }
333 0 : }
334 :
335 :
336 : static void
337 0 : chacha20_ivsetup (CHACHA20_context_t * ctx, const byte * iv, size_t ivlen)
338 : {
339 0 : if (ivlen == CHACHA20_CTR_SIZE)
340 : {
341 0 : ctx->input[12] = buf_get_le32 (iv + 0);
342 0 : ctx->input[13] = buf_get_le32 (iv + 4);
343 0 : ctx->input[14] = buf_get_le32 (iv + 8);
344 0 : ctx->input[15] = buf_get_le32 (iv + 12);
345 : }
346 0 : else if (ivlen == CHACHA20_MAX_IV_SIZE)
347 : {
348 0 : ctx->input[12] = 0;
349 0 : ctx->input[13] = buf_get_le32 (iv + 0);
350 0 : ctx->input[14] = buf_get_le32 (iv + 4);
351 0 : ctx->input[15] = buf_get_le32 (iv + 8);
352 : }
353 0 : else if (ivlen == CHACHA20_MIN_IV_SIZE)
354 : {
355 0 : ctx->input[12] = 0;
356 0 : ctx->input[13] = 0;
357 0 : ctx->input[14] = buf_get_le32 (iv + 0);
358 0 : ctx->input[15] = buf_get_le32 (iv + 4);
359 : }
360 : else
361 : {
362 0 : ctx->input[12] = 0;
363 0 : ctx->input[13] = 0;
364 0 : ctx->input[14] = 0;
365 0 : ctx->input[15] = 0;
366 : }
367 0 : }
368 :
369 :
370 : static gcry_err_code_t
371 0 : chacha20_do_setkey (CHACHA20_context_t * ctx,
372 : const byte * key, unsigned int keylen)
373 : {
374 : static int initialized;
375 : static const char *selftest_failed;
376 0 : unsigned int features = _gcry_get_hw_features ();
377 :
378 0 : if (!initialized)
379 : {
380 0 : initialized = 1;
381 0 : selftest_failed = selftest ();
382 0 : if (selftest_failed)
383 0 : log_error ("CHACHA20 selftest failed (%s)\n", selftest_failed);
384 : }
385 0 : if (selftest_failed)
386 0 : return GPG_ERR_SELFTEST_FAILED;
387 :
388 0 : if (keylen != CHACHA20_MAX_KEY_SIZE && keylen != CHACHA20_MIN_KEY_SIZE)
389 0 : return GPG_ERR_INV_KEYLEN;
390 :
391 : #ifdef USE_SSE2
392 0 : ctx->blocks = _gcry_chacha20_amd64_sse2_blocks;
393 : #else
394 : ctx->blocks = chacha20_blocks;
395 : #endif
396 :
397 : #ifdef USE_SSSE3
398 0 : if (features & HWF_INTEL_SSSE3)
399 0 : ctx->blocks = _gcry_chacha20_amd64_ssse3_blocks;
400 : #endif
401 : #ifdef USE_AVX2
402 0 : if (features & HWF_INTEL_AVX2)
403 0 : ctx->blocks = _gcry_chacha20_amd64_avx2_blocks;
404 : #endif
405 : #ifdef USE_NEON
406 : if (features & HWF_ARM_NEON)
407 : ctx->blocks = _gcry_chacha20_armv7_neon_blocks;
408 : #endif
409 :
410 : (void)features;
411 :
412 0 : chacha20_keysetup (ctx, key, keylen);
413 :
414 : /* We default to a zero nonce. */
415 0 : chacha20_setiv (ctx, NULL, 0);
416 :
417 0 : return 0;
418 : }
419 :
420 :
421 : static gcry_err_code_t
422 0 : chacha20_setkey (void *context, const byte * key, unsigned int keylen)
423 : {
424 0 : CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
425 0 : gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen);
426 0 : _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
427 0 : return rc;
428 : }
429 :
430 :
431 : static void
432 0 : chacha20_setiv (void *context, const byte * iv, size_t ivlen)
433 : {
434 0 : CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
435 :
436 : /* draft-nir-cfrg-chacha20-poly1305-02 defines 96-bit and 64-bit nonce. */
437 0 : if (iv && ivlen != CHACHA20_MAX_IV_SIZE && ivlen != CHACHA20_MIN_IV_SIZE
438 0 : && ivlen != CHACHA20_CTR_SIZE)
439 0 : log_info ("WARNING: chacha20_setiv: bad ivlen=%u\n", (u32) ivlen);
440 :
441 0 : if (iv && (ivlen == CHACHA20_MAX_IV_SIZE || ivlen == CHACHA20_MIN_IV_SIZE
442 0 : || ivlen == CHACHA20_CTR_SIZE))
443 0 : chacha20_ivsetup (ctx, iv, ivlen);
444 : else
445 0 : chacha20_ivsetup (ctx, NULL, 0);
446 :
447 : /* Reset the unused pad bytes counter. */
448 0 : ctx->unused = 0;
449 0 : }
450 :
451 :
452 :
453 : /* Note: This function requires LENGTH > 0. */
454 : static void
455 0 : chacha20_do_encrypt_stream (CHACHA20_context_t * ctx,
456 : byte * outbuf, const byte * inbuf, size_t length)
457 : {
458 0 : unsigned int nburn, burn = 0;
459 :
460 0 : if (ctx->unused)
461 : {
462 0 : unsigned char *p = (void *) ctx->pad;
463 : size_t n;
464 :
465 0 : gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
466 :
467 0 : n = ctx->unused;
468 0 : if (n > length)
469 0 : n = length;
470 0 : buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
471 0 : length -= n;
472 0 : outbuf += n;
473 0 : inbuf += n;
474 0 : ctx->unused -= n;
475 0 : if (!length)
476 0 : return;
477 0 : gcry_assert (!ctx->unused);
478 : }
479 :
480 0 : if (length >= CHACHA20_BLOCK_SIZE)
481 : {
482 0 : size_t nblocks = length / CHACHA20_BLOCK_SIZE;
483 0 : size_t bytes = nblocks * CHACHA20_BLOCK_SIZE;
484 0 : burn = ctx->blocks(ctx->input, inbuf, outbuf, bytes);
485 0 : length -= bytes;
486 0 : outbuf += bytes;
487 0 : inbuf += bytes;
488 : }
489 :
490 0 : if (length > 0)
491 : {
492 0 : nburn = chacha20_core (ctx->pad, ctx);
493 0 : burn = nburn > burn ? nburn : burn;
494 :
495 0 : buf_xor (outbuf, inbuf, ctx->pad, length);
496 0 : ctx->unused = CHACHA20_BLOCK_SIZE - length;
497 : }
498 :
499 0 : _gcry_burn_stack (burn);
500 : }
501 :
502 :
503 : static void
504 0 : chacha20_encrypt_stream (void *context, byte * outbuf, const byte * inbuf,
505 : size_t length)
506 : {
507 0 : CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
508 :
509 0 : if (length)
510 0 : chacha20_do_encrypt_stream (ctx, outbuf, inbuf, length);
511 0 : }
512 :
513 :
514 : static const char *
515 0 : selftest (void)
516 : {
517 : byte ctxbuf[sizeof(CHACHA20_context_t) + 15];
518 : CHACHA20_context_t *ctx;
519 : byte scratch[127 + 1];
520 : byte buf[512 + 64 + 4];
521 : int i;
522 :
523 : /* From draft-strombergson-chacha-test-vectors */
524 : static byte key_1[] = {
525 : 0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78,
526 : 0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35,
527 : 0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb,
528 : 0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d
529 : };
530 : static const byte nonce_1[] =
531 : { 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21 };
532 : static const byte plaintext_1[127] = {
533 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
538 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
539 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
540 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
541 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
542 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
543 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
546 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
547 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
548 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
549 : };
550 : static const byte ciphertext_1[127] = {
551 : 0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9,
552 : 0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06,
553 : 0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00,
554 : 0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf,
555 : 0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd,
556 : 0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f,
557 : 0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f,
558 : 0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92,
559 : 0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9,
560 : 0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36,
561 : 0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1,
562 : 0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38,
563 : 0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea,
564 : 0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0,
565 : 0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27,
566 : 0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33
567 : };
568 :
569 : /* 16-byte alignment required for amd64 implementation. */
570 0 : ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15);
571 :
572 0 : chacha20_setkey (ctx, key_1, sizeof key_1);
573 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
574 0 : scratch[sizeof (scratch) - 1] = 0;
575 0 : chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1);
576 0 : if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
577 0 : return "ChaCha20 encryption test 1 failed.";
578 0 : if (scratch[sizeof (scratch) - 1])
579 0 : return "ChaCha20 wrote too much.";
580 0 : chacha20_setkey (ctx, key_1, sizeof (key_1));
581 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
582 0 : chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1);
583 0 : if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
584 0 : return "ChaCha20 decryption test 1 failed.";
585 :
586 0 : for (i = 0; i < sizeof buf; i++)
587 0 : buf[i] = i;
588 0 : chacha20_setkey (ctx, key_1, sizeof key_1);
589 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
590 : /*encrypt */
591 0 : chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
592 : /*decrypt */
593 0 : chacha20_setkey (ctx, key_1, sizeof key_1);
594 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
595 0 : chacha20_encrypt_stream (ctx, buf, buf, 1);
596 0 : chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1);
597 0 : chacha20_encrypt_stream (ctx, buf + (sizeof buf) - 1,
598 : buf + (sizeof buf) - 1, 1);
599 0 : for (i = 0; i < sizeof buf; i++)
600 0 : if (buf[i] != (byte) i)
601 0 : return "ChaCha20 encryption test 2 failed.";
602 :
603 0 : chacha20_setkey (ctx, key_1, sizeof key_1);
604 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
605 : /* encrypt */
606 0 : for (i = 0; i < sizeof buf; i++)
607 0 : chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1);
608 : /* decrypt */
609 0 : chacha20_setkey (ctx, key_1, sizeof key_1);
610 0 : chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
611 0 : chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
612 0 : for (i = 0; i < sizeof buf; i++)
613 0 : if (buf[i] != (byte) i)
614 0 : return "ChaCha20 encryption test 3 failed.";
615 :
616 0 : return NULL;
617 : }
618 :
619 :
620 : gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = {
621 : GCRY_CIPHER_CHACHA20,
622 : {0, 0}, /* flags */
623 : "CHACHA20", /* name */
624 : NULL, /* aliases */
625 : NULL, /* oids */
626 : 1, /* blocksize in bytes. */
627 : CHACHA20_MAX_KEY_SIZE * 8, /* standard key length in bits. */
628 : sizeof (CHACHA20_context_t),
629 : chacha20_setkey,
630 : NULL,
631 : NULL,
632 : chacha20_encrypt_stream,
633 : chacha20_encrypt_stream,
634 : NULL,
635 : NULL,
636 : chacha20_setiv
637 : };
|