4 * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
6 * Copyright The Mbed TLS Contributors
7 * SPDX-License-Identifier: Apache-2.0
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #if defined(MBEDTLS_CHACHAPOLY_C)
25 #include "mbedtls/chachapoly.h"
26 #include "mbedtls/platform_util.h"
27 #include "mbedtls/error.h"
31 #if defined(MBEDTLS_SELF_TEST)
32 #if defined(MBEDTLS_PLATFORM_C)
33 #include "mbedtls/platform.h"
36 #define mbedtls_printf printf
37 #endif /* MBEDTLS_PLATFORM_C */
38 #endif /* MBEDTLS_SELF_TEST */
40 #if !defined(MBEDTLS_CHACHAPOLY_ALT)
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 )
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 )
54 * \brief Adds nul bytes to pad the AAD for Poly1305.
56 * \param ctx The ChaCha20-Poly1305 context.
58 static int chachapoly_pad_aad(mbedtls_chachapoly_context
*ctx
) {
59 uint32_t partial_block_len
= (uint32_t)(ctx
->aad_len
% 16U);
60 unsigned char zeroes
[15];
62 if (partial_block_len
== 0U)
65 memset(zeroes
, 0, sizeof(zeroes
));
67 return (mbedtls_poly1305_update(&ctx
->poly1305_ctx
,
69 16U - partial_block_len
));
73 * \brief Adds nul bytes to pad the ciphertext for Poly1305.
75 * \param ctx The ChaCha20-Poly1305 context.
77 static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context
*ctx
) {
78 uint32_t partial_block_len
= (uint32_t)(ctx
->ciphertext_len
% 16U);
79 unsigned char zeroes
[15];
81 if (partial_block_len
== 0U)
84 memset(zeroes
, 0, sizeof(zeroes
));
85 return (mbedtls_poly1305_update(&ctx
->poly1305_ctx
,
87 16U - partial_block_len
));
90 void mbedtls_chachapoly_init(mbedtls_chachapoly_context
*ctx
) {
91 CHACHAPOLY_VALIDATE(ctx
!= NULL
);
93 mbedtls_chacha20_init(&ctx
->chacha20_ctx
);
94 mbedtls_poly1305_init(&ctx
->poly1305_ctx
);
96 ctx
->ciphertext_len
= 0U;
97 ctx
->state
= CHACHAPOLY_STATE_INIT
;
98 ctx
->mode
= MBEDTLS_CHACHAPOLY_ENCRYPT
;
101 void mbedtls_chachapoly_free(mbedtls_chachapoly_context
*ctx
) {
105 mbedtls_chacha20_free(&ctx
->chacha20_ctx
);
106 mbedtls_poly1305_free(&ctx
->poly1305_ctx
);
108 ctx
->ciphertext_len
= 0U;
109 ctx
->state
= CHACHAPOLY_STATE_INIT
;
110 ctx
->mode
= MBEDTLS_CHACHAPOLY_ENCRYPT
;
113 int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context
*ctx
,
114 const unsigned char key
[32]) {
115 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
116 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
117 CHACHAPOLY_VALIDATE_RET(key
!= NULL
);
119 ret
= mbedtls_chacha20_setkey(&ctx
->chacha20_ctx
, key
);
124 int mbedtls_chachapoly_starts(mbedtls_chachapoly_context
*ctx
,
125 const unsigned char nonce
[12],
126 mbedtls_chachapoly_mode_t mode
) {
127 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
128 unsigned char poly1305_key
[64];
129 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
130 CHACHAPOLY_VALIDATE_RET(nonce
!= NULL
);
132 /* Set counter = 0, will be update to 1 when generating Poly1305 key */
133 ret
= mbedtls_chacha20_starts(&ctx
->chacha20_ctx
, nonce
, 0U);
137 /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
138 * counter = 0. This is the same as encrypting a buffer of zeroes.
139 * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
140 * The other 256 bits are discarded.
142 memset(poly1305_key
, 0, sizeof(poly1305_key
));
143 ret
= mbedtls_chacha20_update(&ctx
->chacha20_ctx
, sizeof(poly1305_key
),
144 poly1305_key
, poly1305_key
);
148 ret
= mbedtls_poly1305_starts(&ctx
->poly1305_ctx
, poly1305_key
);
152 ctx
->ciphertext_len
= 0U;
153 ctx
->state
= CHACHAPOLY_STATE_AAD
;
158 mbedtls_platform_zeroize(poly1305_key
, 64U);
162 int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context
*ctx
,
163 const unsigned char *aad
,
165 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
166 CHACHAPOLY_VALIDATE_RET(aad_len
== 0 || aad
!= NULL
);
168 if (ctx
->state
!= CHACHAPOLY_STATE_AAD
)
169 return (MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
);
171 ctx
->aad_len
+= aad_len
;
173 return (mbedtls_poly1305_update(&ctx
->poly1305_ctx
, aad
, aad_len
));
176 int mbedtls_chachapoly_update(mbedtls_chachapoly_context
*ctx
,
178 const unsigned char *input
,
179 unsigned char *output
) {
180 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
181 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
182 CHACHAPOLY_VALIDATE_RET(len
== 0 || input
!= NULL
);
183 CHACHAPOLY_VALIDATE_RET(len
== 0 || output
!= NULL
);
185 if ((ctx
->state
!= CHACHAPOLY_STATE_AAD
) &&
186 (ctx
->state
!= CHACHAPOLY_STATE_CIPHERTEXT
)) {
187 return (MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
);
190 if (ctx
->state
== CHACHAPOLY_STATE_AAD
) {
191 ctx
->state
= CHACHAPOLY_STATE_CIPHERTEXT
;
193 ret
= chachapoly_pad_aad(ctx
);
198 ctx
->ciphertext_len
+= len
;
200 if (ctx
->mode
== MBEDTLS_CHACHAPOLY_ENCRYPT
) {
201 ret
= mbedtls_chacha20_update(&ctx
->chacha20_ctx
, len
, input
, output
);
205 ret
= mbedtls_poly1305_update(&ctx
->poly1305_ctx
, output
, len
);
208 } else { /* DECRYPT */
209 ret
= mbedtls_poly1305_update(&ctx
->poly1305_ctx
, input
, len
);
213 ret
= mbedtls_chacha20_update(&ctx
->chacha20_ctx
, len
, input
, output
);
221 int mbedtls_chachapoly_finish(mbedtls_chachapoly_context
*ctx
,
222 unsigned char mac
[16]) {
223 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
224 unsigned char len_block
[16];
225 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
226 CHACHAPOLY_VALIDATE_RET(mac
!= NULL
);
228 if (ctx
->state
== CHACHAPOLY_STATE_INIT
) {
229 return (MBEDTLS_ERR_CHACHAPOLY_BAD_STATE
);
232 if (ctx
->state
== CHACHAPOLY_STATE_AAD
) {
233 ret
= chachapoly_pad_aad(ctx
);
236 } else if (ctx
->state
== CHACHAPOLY_STATE_CIPHERTEXT
) {
237 ret
= chachapoly_pad_ciphertext(ctx
);
242 ctx
->state
= CHACHAPOLY_STATE_FINISHED
;
244 /* The lengths of the AAD and ciphertext are processed by
245 * Poly1305 as the final 128-bit block, encoded as little-endian integers.
247 len_block
[ 0] = (unsigned char)(ctx
->aad_len
);
248 len_block
[ 1] = (unsigned char)(ctx
->aad_len
>> 8);
249 len_block
[ 2] = (unsigned char)(ctx
->aad_len
>> 16);
250 len_block
[ 3] = (unsigned char)(ctx
->aad_len
>> 24);
251 len_block
[ 4] = (unsigned char)(ctx
->aad_len
>> 32);
252 len_block
[ 5] = (unsigned char)(ctx
->aad_len
>> 40);
253 len_block
[ 6] = (unsigned char)(ctx
->aad_len
>> 48);
254 len_block
[ 7] = (unsigned char)(ctx
->aad_len
>> 56);
255 len_block
[ 8] = (unsigned char)(ctx
->ciphertext_len
);
256 len_block
[ 9] = (unsigned char)(ctx
->ciphertext_len
>> 8);
257 len_block
[10] = (unsigned char)(ctx
->ciphertext_len
>> 16);
258 len_block
[11] = (unsigned char)(ctx
->ciphertext_len
>> 24);
259 len_block
[12] = (unsigned char)(ctx
->ciphertext_len
>> 32);
260 len_block
[13] = (unsigned char)(ctx
->ciphertext_len
>> 40);
261 len_block
[14] = (unsigned char)(ctx
->ciphertext_len
>> 48);
262 len_block
[15] = (unsigned char)(ctx
->ciphertext_len
>> 56);
264 ret
= mbedtls_poly1305_update(&ctx
->poly1305_ctx
, len_block
, 16U);
268 ret
= mbedtls_poly1305_finish(&ctx
->poly1305_ctx
, mac
);
273 static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context
*ctx
,
274 mbedtls_chachapoly_mode_t mode
,
276 const unsigned char nonce
[12],
277 const unsigned char *aad
,
279 const unsigned char *input
,
280 unsigned char *output
,
281 unsigned char tag
[16]) {
282 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
284 ret
= mbedtls_chachapoly_starts(ctx
, nonce
, mode
);
288 ret
= mbedtls_chachapoly_update_aad(ctx
, aad
, aad_len
);
292 ret
= mbedtls_chachapoly_update(ctx
, length
, input
, output
);
296 ret
= mbedtls_chachapoly_finish(ctx
, tag
);
302 int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context
*ctx
,
304 const unsigned char nonce
[12],
305 const unsigned char *aad
,
307 const unsigned char *input
,
308 unsigned char *output
,
309 unsigned char tag
[16]) {
310 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
311 CHACHAPOLY_VALIDATE_RET(nonce
!= NULL
);
312 CHACHAPOLY_VALIDATE_RET(tag
!= NULL
);
313 CHACHAPOLY_VALIDATE_RET(aad_len
== 0 || aad
!= NULL
);
314 CHACHAPOLY_VALIDATE_RET(length
== 0 || input
!= NULL
);
315 CHACHAPOLY_VALIDATE_RET(length
== 0 || output
!= NULL
);
317 return (chachapoly_crypt_and_tag(ctx
, MBEDTLS_CHACHAPOLY_ENCRYPT
,
318 length
, nonce
, aad
, aad_len
,
319 input
, output
, tag
));
322 int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context
*ctx
,
324 const unsigned char nonce
[12],
325 const unsigned char *aad
,
327 const unsigned char tag
[16],
328 const unsigned char *input
,
329 unsigned char *output
) {
330 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
331 unsigned char check_tag
[16];
334 CHACHAPOLY_VALIDATE_RET(ctx
!= NULL
);
335 CHACHAPOLY_VALIDATE_RET(nonce
!= NULL
);
336 CHACHAPOLY_VALIDATE_RET(tag
!= NULL
);
337 CHACHAPOLY_VALIDATE_RET(aad_len
== 0 || aad
!= NULL
);
338 CHACHAPOLY_VALIDATE_RET(length
== 0 || input
!= NULL
);
339 CHACHAPOLY_VALIDATE_RET(length
== 0 || output
!= NULL
);
341 if ((ret
= chachapoly_crypt_and_tag(ctx
,
342 MBEDTLS_CHACHAPOLY_DECRYPT
, length
, nonce
,
343 aad
, aad_len
, input
, output
, check_tag
)) != 0) {
347 /* Check tag in "constant-time" */
348 for (diff
= 0, i
= 0; i
< sizeof(check_tag
); i
++)
349 diff
|= tag
[i
] ^ check_tag
[i
];
352 mbedtls_platform_zeroize(output
, length
);
353 return (MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED
);
359 #endif /* MBEDTLS_CHACHAPOLY_ALT */
361 #if defined(MBEDTLS_SELF_TEST)
363 static const unsigned char test_key
[1][32] = {
365 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
366 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
367 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
368 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
372 static const unsigned char test_nonce
[1][12] = {
374 0x07, 0x00, 0x00, 0x00, /* 32-bit common part */
375 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */
379 static const unsigned char test_aad
[1][12] = {
381 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
382 0xc4, 0xc5, 0xc6, 0xc7
386 static const size_t test_aad_len
[1] = {
390 static const unsigned char test_input
[1][114] = {
392 0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
393 0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
394 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
395 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
396 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
397 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
398 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
399 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
400 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
401 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
402 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
403 0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
404 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
405 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
410 static const unsigned char test_output
[1][114] = {
412 0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
413 0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
414 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
415 0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
416 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
417 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
418 0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
419 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
420 0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
421 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
422 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
423 0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
424 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
425 0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
430 static const size_t test_input_len
[1] = {
434 static const unsigned char test_mac
[1][16] = {
436 0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
437 0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
441 /* Make sure no other definition is already present. */
444 #define ASSERT( cond, args ) \
450 mbedtls_printf args; \
457 int mbedtls_chachapoly_self_test(int verbose
) {
458 mbedtls_chachapoly_context ctx
;
460 int ret
= MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED
;
461 unsigned char output
[200];
462 unsigned char mac
[16];
464 for (i
= 0U; i
< 1U; i
++) {
466 mbedtls_printf(" ChaCha20-Poly1305 test %u ", i
);
468 mbedtls_chachapoly_init(&ctx
);
470 ret
= mbedtls_chachapoly_setkey(&ctx
, test_key
[i
]);
471 ASSERT(0 == ret
, ("setkey() error code: %i\n", ret
));
473 ret
= mbedtls_chachapoly_encrypt_and_tag(&ctx
,
482 ASSERT(0 == ret
, ("crypt_and_tag() error code: %i\n", ret
));
484 ASSERT(0 == memcmp(output
, test_output
[i
], test_input_len
[i
]),
485 ("failure (wrong output)\n"));
487 ASSERT(0 == memcmp(mac
, test_mac
[i
], 16U),
488 ("failure (wrong MAC)\n"));
490 mbedtls_chachapoly_free(&ctx
);
493 mbedtls_printf("passed\n");
497 mbedtls_printf("\n");
502 #endif /* MBEDTLS_SELF_TEST */
504 #endif /* MBEDTLS_CHACHAPOLY_C */