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