1 /**
2 * \file chachapoly.c
3 *
4 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
5 *
6 * Copyright The Mbed TLS Contributors
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 #include "common.h"
22
23 #if defined(MBEDTLS_CHACHAPOLY_C)
24
25 #include "mbedtls/chachapoly.h"
26 #include "mbedtls/platform_util.h"
27 #include "mbedtls/error.h"
28
29 #include <string.h>
30
31 #include "mbedtls/platform.h"
32
33 #if !defined(MBEDTLS_CHACHAPOLY_ALT)
34
35 #define CHACHAPOLY_STATE_INIT ( 0 )
36 #define CHACHAPOLY_STATE_AAD ( 1 )
37 #define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
38 #define CHACHAPOLY_STATE_FINISHED ( 3 )
39
40 /**
41 * \brief Adds nul bytes to pad the AAD for Poly1305.
42 *
43 * \param ctx The ChaCha20-Poly1305 context.
44 */
chachapoly_pad_aad(mbedtls_chachapoly_context * ctx)45 static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
46 {
47 uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
48 unsigned char zeroes[15];
49
50 if( partial_block_len == 0U )
51 return( 0 );
52
53 memset( zeroes, 0, sizeof( zeroes ) );
54
55 return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
56 zeroes,
57 16U - partial_block_len ) );
58 }
59
60 /**
61 * \brief Adds nul bytes to pad the ciphertext for Poly1305.
62 *
63 * \param ctx The ChaCha20-Poly1305 context.
64 */
chachapoly_pad_ciphertext(mbedtls_chachapoly_context * ctx)65 static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
66 {
67 uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
68 unsigned char zeroes[15];
69
70 if( partial_block_len == 0U )
71 return( 0 );
72
73 memset( zeroes, 0, sizeof( zeroes ) );
74 return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
75 zeroes,
76 16U - partial_block_len ) );
77 }
78
mbedtls_chachapoly_init(mbedtls_chachapoly_context * ctx)79 void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
80 {
81 mbedtls_chacha20_init( &ctx->chacha20_ctx );
82 mbedtls_poly1305_init( &ctx->poly1305_ctx );
83 ctx->aad_len = 0U;
84 ctx->ciphertext_len = 0U;
85 ctx->state = CHACHAPOLY_STATE_INIT;
86 ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
87 }
88
mbedtls_chachapoly_free(mbedtls_chachapoly_context * ctx)89 void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
90 {
91 if( ctx == NULL )
92 return;
93
94 mbedtls_chacha20_free( &ctx->chacha20_ctx );
95 mbedtls_poly1305_free( &ctx->poly1305_ctx );
96 ctx->aad_len = 0U;
97 ctx->ciphertext_len = 0U;
98 ctx->state = CHACHAPOLY_STATE_INIT;
99 ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;
100 }
101
mbedtls_chachapoly_setkey(mbedtls_chachapoly_context * ctx,const unsigned char key[32])102 int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
103 const unsigned char key[32] )
104 {
105 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
106
107 ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
108
109 return( ret );
110 }
111
mbedtls_chachapoly_starts(mbedtls_chachapoly_context * ctx,const unsigned char nonce[12],mbedtls_chachapoly_mode_t mode)112 int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
113 const unsigned char nonce[12],
114 mbedtls_chachapoly_mode_t mode )
115 {
116 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
117 unsigned char poly1305_key[64];
118
119 /* Set counter = 0, will be update to 1 when generating Poly1305 key */
120 ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
121 if( ret != 0 )
122 goto cleanup;
123
124 /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
125 * counter = 0. This is the same as encrypting a buffer of zeroes.
126 * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
127 * The other 256 bits are discarded.
128 */
129 memset( poly1305_key, 0, sizeof( poly1305_key ) );
130 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
131 poly1305_key, poly1305_key );
132 if( ret != 0 )
133 goto cleanup;
134
135 ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
136
137 if( ret == 0 )
138 {
139 ctx->aad_len = 0U;
140 ctx->ciphertext_len = 0U;
141 ctx->state = CHACHAPOLY_STATE_AAD;
142 ctx->mode = mode;
143 }
144
145 cleanup:
146 mbedtls_platform_zeroize( poly1305_key, 64U );
147 return( ret );
148 }
149
mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context * ctx,const unsigned char * aad,size_t aad_len)150 int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
151 const unsigned char *aad,
152 size_t aad_len )
153 {
154 if( ctx->state != CHACHAPOLY_STATE_AAD )
155 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
156
157 ctx->aad_len += aad_len;
158
159 return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
160 }
161
mbedtls_chachapoly_update(mbedtls_chachapoly_context * ctx,size_t len,const unsigned char * input,unsigned char * output)162 int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
163 size_t len,
164 const unsigned char *input,
165 unsigned char *output )
166 {
167 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
168
169 if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
170 ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
171 {
172 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
173 }
174
175 if( ctx->state == CHACHAPOLY_STATE_AAD )
176 {
177 ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
178
179 ret = chachapoly_pad_aad( ctx );
180 if( ret != 0 )
181 return( ret );
182 }
183
184 ctx->ciphertext_len += len;
185
186 if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
187 {
188 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
189 if( ret != 0 )
190 return( ret );
191
192 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
193 if( ret != 0 )
194 return( ret );
195 }
196 else /* DECRYPT */
197 {
198 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
199 if( ret != 0 )
200 return( ret );
201
202 ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
203 if( ret != 0 )
204 return( ret );
205 }
206
207 return( 0 );
208 }
209
mbedtls_chachapoly_finish(mbedtls_chachapoly_context * ctx,unsigned char mac[16])210 int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
211 unsigned char mac[16] )
212 {
213 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
214 unsigned char len_block[16];
215
216 if( ctx->state == CHACHAPOLY_STATE_INIT )
217 {
218 return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
219 }
220
221 if( ctx->state == CHACHAPOLY_STATE_AAD )
222 {
223 ret = chachapoly_pad_aad( ctx );
224 if( ret != 0 )
225 return( ret );
226 }
227 else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
228 {
229 ret = chachapoly_pad_ciphertext( ctx );
230 if( ret != 0 )
231 return( ret );
232 }
233
234 ctx->state = CHACHAPOLY_STATE_FINISHED;
235
236 /* The lengths of the AAD and ciphertext are processed by
237 * Poly1305 as the final 128-bit block, encoded as little-endian integers.
238 */
239 MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);
240 MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);
241
242 ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
243 if( ret != 0 )
244 return( ret );
245
246 ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
247
248 return( ret );
249 }
250
chachapoly_crypt_and_tag(mbedtls_chachapoly_context * ctx,mbedtls_chachapoly_mode_t mode,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char * input,unsigned char * output,unsigned char tag[16])251 static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
252 mbedtls_chachapoly_mode_t mode,
253 size_t length,
254 const unsigned char nonce[12],
255 const unsigned char *aad,
256 size_t aad_len,
257 const unsigned char *input,
258 unsigned char *output,
259 unsigned char tag[16] )
260 {
261 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
262
263 ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
264 if( ret != 0 )
265 goto cleanup;
266
267 ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
268 if( ret != 0 )
269 goto cleanup;
270
271 ret = mbedtls_chachapoly_update( ctx, length, input, output );
272 if( ret != 0 )
273 goto cleanup;
274
275 ret = mbedtls_chachapoly_finish( ctx, tag );
276
277 cleanup:
278 return( ret );
279 }
280
mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context * ctx,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char * input,unsigned char * output,unsigned char tag[16])281 int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
282 size_t length,
283 const unsigned char nonce[12],
284 const unsigned char *aad,
285 size_t aad_len,
286 const unsigned char *input,
287 unsigned char *output,
288 unsigned char tag[16] )
289 {
290 return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
291 length, nonce, aad, aad_len,
292 input, output, tag ) );
293 }
294
mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context * ctx,size_t length,const unsigned char nonce[12],const unsigned char * aad,size_t aad_len,const unsigned char tag[16],const unsigned char * input,unsigned char * output)295 int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
296 size_t length,
297 const unsigned char nonce[12],
298 const unsigned char *aad,
299 size_t aad_len,
300 const unsigned char tag[16],
301 const unsigned char *input,
302 unsigned char *output )
303 {
304 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
305 unsigned char check_tag[16];
306 size_t i;
307 int diff;
308
309 if( ( ret = chachapoly_crypt_and_tag( ctx,
310 MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
311 aad, aad_len, input, output, check_tag ) ) != 0 )
312 {
313 return( ret );
314 }
315
316 /* Check tag in "constant-time" */
317 for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
318 diff |= tag[i] ^ check_tag[i];
319
320 if( diff != 0 )
321 {
322 mbedtls_platform_zeroize( output, length );
323 return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
324 }
325
326 return( 0 );
327 }
328
329 #endif /* MBEDTLS_CHACHAPOLY_ALT */
330
331 #if defined(MBEDTLS_SELF_TEST)
332
333 static const unsigned char test_key[1][32] =
334 {
335 {
336 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
337 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
338 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
339 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
340 }
341 };
342
343 static const unsigned char test_nonce[1][12] =
344 {
345 {
346 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
347 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
348 }
349 };
350
351 static const unsigned char test_aad[1][12] =
352 {
353 {
354 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
355 0xc4, 0xc5, 0xc6, 0xc7
356 }
357 };
358
359 static const size_t test_aad_len[1] =
360 {
361 12U
362 };
363
364 static const unsigned char test_input[1][114] =
365 {
366 {
367 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
368 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
369 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
370 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
371 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
372 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
373 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
374 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
375 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
376 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
377 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
378 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
379 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
380 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
381 0x74, 0x2e
382 }
383 };
384
385 static const unsigned char test_output[1][114] =
386 {
387 {
388 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
389 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
390 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
391 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
392 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
393 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
394 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
395 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
396 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
397 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
398 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
399 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
400 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
401 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
402 0x61, 0x16
403 }
404 };
405
406 static const size_t test_input_len[1] =
407 {
408 114U
409 };
410
411 static const unsigned char test_mac[1][16] =
412 {
413 {
414 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
415 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
416 }
417 };
418
419 /* Make sure no other definition is already present. */
420 #undef ASSERT
421
422 #define ASSERT( cond, args ) \
423 do \
424 { \
425 if( ! ( cond ) ) \
426 { \
427 if( verbose != 0 ) \
428 mbedtls_printf args; \
429 \
430 return( -1 ); \
431 } \
432 } \
433 while( 0 )
434
mbedtls_chachapoly_self_test(int verbose)435 int mbedtls_chachapoly_self_test( int verbose )
436 {
437 mbedtls_chachapoly_context ctx;
438 unsigned i;
439 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
440 unsigned char output[200];
441 unsigned char mac[16];
442
443 for( i = 0U; i < 1U; i++ )
444 {
445 if( verbose != 0 )
446 mbedtls_printf( " ChaCha20-Poly1305 test %u ", i );
447
448 mbedtls_chachapoly_init( &ctx );
449
450 ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
451 ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
452
453 ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
454 test_input_len[i],
455 test_nonce[i],
456 test_aad[i],
457 test_aad_len[i],
458 test_input[i],
459 output,
460 mac );
461
462 ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
463
464 ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
465 ( "failure (wrong output)\n" ) );
466
467 ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
468 ( "failure (wrong MAC)\n" ) );
469
470 mbedtls_chachapoly_free( &ctx );
471
472 if( verbose != 0 )
473 mbedtls_printf( "passed\n" );
474 }
475
476 if( verbose != 0 )
477 mbedtls_printf( "\n" );
478
479 return( 0 );
480 }
481
482 #endif /* MBEDTLS_SELF_TEST */
483
484 #endif /* MBEDTLS_CHACHAPOLY_C */
485