1/**
2 * \file chacha20.c
3 *
4 * \brief ChaCha20 cipher.
5 *
6 * \author Daniel King <damaki.gh@gmail.com>
7 *
8 * Copyright The Mbed TLS Contributors
9 * SPDX-License-Identifier: Apache-2.0
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License"); you may
12 * not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24#include "common.h"
25
26#if defined(MBEDTLS_CHACHA20_C)
27
28#include "mbedtls/chacha20.h"
29#include "mbedtls/platform_util.h"
30#include "mbedtls/error.h"
31
32#include <stddef.h>
33#include <string.h>
34
35#include "mbedtls/platform.h"
36
37#if !defined(MBEDTLS_CHACHA20_ALT)
38
39/* Parameter validation macros */
40#define CHACHA20_VALIDATE_RET(cond) \
41 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA)
42#define CHACHA20_VALIDATE(cond) \
43 MBEDTLS_INTERNAL_VALIDATE(cond)
44
45#define ROTL32(value, amount) \
46 ((uint32_t) ((value) << (amount)) | ((value) >> (32 - (amount))))
47
48#define CHACHA20_CTR_INDEX (12U)
49
50#define CHACHA20_BLOCK_SIZE_BYTES (4U * 16U)
51
52/**
53 * \brief ChaCha20 quarter round operation.
54 *
55 * The quarter round is defined as follows (from RFC 7539):
56 * 1. a += b; d ^= a; d <<<= 16;
57 * 2. c += d; b ^= c; b <<<= 12;
58 * 3. a += b; d ^= a; d <<<= 8;
59 * 4. c += d; b ^= c; b <<<= 7;
60 *
61 * \param state ChaCha20 state to modify.
62 * \param a The index of 'a' in the state.
63 * \param b The index of 'b' in the state.
64 * \param c The index of 'c' in the state.
65 * \param d The index of 'd' in the state.
66 */
67static inline void chacha20_quarter_round(uint32_t state[16],
68 size_t a,
69 size_t b,
70 size_t c,
71 size_t d)
72{
73 /* a += b; d ^= a; d <<<= 16; */
74 state[a] += state[b];
75 state[d] ^= state[a];
76 state[d] = ROTL32(state[d], 16);
77
78 /* c += d; b ^= c; b <<<= 12 */
79 state[c] += state[d];
80 state[b] ^= state[c];
81 state[b] = ROTL32(state[b], 12);
82
83 /* a += b; d ^= a; d <<<= 8; */
84 state[a] += state[b];
85 state[d] ^= state[a];
86 state[d] = ROTL32(state[d], 8);
87
88 /* c += d; b ^= c; b <<<= 7; */
89 state[c] += state[d];
90 state[b] ^= state[c];
91 state[b] = ROTL32(state[b], 7);
92}
93
94/**
95 * \brief Perform the ChaCha20 inner block operation.
96 *
97 * This function performs two rounds: the column round and the
98 * diagonal round.
99 *
100 * \param state The ChaCha20 state to update.
101 */
102static void chacha20_inner_block(uint32_t state[16])
103{
104 chacha20_quarter_round(state, 0, 4, 8, 12);
105 chacha20_quarter_round(state, 1, 5, 9, 13);
106 chacha20_quarter_round(state, 2, 6, 10, 14);
107 chacha20_quarter_round(state, 3, 7, 11, 15);
108
109 chacha20_quarter_round(state, 0, 5, 10, 15);
110 chacha20_quarter_round(state, 1, 6, 11, 12);
111 chacha20_quarter_round(state, 2, 7, 8, 13);
112 chacha20_quarter_round(state, 3, 4, 9, 14);
113}
114
115/**
116 * \brief Generates a keystream block.
117 *
118 * \param initial_state The initial ChaCha20 state (key, nonce, counter).
119 * \param keystream Generated keystream bytes are written to this buffer.
120 */
121static void chacha20_block(const uint32_t initial_state[16],
122 unsigned char keystream[64])
123{
124 uint32_t working_state[16];
125 size_t i;
126
127 memcpy(working_state,
128 initial_state,
129 CHACHA20_BLOCK_SIZE_BYTES);
130
131 for (i = 0U; i < 10U; i++) {
132 chacha20_inner_block(working_state);
133 }
134
135 working_state[0] += initial_state[0];
136 working_state[1] += initial_state[1];
137 working_state[2] += initial_state[2];
138 working_state[3] += initial_state[3];
139 working_state[4] += initial_state[4];
140 working_state[5] += initial_state[5];
141 working_state[6] += initial_state[6];
142 working_state[7] += initial_state[7];
143 working_state[8] += initial_state[8];
144 working_state[9] += initial_state[9];
145 working_state[10] += initial_state[10];
146 working_state[11] += initial_state[11];
147 working_state[12] += initial_state[12];
148 working_state[13] += initial_state[13];
149 working_state[14] += initial_state[14];
150 working_state[15] += initial_state[15];
151
152 for (i = 0U; i < 16; i++) {
153 size_t offset = i * 4U;
154
155 MBEDTLS_PUT_UINT32_LE(working_state[i], keystream, offset);
156 }
157
158 mbedtls_platform_zeroize(working_state, sizeof(working_state));
159}
160
161void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx)
162{
163 CHACHA20_VALIDATE(ctx != NULL);
164
165 mbedtls_platform_zeroize(ctx->state, sizeof(ctx->state));
166 mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));
167
168 /* Initially, there's no keystream bytes available */
169 ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
170}
171
172void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx)
173{
174 if (ctx != NULL) {
175 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_chacha20_context));
176 }
177}
178
179int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx,
180 const unsigned char key[32])
181{
182 CHACHA20_VALIDATE_RET(ctx != NULL);
183 CHACHA20_VALIDATE_RET(key != NULL);
184
185 /* ChaCha20 constants - the string "expand 32-byte k" */
186 ctx->state[0] = 0x61707865;
187 ctx->state[1] = 0x3320646e;
188 ctx->state[2] = 0x79622d32;
189 ctx->state[3] = 0x6b206574;
190
191 /* Set key */
192 ctx->state[4] = MBEDTLS_GET_UINT32_LE(key, 0);
193 ctx->state[5] = MBEDTLS_GET_UINT32_LE(key, 4);
194 ctx->state[6] = MBEDTLS_GET_UINT32_LE(key, 8);
195 ctx->state[7] = MBEDTLS_GET_UINT32_LE(key, 12);
196 ctx->state[8] = MBEDTLS_GET_UINT32_LE(key, 16);
197 ctx->state[9] = MBEDTLS_GET_UINT32_LE(key, 20);
198 ctx->state[10] = MBEDTLS_GET_UINT32_LE(key, 24);
199 ctx->state[11] = MBEDTLS_GET_UINT32_LE(key, 28);
200
201 return 0;
202}
203
204int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx,
205 const unsigned char nonce[12],
206 uint32_t counter)
207{
208 CHACHA20_VALIDATE_RET(ctx != NULL);
209 CHACHA20_VALIDATE_RET(nonce != NULL);
210
211 /* Counter */
212 ctx->state[12] = counter;
213
214 /* Nonce */
215 ctx->state[13] = MBEDTLS_GET_UINT32_LE(nonce, 0);
216 ctx->state[14] = MBEDTLS_GET_UINT32_LE(nonce, 4);
217 ctx->state[15] = MBEDTLS_GET_UINT32_LE(nonce, 8);
218
219 mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));
220
221 /* Initially, there's no keystream bytes available */
222 ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
223
224 return 0;
225}
226
227int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx,
228 size_t size,
229 const unsigned char *input,
230 unsigned char *output)
231{
232 size_t offset = 0U;
233 size_t i;
234
235 CHACHA20_VALIDATE_RET(ctx != NULL);
236 CHACHA20_VALIDATE_RET(size == 0 || input != NULL);
237 CHACHA20_VALIDATE_RET(size == 0 || output != NULL);
238
239 /* Use leftover keystream bytes, if available */
240 while (size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES) {
241 output[offset] = input[offset]
242 ^ ctx->keystream8[ctx->keystream_bytes_used];
243
244 ctx->keystream_bytes_used++;
245 offset++;
246 size--;
247 }
248
249 /* Process full blocks */
250 while (size >= CHACHA20_BLOCK_SIZE_BYTES) {
251 /* Generate new keystream block and increment counter */
252 chacha20_block(ctx->state, ctx->keystream8);
253 ctx->state[CHACHA20_CTR_INDEX]++;
254
255 for (i = 0U; i < 64U; i += 8U) {
256 output[offset + i] = input[offset + i] ^ ctx->keystream8[i];
257 output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1];
258 output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2];
259 output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3];
260 output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4];
261 output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5];
262 output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6];
263 output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7];
264 }
265
266 offset += CHACHA20_BLOCK_SIZE_BYTES;
267 size -= CHACHA20_BLOCK_SIZE_BYTES;
268 }
269
270 /* Last (partial) block */
271 if (size > 0U) {
272 /* Generate new keystream block and increment counter */
273 chacha20_block(ctx->state, ctx->keystream8);
274 ctx->state[CHACHA20_CTR_INDEX]++;
275
276 for (i = 0U; i < size; i++) {
277 output[offset + i] = input[offset + i] ^ ctx->keystream8[i];
278 }
279
280 ctx->keystream_bytes_used = size;
281
282 }
283
284 return 0;
285}
286
287int mbedtls_chacha20_crypt(const unsigned char key[32],
288 const unsigned char nonce[12],
289 uint32_t counter,
290 size_t data_len,
291 const unsigned char *input,
292 unsigned char *output)
293{
294 mbedtls_chacha20_context ctx;
295 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
296
297 CHACHA20_VALIDATE_RET(key != NULL);
298 CHACHA20_VALIDATE_RET(nonce != NULL);
299 CHACHA20_VALIDATE_RET(data_len == 0 || input != NULL);
300 CHACHA20_VALIDATE_RET(data_len == 0 || output != NULL);
301
302 mbedtls_chacha20_init(&ctx);
303
304 ret = mbedtls_chacha20_setkey(&ctx, key);
305 if (ret != 0) {
306 goto cleanup;
307 }
308
309 ret = mbedtls_chacha20_starts(&ctx, nonce, counter);
310 if (ret != 0) {
311 goto cleanup;
312 }
313
314 ret = mbedtls_chacha20_update(&ctx, data_len, input, output);
315
316cleanup:
317 mbedtls_chacha20_free(&ctx);
318 return ret;
319}
320
321#endif /* !MBEDTLS_CHACHA20_ALT */
322
323#if defined(MBEDTLS_SELF_TEST)
324
325static const unsigned char test_keys[2][32] =
326{
327 {
328 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
332 },
333 {
334 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
336 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
338 }
339};
340
341static const unsigned char test_nonces[2][12] =
342{
343 {
344 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
345 0x00, 0x00, 0x00, 0x00
346 },
347 {
348 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349 0x00, 0x00, 0x00, 0x02
350 }
351};
352
353static const uint32_t test_counters[2] =
354{
355 0U,
356 1U
357};
358
359static const unsigned char test_input[2][375] =
360{
361 {
362 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
370 },
371 {
372 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d,
373 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74,
374 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45,
375 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
376 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
377 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72,
378 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66,
379 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69,
380 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
381 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72,
382 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66,
383 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46,
384 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
385 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20,
386 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61,
387 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73,
388 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
389 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69,
390 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
391 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
392 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49,
393 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69,
394 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,
395 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72,
396 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49,
397 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74,
398 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
399 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20,
400 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
401 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75,
402 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20,
403 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
404 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45,
405 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69,
406 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20,
407 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20,
408 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20,
409 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63,
410 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63,
411 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,
412 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61,
413 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e,
414 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f,
415 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c,
416 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61,
417 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
418 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f
419 }
420};
421
422static const unsigned char test_output[2][375] =
423{
424 {
425 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
426 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
427 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
428 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
429 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
430 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
431 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
432 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86
433 },
434 {
435 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde,
436 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70,
437 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd,
438 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec,
439 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,
440 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05,
441 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f,
442 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d,
443 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa,
444 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,
445 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7,
446 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50,
447 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05,
448 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c,
449 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,
450 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a,
451 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0,
452 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66,
453 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4,
454 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,
455 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91,
456 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28,
457 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87,
458 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b,
459 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,
460 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f,
461 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76,
462 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c,
463 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b,
464 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,
465 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd,
466 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b,
467 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe,
468 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0,
469 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,
470 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f,
471 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3,
472 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62,
473 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91,
474 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,
475 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64,
476 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85,
477 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41,
478 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab,
479 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,
480 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd,
481 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21
482 }
483};
484
485static const size_t test_lengths[2] =
486{
487 64U,
488 375U
489};
490
491/* Make sure no other definition is already present. */
492#undef ASSERT
493
494#define ASSERT(cond, args) \
495 do \
496 { \
497 if (!(cond)) \
498 { \
499 if (verbose != 0) \
500 mbedtls_printf args; \
501 \
502 return -1; \
503 } \
504 } \
505 while (0)
506
507int mbedtls_chacha20_self_test(int verbose)
508{
509 unsigned char output[381];
510 unsigned i;
511 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
512
513 for (i = 0U; i < 2U; i++) {
514 if (verbose != 0) {
515 mbedtls_printf(" ChaCha20 test %u ", i);
516 }
517
518 ret = mbedtls_chacha20_crypt(test_keys[i],
519 test_nonces[i],
520 test_counters[i],
521 test_lengths[i],
522 test_input[i],
523 output);
524
525 ASSERT(0 == ret, ("error code: %i\n", ret));
526
527 ASSERT(0 == memcmp(output, test_output[i], test_lengths[i]),
528 ("failed (output)\n"));
529
530 if (verbose != 0) {
531 mbedtls_printf("passed\n");
532 }
533 }
534
535 if (verbose != 0) {
536 mbedtls_printf("\n");
537 }
538
539 return 0;
540}
541
542#endif /* MBEDTLS_SELF_TEST */
543
544#endif /* !MBEDTLS_CHACHA20_C */
545