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