blob: ab29dfa1b1700f2aee4a6ccbecdc7b73126670fd [file] [log] [blame]
Daniel Kingb8025c52016-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{
62 uint32_t partial_block_len = (uint32_t)( ctx->aad_len % 16U );
63 unsigned char zeroes[15];
64
65 if ( partial_block_len > 0U )
66 {
67 memset( zeroes, 0, sizeof(zeroes) );
68 (void)mbedtls_poly1305_update( &ctx->poly1305_ctx,
69 16U - partial_block_len,
70 zeroes );
71 }
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{
81 uint32_t partial_block_len = (uint32_t)( ctx->ciphertext_len % 16U );
82 unsigned char zeroes[15];
83
84 if ( partial_block_len > 0U )
85 {
86 memset( zeroes, 0, sizeof(zeroes) );
87 (void)mbedtls_poly1305_update( &ctx->poly1305_ctx,
88 16U - partial_block_len,
89 zeroes );
90 }
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{
177 if ( ( ctx == NULL ) || ( aad == NULL ) )
178 {
179 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
180 }
181 else if ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_AAD )
182 {
183 return (MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
184 }
185
186 ctx->aad_len += aad_len;
187
188 return ( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad_len, aad ) );
189}
190
191int mbedtls_aead_chacha20_poly1305_update( mbedtls_aead_chacha20_poly1305_context *ctx,
192 size_t len,
193 const unsigned char *input,
194 unsigned char *output )
195{
196 if ( ( ctx == NULL ) || ( input == NULL ) || ( output == NULL ) )
197 {
198 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
199 }
200 else if ( ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_AAD ) &&
201 ( ctx->state != AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT ) )
202 {
203 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
204 }
205
206 if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_AAD )
207 {
208 ctx->state = AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT;
209
210 mbedtls_aead_chacha20_poly1305_pad_aad( ctx );
211 }
212
213 ctx->ciphertext_len += len;
214
215 if ( ctx->mode == MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT )
216 {
217 /* Note: the following functions return an error only if one or more of
218 * the input pointers are NULL. Since we have checked their validity
219 * above, we can safety ignore the return value.
220 */
221 (void)mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
222 (void)mbedtls_poly1305_update( &ctx->poly1305_ctx, len, output );
223 }
224 else /* DECRYPT */
225 {
226 (void)mbedtls_poly1305_update( &ctx->poly1305_ctx, len, input );
227 (void)mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
228 }
229
230 return( 0 );
231}
232
233int mbedtls_aead_chacha20_poly1305_finish( mbedtls_aead_chacha20_poly1305_context *ctx,
234 unsigned char mac[16] )
235{
236 unsigned char len_block[16];
237
238 if ( ( ctx == NULL ) || ( mac == NULL ) )
239 {
240 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_INPUT_DATA );
241 }
242 else if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_INIT )
243 {
244 return( MBEDTLS_ERR_AEAD_CHACHA20_POLY1305_BAD_STATE );
245 }
246
247 if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_AAD )
248 {
249 mbedtls_aead_chacha20_poly1305_pad_aad( ctx );
250 }
251 else if ( ctx->state == AEAD_CHACHA20_POLY1305_STATE_CIPHERTEXT )
252 {
253 mbedtls_aead_chacha20_poly1305_pad_ciphertext( ctx );
254 }
255
256 ctx->state = AEAD_CHACHA20_POLY1305_STATE_FINISHED;
257
258 /* The lengths of the AAD and ciphertext are processed by
259 * Poly1305 as the final 128-bit block, encoded as little-endian integers.
260 */
261 len_block[0] = (unsigned char)ctx->aad_len;
262 len_block[1] = (unsigned char)( ctx->aad_len >> 8 );
263 len_block[2] = (unsigned char)( ctx->aad_len >> 16 );
264 len_block[3] = (unsigned char)( ctx->aad_len >> 24 );
265 len_block[4] = (unsigned char)( ctx->aad_len >> 32 );
266 len_block[5] = (unsigned char)( ctx->aad_len >> 40 );
267 len_block[6] = (unsigned char)( ctx->aad_len >> 48 );
268 len_block[7] = (unsigned char)( ctx->aad_len >> 56 );
269 len_block[8] = (unsigned char)ctx->ciphertext_len;
270 len_block[9] = (unsigned char)( ctx->ciphertext_len >> 8 );
271 len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
272 len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
273 len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
274 len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
275 len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
276 len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
277
278 (void)mbedtls_poly1305_update( &ctx->poly1305_ctx, 16U, len_block );
279 (void)mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
280
281 return( 0 );
282}
283
284#endif /* MBEDTLS_AEAD_CHACHA20_POLY1305_ALT */
285
286int mbedtls_aead_chacha20_poly1305_crypt_and_mac ( const unsigned char key[32],
287 const unsigned char nonce[12],
288 mbedtls_aead_chacha20_poly1305_mode_t mode,
289 size_t aad_len,
290 const unsigned char *aad,
291 size_t ilen,
292 const unsigned char *input,
293 unsigned char *output,
294 unsigned char mac[16] )
295{
296 mbedtls_aead_chacha20_poly1305_context ctx;
297 int result;
298
299 mbedtls_aead_chacha20_poly1305_init( &ctx );
300
301 result = mbedtls_aead_chacha20_poly1305_setkey( &ctx, key );
302 if ( result != 0 )
303 goto cleanup;
304
305 result = mbedtls_aead_chacha20_poly1305_starts( &ctx, nonce, mode );
306 if ( result != 0 )
307 goto cleanup;
308
309 result = mbedtls_aead_chacha20_poly1305_update_aad( &ctx, aad_len, aad );
310 if ( result != 0 )
311 goto cleanup;
312
313 result = mbedtls_aead_chacha20_poly1305_update( &ctx, ilen, input, output );
314 if ( result != 0 )
315 goto cleanup;
316
317 result = mbedtls_aead_chacha20_poly1305_finish( &ctx, mac );
318
319cleanup:
320 mbedtls_aead_chacha20_poly1305_free( &ctx );
321 return( result );
322}
323
324#if defined(MBEDTLS_SELF_TEST)
325
326static const unsigned char test_key[1][32] =
327{
328 {
329 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
330 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
331 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
332 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
333 }
334};
335
336static const unsigned char test_nonce[1][12] =
337{
338 {
339 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
340 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
341 }
342};
343
344static const unsigned char test_aad[1][12] =
345{
346 {
347 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
348 0xc4, 0xc5, 0xc6, 0xc7
349 }
350};
351
352static const size_t test_aad_len[1] =
353{
354 12U
355};
356
357static const unsigned char test_input[1][114] =
358{
359 {
360 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
361 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
362 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
363 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
364 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
365 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
366 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
367 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
368 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
369 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
370 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
371 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
372 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
373 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
374 0x74, 0x2e
375 }
376};
377
378static const unsigned char test_output[1][114] =
379{
380 {
381 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
382 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
383 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
384 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
385 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
386 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
387 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
388 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
389 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
390 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
391 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
392 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
393 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
394 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
395 0x61, 0x16
396 }
397};
398
399static const size_t test_input_len[1] =
400{
401 114U
402};
403
404static const unsigned char test_mac[1][16] =
405{
406 {
407 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
408 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
409 }
410};
411
412int mbedtls_aead_chacha20_poly1305_self_test( int verbose )
413{
414 size_t i;
415 int result;
416 unsigned char output[200];
417 unsigned char mac[16];
418
419 for ( i = 0U; i < 1U; i++ )
420 {
421 result = mbedtls_aead_chacha20_poly1305_crypt_and_mac( test_key[i],
422 test_nonce[i],
423 MBEDTLS_AEAD_CHACHA20_POLY1305_ENCRYPT,
424 test_aad_len[i],
425 test_aad[i],
426 test_input_len[i],
427 test_input[i],
428 output,
429 mac );
430 if ( result != 0 )
431 {
432 if ( verbose != 0 )
433 {
434 mbedtls_printf( "ChaCha20-Poly1305 test %zi error code: %i\n", i, result );
435 }
436 return( -1 );
437 }
438
439 if ( memcmp( output, test_output[i], test_input_len[i] ) != 0 )
440 {
441 if ( verbose != 0 )
442 {
443 mbedtls_printf( "ChaCha20-Poly1305 test %zi failure (wrong output)\n", i );
444 }
445 return( -1 );
446 }
447
448 if ( memcmp( mac, test_mac[i], 16U ) != 0 )
449 {
450 if ( verbose != 0 )
451 {
452 mbedtls_printf( "ChaCha20-Poly1305 test %zi failure (wrong MAC)\n", i );
453 }
454 return( -1 );
455 }
456 }
457
458 return( 0 );
459}
460
461#endif /* MBEDTLS_SELF_TEST */
462
463#endif /* MBEDTLS_AEAD_CHACHA20_POLY1305_C */