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