source: azure_iot_hub_mbedtls/trunk/mbedtls-2.16.1/library/chachapoly.c@ 398

Last change on this file since 398 was 398, checked in by coas-nagasima, 5 years ago

mbedTLS版Azure IoT Hub接続サンプルのソースコードを追加

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