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