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