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