blob: 2e07f1ed46aad34be74c0b20d3603ffb0ca224c3 [file] [log] [blame]
Daniel King31ac12e2016-05-17 14:43:01 -03001/**
2 * \file aead_chacha20_poly1305.c
3 *
4 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
5 *
6 * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License"); you may
10 * not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 * This file is part of mbed TLS (https://tls.mbed.org)
22 */
23#if !defined(MBEDTLS_CONFIG_FILE)
24#include "mbedtls/config.h"
25#else
26#include MBEDTLS_CONFIG_FILE
27#endif
28
29#if defined(MBEDTLS_AEAD_CHACHA20_POLY1305_C)
30
31#include "mbedtls/aead_chacha20_poly1305.h"
32#include <string.h>
33
34#if defined(MBEDTLS_SELF_TEST)
35#if defined(MBEDTLS_PLATFORM_C)
36#include "mbedtls/platform.h"
37#else
38#include <stdio.h>
39#define mbedtls_printf printf
40#endif /* MBEDTLS_PLATFORM_C */
41#endif /* MBEDTLS_SELF_TEST */
42
43#if !defined(MBEDTLS_AEAD_CHACHA20_POLY1305_ALT)
44
45#define AEAD_CHACHA20_POLY1305_STATE_INIT ( 0 )
46#define AEAD_CHACHA20_POLY1305_STATE_AAD ( 1 )
47#define AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
48#define AEAD_CHACHA20_POLY1305_STATE_FINISHED ( 3 )
49
50/* Implementation that should never be optimized out by the compiler */
51static void mbedtls_zeroize( void *v, size_t n ) {
52 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
53}
54
55/**
56 * \brief Adds padding bytes (zeroes) to pad the AAD for Poly1305.
57 *
58 * \param ctx The ChaCha20-Poly1305 context.
59 */
60static void mbedtls_aead_chacha20_poly1305_pad_aad( mbedtls_aead_chacha20_poly1305_context *ctx )
61{
Daniel Kingf5892752016-05-24 11:16:17 -030062 uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
Daniel King31ac12e2016-05-17 14:43:01 -030063 unsigned char zeroes[15];
64
65 if ( partial_block_len > 0U )
66 {
Daniel Kingf5892752016-05-24 11:16:17 -030067 memset( zeroes, 0, sizeof( zeroes ) );
68 (void) mbedtls_poly1305_update( &ctx->poly1305_ctx,
69 16U - partial_block_len,
70 zeroes );
Daniel King31ac12e2016-05-17 14:43:01 -030071 }
72}
73
74/**
75 * \brief Adds padding bytes (zeroes) to pad the ciphertext for Poly1305.
76 *
77 * \param ctx The ChaCha20-Poly1305 context.
78 */
79static void mbedtls_aead_chacha20_poly1305_pad_ciphertext( mbedtls_aead_chacha20_poly1305_context *ctx )
80{
Daniel Kingf5892752016-05-24 11:16:17 -030081 uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
Daniel King31ac12e2016-05-17 14:43:01 -030082 unsigned char zeroes[15];
83
84 if ( partial_block_len > 0U )
85 {
Daniel Kingf5892752016-05-24 11:16:17 -030086 memset( zeroes, 0, sizeof( zeroes ) );
87 (void) mbedtls_poly1305_update( &ctx->poly1305_ctx,
88 16U - partial_block_len,
89 zeroes );
Daniel King31ac12e2016-05-17 14:43:01 -030090 }
91}
92
93void mbedtls_aead_chacha20_poly1305_init( mbedtls_aead_chacha20_poly1305_context *ctx )
94{
95 if ( ctx != NULL )
96 {
97 mbedtls_chacha20_init( &ctx->chacha20_ctx );
98 mbedtls_poly1305_init( &ctx->poly1305_ctx );
99 ctx->aad_len = 0U;
100 ctx->ciphertext_len = 0U;
101 ctx->state = AEAD_CHACHA20_POLY1305_STATE_INIT;
102 ctx->mode = MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT;
103 }
104}
105
106void mbedtls_aead_chacha20_poly1305_free( mbedtls_aead_chacha20_poly1305_context *ctx )
107{
108 if ( ctx != NULL )
109 {
110 mbedtls_chacha20_free( &ctx->chacha20_ctx );
111 mbedtls_poly1305_free( &ctx->poly1305_ctx );
112 ctx->aad_len = 0U;
113 ctx->ciphertext_len = 0U;
114 ctx->state = AEAD_CHACHA20_POLY1305_STATE_INIT;
115 ctx->mode = MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT;
116 }
117}
118
119int mbedtls_aead_chacha20_poly1305_setkey( mbedtls_aead_chacha20_poly1305_context *ctx,
120 const unsigned char key[32] )
121{
122 int result;
123
124 if ( ( ctx == NULL ) || ( key == NULL ) )
125 {
126 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
127 }
128
129 result = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
130
131 return( result );
132}
133
134int mbedtls_aead_chacha20_poly1305_starts( mbedtls_aead_chacha20_poly1305_context *ctx,
135 const unsigned char nonce[12],
136 mbedtls_aead_chacha20_poly1305_mode_t mode )
137{
138 int result;
139 unsigned char poly1305_key[64];
140
141 if ( ( ctx == NULL ) || ( nonce == NULL ) )
142 {
143 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
144 }
145
146 result = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 1U );
147 if ( result != 0 )
148 goto cleanup;
149
150 /* Generate the Poly1305 key by getting the ChaCha20 keystream output with counter = 0.
151 * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
152 * The other 256 bits are discarded.
153 */
154 result = mbedtls_chacha20_keystream_block( &ctx->chacha20_ctx, 0U, poly1305_key );
155 if ( result != 0 )
156 goto cleanup;
157
158 result = mbedtls_poly1305_setkey( &ctx->poly1305_ctx, poly1305_key );
159
160 if ( result == 0 )
161 {
162 ctx->aad_len = 0U;
163 ctx->ciphertext_len = 0U;
164 ctx->state = AEAD_CHACHA20_POLY1305_STATE_AAD;
165 ctx->mode = mode;
166 }
167
168cleanup:
169 mbedtls_zeroize( poly1305_key, 64U );
170 return( result );
171}
172
173int mbedtls_aead_chacha20_poly1305_update_aad( mbedtls_aead_chacha20_poly1305_context *ctx,
174 size_t aad_len,
175 const unsigned char *aad )
176{
Daniel Kingf28c2aa2016-05-17 15:56:26 -0300177 if ( ctx == NULL )
Daniel King31ac12e2016-05-17 14:43:01 -0300178 {
179 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
180 }
Daniel Kingf28c2aa2016-05-17 15:56:26 -0300181 else if ( ( aad_len > 0U ) && ( aad == NULL ) )
182 {
183 /* aad pointer is allowed to be NULL if aad_len == 0 */
184 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
185 }
Daniel King31ac12e2016-05-17 14:43:01 -0300186 else if ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_AAD )
187 {
Daniel Kingf5892752016-05-24 11:16:17 -0300188 return(MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
Daniel King31ac12e2016-05-17 14:43:01 -0300189 }
190
191 ctx->aad_len += aad_len;
192
Daniel Kingf5892752016-05-24 11:16:17 -0300193 return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad_len, aad ) );
Daniel King31ac12e2016-05-17 14:43:01 -0300194}
195
196int mbedtls_aead_chacha20_poly1305_update( mbedtls_aead_chacha20_poly1305_context *ctx,
197 size_t len,
198 const unsigned char *input,
199 unsigned char *output )
200{
201 if ( ( ctx == NULL ) || ( input == NULL ) || ( output == NULL ) )
202 {
203 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
204 }
Daniel Kingf28c2aa2016-05-17 15:56:26 -0300205 else if ( ( len > 0U ) && ( ( input == NULL ) || ( output == NULL ) ) )
206 {
207 /* input and output pointers are allowed to be NULL if len == 0 */
208 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
209 }
Daniel King31ac12e2016-05-17 14:43:01 -0300210 else if ( ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_AAD ) &&
211 ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT ) )
212 {
213 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
214 }
215
216 if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_AAD )
217 {
218 ctx->state = AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT;
219
220 mbedtls_aead_chacha20_poly1305_pad_aad( ctx );
221 }
222
223 ctx->ciphertext_len += len;
224
225 if ( ctx->mode == MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT )
226 {
227 /* Note: the following functions return an error only if one or more of
228 * the input pointers are NULL. Since we have checked their validity
229 * above, we can safety ignore the return value.
230 */
Daniel Kingf5892752016-05-24 11:16:17 -0300231 (void) mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
232 (void) mbedtls_poly1305_update( &ctx->poly1305_ctx, len, output );
Daniel King31ac12e2016-05-17 14:43:01 -0300233 }
234 else /* DECRYPT */
235 {
Daniel Kingf5892752016-05-24 11:16:17 -0300236 (void) mbedtls_poly1305_update( &ctx->poly1305_ctx, len, input );
237 (void) mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
Daniel King31ac12e2016-05-17 14:43:01 -0300238 }
239
240 return( 0 );
241}
242
243int mbedtls_aead_chacha20_poly1305_finish( mbedtls_aead_chacha20_poly1305_context *ctx,
244 unsigned char mac[16] )
245{
246 unsigned char len_block[16];
247
248 if ( ( ctx == NULL ) || ( mac == NULL ) )
249 {
250 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
251 }
252 else if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_INIT )
253 {
254 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
255 }
256
257 if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_AAD )
258 {
259 mbedtls_aead_chacha20_poly1305_pad_aad( ctx );
260 }
261 else if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT )
262 {
263 mbedtls_aead_chacha20_poly1305_pad_ciphertext( ctx );
264 }
265
266 ctx->state = AEAD_CHACHA20_POLY1305_STATE_FINISHED;
267
268 /* The lengths of the AAD and ciphertext are processed by
269 * Poly1305 as the final 128-bit block, encoded as little-endian integers.
270 */
Daniel Kingf5892752016-05-24 11:16:17 -0300271 len_block[0] = (unsigned char) ctx->aad_len;
272 len_block[1] = (unsigned char) ( ctx->aad_len >> 8 );
273 len_block[2] = (unsigned char) ( ctx->aad_len >> 16 );
274 len_block[3] = (unsigned char) ( ctx->aad_len >> 24 );
275 len_block[4] = (unsigned char) ( ctx->aad_len >> 32 );
276 len_block[5] = (unsigned char) ( ctx->aad_len >> 40 );
277 len_block[6] = (unsigned char) ( ctx->aad_len >> 48 );
278 len_block[7] = (unsigned char) ( ctx->aad_len >> 56 );
279 len_block[8] = (unsigned char) ctx->ciphertext_len;
280 len_block[9] = (unsigned char) ( ctx->ciphertext_len >> 8 );
281 len_block[10] = (unsigned char) ( ctx->ciphertext_len >> 16 );
282 len_block[11] = (unsigned char) ( ctx->ciphertext_len >> 24 );
283 len_block[12] = (unsigned char) ( ctx->ciphertext_len >> 32 );
284 len_block[13] = (unsigned char) ( ctx->ciphertext_len >> 40 );
285 len_block[14] = (unsigned char) ( ctx->ciphertext_len >> 48 );
286 len_block[15] = (unsigned char) ( ctx->ciphertext_len >> 56 );
Daniel King31ac12e2016-05-17 14:43:01 -0300287
Daniel Kingf5892752016-05-24 11:16:17 -0300288 (void) mbedtls_poly1305_update( &ctx->poly1305_ctx, 16U, len_block );
289 (void) mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
Daniel King31ac12e2016-05-17 14:43:01 -0300290
291 return( 0 );
292}
293
Daniel King31ac12e2016-05-17 14:43:01 -0300294int mbedtls_aead_chacha20_poly1305_crypt_and_mac ( const unsigned char key[32],
295 const unsigned char nonce[12],
296 mbedtls_aead_chacha20_poly1305_mode_t mode,
297 size_t aad_len,
298 const unsigned char *aad,
299 size_t ilen,
300 const unsigned char *input,
301 unsigned char *output,
302 unsigned char mac[16] )
303{
304 mbedtls_aead_chacha20_poly1305_context ctx;
305 int result;
306
307 mbedtls_aead_chacha20_poly1305_init( &ctx );
308
309 result = mbedtls_aead_chacha20_poly1305_setkey( &ctx, key );
310 if ( result != 0 )
311 goto cleanup;
312
313 result = mbedtls_aead_chacha20_poly1305_starts( &ctx, nonce, mode );
314 if ( result != 0 )
315 goto cleanup;
316
317 result = mbedtls_aead_chacha20_poly1305_update_aad( &ctx, aad_len, aad );
318 if ( result != 0 )
319 goto cleanup;
320
321 result = mbedtls_aead_chacha20_poly1305_update( &ctx, ilen, input, output );
322 if ( result != 0 )
323 goto cleanup;
324
325 result = mbedtls_aead_chacha20_poly1305_finish( &ctx, mac );
326
327cleanup:
328 mbedtls_aead_chacha20_poly1305_free( &ctx );
329 return( result );
330}
331
Manuel Pégourié-Gonnarddeda80e2018-05-07 09:58:35 +0200332#endif /* MBEDTLS_AEAD_CHACHA20_POLY1305_ALT */
333
Daniel King31ac12e2016-05-17 14:43:01 -0300334#if defined(MBEDTLS_SELF_TEST)
335
336static const unsigned char test_key[1][32] =
337{
338 {
339 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
340 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
341 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
342 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
343 }
344};
345
346static const unsigned char test_nonce[1][12] =
347{
348 {
349 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
350 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
351 }
352};
353
354static const unsigned char test_aad[1][12] =
355{
356 {
357 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
358 0xc4, 0xc5, 0xc6, 0xc7
359 }
360};
361
362static const size_t test_aad_len[1] =
363{
364 12U
365};
366
367static const unsigned char test_input[1][114] =
368{
369 {
370 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
371 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
372 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
373 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
374 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
375 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
376 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
377 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
378 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
379 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
380 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
381 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
382 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
383 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
384 0x74, 0x2e
385 }
386};
387
388static const unsigned char test_output[1][114] =
389{
390 {
391 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
392 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
393 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
394 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
395 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
396 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
397 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
398 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
399 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
400 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
401 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
402 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
403 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
404 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
405 0x61, 0x16
406 }
407};
408
409static const size_t test_input_len[1] =
410{
411 114U
412};
413
414static const unsigned char test_mac[1][16] =
415{
416 {
417 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
418 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
419 }
420};
421
422int mbedtls_aead_chacha20_poly1305_self_test( int verbose )
423{
424 size_t i;
425 int result;
426 unsigned char output[200];
427 unsigned char mac[16];
428
429 for ( i = 0U; i < 1U; i++ )
430 {
Daniel Kingd00afaf2016-05-18 10:07:53 -0300431 if ( verbose != 0 )
432 {
Daniel King47252c72016-05-19 09:57:59 -0300433 mbedtls_printf( " ChaCha20-Poly1305 test %zu ", i );
Daniel Kingd00afaf2016-05-18 10:07:53 -0300434 }
435
Daniel King31ac12e2016-05-17 14:43:01 -0300436 result = mbedtls_aead_chacha20_poly1305_crypt_and_mac( test_key[i],
437 test_nonce[i],
438 MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT,
439 test_aad_len[i],
440 test_aad[i],
441 test_input_len[i],
442 test_input[i],
443 output,
444 mac );
445 if ( result != 0 )
446 {
447 if ( verbose != 0 )
448 {
Daniel Kingd00afaf2016-05-18 10:07:53 -0300449 mbedtls_printf( "error code: %i\n", result );
Daniel King31ac12e2016-05-17 14:43:01 -0300450 }
451 return( -1 );
452 }
453
454 if ( memcmp( output, test_output[i], test_input_len[i] ) != 0 )
455 {
456 if ( verbose != 0 )
457 {
Daniel Kingd00afaf2016-05-18 10:07:53 -0300458 mbedtls_printf( "failure (wrong output)\n" );
Daniel King31ac12e2016-05-17 14:43:01 -0300459 }
460 return( -1 );
461 }
462
463 if ( memcmp( mac, test_mac[i], 16U ) != 0 )
464 {
465 if ( verbose != 0 )
466 {
Daniel Kingd00afaf2016-05-18 10:07:53 -0300467 mbedtls_printf( "failure (wrong MAC)\n" );
Daniel King31ac12e2016-05-17 14:43:01 -0300468 }
469 return( -1 );
470 }
Daniel Kingd00afaf2016-05-18 10:07:53 -0300471
472 if ( verbose != 0 )
473 {
474 mbedtls_printf( "passed\n" );
475 }
476 }
477
478 if( verbose != 0 )
479 {
480 mbedtls_printf( "\n" );
Daniel King31ac12e2016-05-17 14:43:01 -0300481 }
482
483 return( 0 );
484}
485
486#endif /* MBEDTLS_SELF_TEST */
487
488#endif /* MBEDTLS_AEAD_CHACHA20_POLY1305_C */