xref: /optee_os/lib/libmbedtls/mbedtls/library/chachapoly.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
13d3b0591SJens Wiklander /*  SPDX-License-Identifier: Apache-2.0 */
23d3b0591SJens Wiklander /**
33d3b0591SJens Wiklander  * \file chachapoly.c
43d3b0591SJens Wiklander  *
53d3b0591SJens Wiklander  * \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.
63d3b0591SJens Wiklander  *
73d3b0591SJens Wiklander  *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
83d3b0591SJens Wiklander  *
93d3b0591SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
103d3b0591SJens Wiklander  *  not use this file except in compliance with the License.
113d3b0591SJens Wiklander  *  You may obtain a copy of the License at
123d3b0591SJens Wiklander  *
133d3b0591SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
143d3b0591SJens Wiklander  *
153d3b0591SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
163d3b0591SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
173d3b0591SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
183d3b0591SJens Wiklander  *  See the License for the specific language governing permissions and
193d3b0591SJens Wiklander  *  limitations under the License.
203d3b0591SJens Wiklander  *
213d3b0591SJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
223d3b0591SJens Wiklander  */
233d3b0591SJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
243d3b0591SJens Wiklander #include "mbedtls/config.h"
253d3b0591SJens Wiklander #else
263d3b0591SJens Wiklander #include MBEDTLS_CONFIG_FILE
273d3b0591SJens Wiklander #endif
283d3b0591SJens Wiklander 
293d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHAPOLY_C)
303d3b0591SJens Wiklander 
313d3b0591SJens Wiklander #include "mbedtls/chachapoly.h"
323d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
33*11fa71b9SJerome Forissier #include "mbedtls/error.h"
343d3b0591SJens Wiklander 
353d3b0591SJens Wiklander #include <string.h>
363d3b0591SJens Wiklander 
373d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST)
383d3b0591SJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
393d3b0591SJens Wiklander #include "mbedtls/platform.h"
403d3b0591SJens Wiklander #else
413d3b0591SJens Wiklander #include <stdio.h>
423d3b0591SJens Wiklander #define mbedtls_printf printf
433d3b0591SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
443d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST */
453d3b0591SJens Wiklander 
463d3b0591SJens Wiklander #if !defined(MBEDTLS_CHACHAPOLY_ALT)
473d3b0591SJens Wiklander 
483d3b0591SJens Wiklander /* Parameter validation macros */
493d3b0591SJens Wiklander #define CHACHAPOLY_VALIDATE_RET( cond )                                       \
503d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA )
513d3b0591SJens Wiklander #define CHACHAPOLY_VALIDATE( cond )                                           \
523d3b0591SJens Wiklander     MBEDTLS_INTERNAL_VALIDATE( cond )
533d3b0591SJens Wiklander 
543d3b0591SJens Wiklander #define CHACHAPOLY_STATE_INIT       ( 0 )
553d3b0591SJens Wiklander #define CHACHAPOLY_STATE_AAD        ( 1 )
563d3b0591SJens Wiklander #define CHACHAPOLY_STATE_CIPHERTEXT ( 2 ) /* Encrypting or decrypting */
573d3b0591SJens Wiklander #define CHACHAPOLY_STATE_FINISHED   ( 3 )
583d3b0591SJens Wiklander 
593d3b0591SJens Wiklander /**
603d3b0591SJens Wiklander  * \brief           Adds nul bytes to pad the AAD for Poly1305.
613d3b0591SJens Wiklander  *
623d3b0591SJens Wiklander  * \param ctx       The ChaCha20-Poly1305 context.
633d3b0591SJens Wiklander  */
643d3b0591SJens Wiklander static int chachapoly_pad_aad( mbedtls_chachapoly_context *ctx )
653d3b0591SJens Wiklander {
663d3b0591SJens Wiklander     uint32_t partial_block_len = (uint32_t) ( ctx->aad_len % 16U );
673d3b0591SJens Wiklander     unsigned char zeroes[15];
683d3b0591SJens Wiklander 
693d3b0591SJens Wiklander     if( partial_block_len == 0U )
703d3b0591SJens Wiklander         return( 0 );
713d3b0591SJens Wiklander 
723d3b0591SJens Wiklander     memset( zeroes, 0, sizeof( zeroes ) );
733d3b0591SJens Wiklander 
743d3b0591SJens Wiklander     return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
753d3b0591SJens Wiklander                                      zeroes,
763d3b0591SJens Wiklander                                      16U - partial_block_len ) );
773d3b0591SJens Wiklander }
783d3b0591SJens Wiklander 
793d3b0591SJens Wiklander /**
803d3b0591SJens Wiklander  * \brief           Adds nul bytes to pad the ciphertext for Poly1305.
813d3b0591SJens Wiklander  *
823d3b0591SJens Wiklander  * \param ctx       The ChaCha20-Poly1305 context.
833d3b0591SJens Wiklander  */
843d3b0591SJens Wiklander static int chachapoly_pad_ciphertext( mbedtls_chachapoly_context *ctx )
853d3b0591SJens Wiklander {
863d3b0591SJens Wiklander     uint32_t partial_block_len = (uint32_t) ( ctx->ciphertext_len % 16U );
873d3b0591SJens Wiklander     unsigned char zeroes[15];
883d3b0591SJens Wiklander 
893d3b0591SJens Wiklander     if( partial_block_len == 0U )
903d3b0591SJens Wiklander         return( 0 );
913d3b0591SJens Wiklander 
923d3b0591SJens Wiklander     memset( zeroes, 0, sizeof( zeroes ) );
933d3b0591SJens Wiklander     return( mbedtls_poly1305_update( &ctx->poly1305_ctx,
943d3b0591SJens Wiklander                                      zeroes,
953d3b0591SJens Wiklander                                      16U - partial_block_len ) );
963d3b0591SJens Wiklander }
973d3b0591SJens Wiklander 
983d3b0591SJens Wiklander void mbedtls_chachapoly_init( mbedtls_chachapoly_context *ctx )
993d3b0591SJens Wiklander {
1003d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE( ctx != NULL );
1013d3b0591SJens Wiklander 
1023d3b0591SJens Wiklander     mbedtls_chacha20_init( &ctx->chacha20_ctx );
1033d3b0591SJens Wiklander     mbedtls_poly1305_init( &ctx->poly1305_ctx );
1043d3b0591SJens Wiklander     ctx->aad_len        = 0U;
1053d3b0591SJens Wiklander     ctx->ciphertext_len = 0U;
1063d3b0591SJens Wiklander     ctx->state          = CHACHAPOLY_STATE_INIT;
1073d3b0591SJens Wiklander     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
1083d3b0591SJens Wiklander }
1093d3b0591SJens Wiklander 
1103d3b0591SJens Wiklander void mbedtls_chachapoly_free( mbedtls_chachapoly_context *ctx )
1113d3b0591SJens Wiklander {
1123d3b0591SJens Wiklander     if( ctx == NULL )
1133d3b0591SJens Wiklander         return;
1143d3b0591SJens Wiklander 
1153d3b0591SJens Wiklander     mbedtls_chacha20_free( &ctx->chacha20_ctx );
1163d3b0591SJens Wiklander     mbedtls_poly1305_free( &ctx->poly1305_ctx );
1173d3b0591SJens Wiklander     ctx->aad_len        = 0U;
1183d3b0591SJens Wiklander     ctx->ciphertext_len = 0U;
1193d3b0591SJens Wiklander     ctx->state          = CHACHAPOLY_STATE_INIT;
1203d3b0591SJens Wiklander     ctx->mode           = MBEDTLS_CHACHAPOLY_ENCRYPT;
1213d3b0591SJens Wiklander }
1223d3b0591SJens Wiklander 
1233d3b0591SJens Wiklander int mbedtls_chachapoly_setkey( mbedtls_chachapoly_context *ctx,
1243d3b0591SJens Wiklander                                const unsigned char key[32] )
1253d3b0591SJens Wiklander {
126*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1273d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx != NULL );
1283d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( key != NULL );
1293d3b0591SJens Wiklander 
1303d3b0591SJens Wiklander     ret = mbedtls_chacha20_setkey( &ctx->chacha20_ctx, key );
1313d3b0591SJens Wiklander 
1323d3b0591SJens Wiklander     return( ret );
1333d3b0591SJens Wiklander }
1343d3b0591SJens Wiklander 
1353d3b0591SJens Wiklander int mbedtls_chachapoly_starts( mbedtls_chachapoly_context *ctx,
1363d3b0591SJens Wiklander                                const unsigned char nonce[12],
1373d3b0591SJens Wiklander                                mbedtls_chachapoly_mode_t mode  )
1383d3b0591SJens Wiklander {
139*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1403d3b0591SJens Wiklander     unsigned char poly1305_key[64];
1413d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx != NULL );
1423d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( nonce != NULL );
1433d3b0591SJens Wiklander 
1443d3b0591SJens Wiklander     /* Set counter = 0, will be update to 1 when generating Poly1305 key */
1453d3b0591SJens Wiklander     ret = mbedtls_chacha20_starts( &ctx->chacha20_ctx, nonce, 0U );
1463d3b0591SJens Wiklander     if( ret != 0 )
1473d3b0591SJens Wiklander         goto cleanup;
1483d3b0591SJens Wiklander 
1493d3b0591SJens Wiklander     /* Generate the Poly1305 key by getting the ChaCha20 keystream output with
1503d3b0591SJens Wiklander      * counter = 0.  This is the same as encrypting a buffer of zeroes.
1513d3b0591SJens Wiklander      * Only the first 256-bits (32 bytes) of the key is used for Poly1305.
1523d3b0591SJens Wiklander      * The other 256 bits are discarded.
1533d3b0591SJens Wiklander      */
1543d3b0591SJens Wiklander     memset( poly1305_key, 0, sizeof( poly1305_key ) );
1553d3b0591SJens Wiklander     ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, sizeof( poly1305_key ),
1563d3b0591SJens Wiklander                                       poly1305_key, poly1305_key );
1573d3b0591SJens Wiklander     if( ret != 0 )
1583d3b0591SJens Wiklander         goto cleanup;
1593d3b0591SJens Wiklander 
1603d3b0591SJens Wiklander     ret = mbedtls_poly1305_starts( &ctx->poly1305_ctx, poly1305_key );
1613d3b0591SJens Wiklander 
1623d3b0591SJens Wiklander     if( ret == 0 )
1633d3b0591SJens Wiklander     {
1643d3b0591SJens Wiklander         ctx->aad_len        = 0U;
1653d3b0591SJens Wiklander         ctx->ciphertext_len = 0U;
1663d3b0591SJens Wiklander         ctx->state          = CHACHAPOLY_STATE_AAD;
1673d3b0591SJens Wiklander         ctx->mode           = mode;
1683d3b0591SJens Wiklander     }
1693d3b0591SJens Wiklander 
1703d3b0591SJens Wiklander cleanup:
1713d3b0591SJens Wiklander     mbedtls_platform_zeroize( poly1305_key, 64U );
1723d3b0591SJens Wiklander     return( ret );
1733d3b0591SJens Wiklander }
1743d3b0591SJens Wiklander 
1753d3b0591SJens Wiklander int mbedtls_chachapoly_update_aad( mbedtls_chachapoly_context *ctx,
1763d3b0591SJens Wiklander                                    const unsigned char *aad,
1773d3b0591SJens Wiklander                                    size_t aad_len )
1783d3b0591SJens Wiklander {
1793d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx != NULL );
1803d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad != NULL );
1813d3b0591SJens Wiklander 
1823d3b0591SJens Wiklander     if( ctx->state != CHACHAPOLY_STATE_AAD )
1833d3b0591SJens Wiklander         return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
1843d3b0591SJens Wiklander 
1853d3b0591SJens Wiklander     ctx->aad_len += aad_len;
1863d3b0591SJens Wiklander 
1873d3b0591SJens Wiklander     return( mbedtls_poly1305_update( &ctx->poly1305_ctx, aad, aad_len ) );
1883d3b0591SJens Wiklander }
1893d3b0591SJens Wiklander 
1903d3b0591SJens Wiklander int mbedtls_chachapoly_update( mbedtls_chachapoly_context *ctx,
1913d3b0591SJens Wiklander                                size_t len,
1923d3b0591SJens Wiklander                                const unsigned char *input,
1933d3b0591SJens Wiklander                                unsigned char *output )
1943d3b0591SJens Wiklander {
195*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1963d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx != NULL );
1973d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( len == 0 || input != NULL );
1983d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( len == 0 || output != NULL );
1993d3b0591SJens Wiklander 
2003d3b0591SJens Wiklander     if( ( ctx->state != CHACHAPOLY_STATE_AAD ) &&
2013d3b0591SJens Wiklander         ( ctx->state != CHACHAPOLY_STATE_CIPHERTEXT ) )
2023d3b0591SJens Wiklander     {
2033d3b0591SJens Wiklander         return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
2043d3b0591SJens Wiklander     }
2053d3b0591SJens Wiklander 
2063d3b0591SJens Wiklander     if( ctx->state == CHACHAPOLY_STATE_AAD )
2073d3b0591SJens Wiklander     {
2083d3b0591SJens Wiklander         ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;
2093d3b0591SJens Wiklander 
2103d3b0591SJens Wiklander         ret = chachapoly_pad_aad( ctx );
2113d3b0591SJens Wiklander         if( ret != 0 )
2123d3b0591SJens Wiklander             return( ret );
2133d3b0591SJens Wiklander     }
2143d3b0591SJens Wiklander 
2153d3b0591SJens Wiklander     ctx->ciphertext_len += len;
2163d3b0591SJens Wiklander 
2173d3b0591SJens Wiklander     if( ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT )
2183d3b0591SJens Wiklander     {
2193d3b0591SJens Wiklander         ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
2203d3b0591SJens Wiklander         if( ret != 0 )
2213d3b0591SJens Wiklander             return( ret );
2223d3b0591SJens Wiklander 
2233d3b0591SJens Wiklander         ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, output, len );
2243d3b0591SJens Wiklander         if( ret != 0 )
2253d3b0591SJens Wiklander             return( ret );
2263d3b0591SJens Wiklander     }
2273d3b0591SJens Wiklander     else /* DECRYPT */
2283d3b0591SJens Wiklander     {
2293d3b0591SJens Wiklander         ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, input, len );
2303d3b0591SJens Wiklander         if( ret != 0 )
2313d3b0591SJens Wiklander             return( ret );
2323d3b0591SJens Wiklander 
2333d3b0591SJens Wiklander         ret = mbedtls_chacha20_update( &ctx->chacha20_ctx, len, input, output );
2343d3b0591SJens Wiklander         if( ret != 0 )
2353d3b0591SJens Wiklander             return( ret );
2363d3b0591SJens Wiklander     }
2373d3b0591SJens Wiklander 
2383d3b0591SJens Wiklander     return( 0 );
2393d3b0591SJens Wiklander }
2403d3b0591SJens Wiklander 
2413d3b0591SJens Wiklander int mbedtls_chachapoly_finish( mbedtls_chachapoly_context *ctx,
2423d3b0591SJens Wiklander                                unsigned char mac[16] )
2433d3b0591SJens Wiklander {
244*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2453d3b0591SJens Wiklander     unsigned char len_block[16];
2463d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx != NULL );
2473d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( mac != NULL );
2483d3b0591SJens Wiklander 
2493d3b0591SJens Wiklander     if( ctx->state == CHACHAPOLY_STATE_INIT )
2503d3b0591SJens Wiklander     {
2513d3b0591SJens Wiklander         return( MBEDTLS_ERR_CHACHAPOLY_BAD_STATE );
2523d3b0591SJens Wiklander     }
2533d3b0591SJens Wiklander 
2543d3b0591SJens Wiklander     if( ctx->state == CHACHAPOLY_STATE_AAD )
2553d3b0591SJens Wiklander     {
2563d3b0591SJens Wiklander         ret = chachapoly_pad_aad( ctx );
2573d3b0591SJens Wiklander         if( ret != 0 )
2583d3b0591SJens Wiklander             return( ret );
2593d3b0591SJens Wiklander     }
2603d3b0591SJens Wiklander     else if( ctx->state == CHACHAPOLY_STATE_CIPHERTEXT )
2613d3b0591SJens Wiklander     {
2623d3b0591SJens Wiklander         ret = chachapoly_pad_ciphertext( ctx );
2633d3b0591SJens Wiklander         if( ret != 0 )
2643d3b0591SJens Wiklander             return( ret );
2653d3b0591SJens Wiklander     }
2663d3b0591SJens Wiklander 
2673d3b0591SJens Wiklander     ctx->state = CHACHAPOLY_STATE_FINISHED;
2683d3b0591SJens Wiklander 
2693d3b0591SJens Wiklander     /* The lengths of the AAD and ciphertext are processed by
2703d3b0591SJens Wiklander      * Poly1305 as the final 128-bit block, encoded as little-endian integers.
2713d3b0591SJens Wiklander      */
2723d3b0591SJens Wiklander     len_block[ 0] = (unsigned char)( ctx->aad_len       );
2733d3b0591SJens Wiklander     len_block[ 1] = (unsigned char)( ctx->aad_len >>  8 );
2743d3b0591SJens Wiklander     len_block[ 2] = (unsigned char)( ctx->aad_len >> 16 );
2753d3b0591SJens Wiklander     len_block[ 3] = (unsigned char)( ctx->aad_len >> 24 );
2763d3b0591SJens Wiklander     len_block[ 4] = (unsigned char)( ctx->aad_len >> 32 );
2773d3b0591SJens Wiklander     len_block[ 5] = (unsigned char)( ctx->aad_len >> 40 );
2783d3b0591SJens Wiklander     len_block[ 6] = (unsigned char)( ctx->aad_len >> 48 );
2793d3b0591SJens Wiklander     len_block[ 7] = (unsigned char)( ctx->aad_len >> 56 );
2803d3b0591SJens Wiklander     len_block[ 8] = (unsigned char)( ctx->ciphertext_len       );
2813d3b0591SJens Wiklander     len_block[ 9] = (unsigned char)( ctx->ciphertext_len >>  8 );
2823d3b0591SJens Wiklander     len_block[10] = (unsigned char)( ctx->ciphertext_len >> 16 );
2833d3b0591SJens Wiklander     len_block[11] = (unsigned char)( ctx->ciphertext_len >> 24 );
2843d3b0591SJens Wiklander     len_block[12] = (unsigned char)( ctx->ciphertext_len >> 32 );
2853d3b0591SJens Wiklander     len_block[13] = (unsigned char)( ctx->ciphertext_len >> 40 );
2863d3b0591SJens Wiklander     len_block[14] = (unsigned char)( ctx->ciphertext_len >> 48 );
2873d3b0591SJens Wiklander     len_block[15] = (unsigned char)( ctx->ciphertext_len >> 56 );
2883d3b0591SJens Wiklander 
2893d3b0591SJens Wiklander     ret = mbedtls_poly1305_update( &ctx->poly1305_ctx, len_block, 16U );
2903d3b0591SJens Wiklander     if( ret != 0 )
2913d3b0591SJens Wiklander         return( ret );
2923d3b0591SJens Wiklander 
2933d3b0591SJens Wiklander     ret = mbedtls_poly1305_finish( &ctx->poly1305_ctx, mac );
2943d3b0591SJens Wiklander 
2953d3b0591SJens Wiklander     return( ret );
2963d3b0591SJens Wiklander }
2973d3b0591SJens Wiklander 
2983d3b0591SJens Wiklander static int chachapoly_crypt_and_tag( mbedtls_chachapoly_context *ctx,
2993d3b0591SJens Wiklander                                      mbedtls_chachapoly_mode_t mode,
3003d3b0591SJens Wiklander                                      size_t length,
3013d3b0591SJens Wiklander                                      const unsigned char nonce[12],
3023d3b0591SJens Wiklander                                      const unsigned char *aad,
3033d3b0591SJens Wiklander                                      size_t aad_len,
3043d3b0591SJens Wiklander                                      const unsigned char *input,
3053d3b0591SJens Wiklander                                      unsigned char *output,
3063d3b0591SJens Wiklander                                      unsigned char tag[16] )
3073d3b0591SJens Wiklander {
308*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3093d3b0591SJens Wiklander 
3103d3b0591SJens Wiklander     ret = mbedtls_chachapoly_starts( ctx, nonce, mode );
3113d3b0591SJens Wiklander     if( ret != 0 )
3123d3b0591SJens Wiklander         goto cleanup;
3133d3b0591SJens Wiklander 
3143d3b0591SJens Wiklander     ret = mbedtls_chachapoly_update_aad( ctx, aad, aad_len );
3153d3b0591SJens Wiklander     if( ret != 0 )
3163d3b0591SJens Wiklander         goto cleanup;
3173d3b0591SJens Wiklander 
3183d3b0591SJens Wiklander     ret = mbedtls_chachapoly_update( ctx, length, input, output );
3193d3b0591SJens Wiklander     if( ret != 0 )
3203d3b0591SJens Wiklander         goto cleanup;
3213d3b0591SJens Wiklander 
3223d3b0591SJens Wiklander     ret = mbedtls_chachapoly_finish( ctx, tag );
3233d3b0591SJens Wiklander 
3243d3b0591SJens Wiklander cleanup:
3253d3b0591SJens Wiklander     return( ret );
3263d3b0591SJens Wiklander }
3273d3b0591SJens Wiklander 
3283d3b0591SJens Wiklander int mbedtls_chachapoly_encrypt_and_tag( mbedtls_chachapoly_context *ctx,
3293d3b0591SJens Wiklander                                         size_t length,
3303d3b0591SJens Wiklander                                         const unsigned char nonce[12],
3313d3b0591SJens Wiklander                                         const unsigned char *aad,
3323d3b0591SJens Wiklander                                         size_t aad_len,
3333d3b0591SJens Wiklander                                         const unsigned char *input,
3343d3b0591SJens Wiklander                                         unsigned char *output,
3353d3b0591SJens Wiklander                                         unsigned char tag[16] )
3363d3b0591SJens Wiklander {
3373d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
3383d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( nonce != NULL );
3393d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( tag   != NULL );
3403d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
3413d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
3423d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );
3433d3b0591SJens Wiklander 
3443d3b0591SJens Wiklander     return( chachapoly_crypt_and_tag( ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,
3453d3b0591SJens Wiklander                                       length, nonce, aad, aad_len,
3463d3b0591SJens Wiklander                                       input, output, tag ) );
3473d3b0591SJens Wiklander }
3483d3b0591SJens Wiklander 
3493d3b0591SJens Wiklander int mbedtls_chachapoly_auth_decrypt( mbedtls_chachapoly_context *ctx,
3503d3b0591SJens Wiklander                                      size_t length,
3513d3b0591SJens Wiklander                                      const unsigned char nonce[12],
3523d3b0591SJens Wiklander                                      const unsigned char *aad,
3533d3b0591SJens Wiklander                                      size_t aad_len,
3543d3b0591SJens Wiklander                                      const unsigned char tag[16],
3553d3b0591SJens Wiklander                                      const unsigned char *input,
3563d3b0591SJens Wiklander                                      unsigned char *output )
3573d3b0591SJens Wiklander {
358*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3593d3b0591SJens Wiklander     unsigned char check_tag[16];
3603d3b0591SJens Wiklander     size_t i;
3613d3b0591SJens Wiklander     int diff;
3623d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( ctx   != NULL );
3633d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( nonce != NULL );
3643d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( tag   != NULL );
3653d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( aad_len == 0 || aad    != NULL );
3663d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( length  == 0 || input  != NULL );
3673d3b0591SJens Wiklander     CHACHAPOLY_VALIDATE_RET( length  == 0 || output != NULL );
3683d3b0591SJens Wiklander 
3693d3b0591SJens Wiklander     if( ( ret = chachapoly_crypt_and_tag( ctx,
3703d3b0591SJens Wiklander                         MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,
3713d3b0591SJens Wiklander                         aad, aad_len, input, output, check_tag ) ) != 0 )
3723d3b0591SJens Wiklander     {
3733d3b0591SJens Wiklander         return( ret );
3743d3b0591SJens Wiklander     }
3753d3b0591SJens Wiklander 
3763d3b0591SJens Wiklander     /* Check tag in "constant-time" */
3773d3b0591SJens Wiklander     for( diff = 0, i = 0; i < sizeof( check_tag ); i++ )
3783d3b0591SJens Wiklander         diff |= tag[i] ^ check_tag[i];
3793d3b0591SJens Wiklander 
3803d3b0591SJens Wiklander     if( diff != 0 )
3813d3b0591SJens Wiklander     {
3823d3b0591SJens Wiklander         mbedtls_platform_zeroize( output, length );
3833d3b0591SJens Wiklander         return( MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED );
3843d3b0591SJens Wiklander     }
3853d3b0591SJens Wiklander 
3863d3b0591SJens Wiklander     return( 0 );
3873d3b0591SJens Wiklander }
3883d3b0591SJens Wiklander 
3893d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_ALT */
3903d3b0591SJens Wiklander 
3913d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST)
3923d3b0591SJens Wiklander 
3933d3b0591SJens Wiklander static const unsigned char test_key[1][32] =
3943d3b0591SJens Wiklander {
3953d3b0591SJens Wiklander     {
3963d3b0591SJens Wiklander         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
3973d3b0591SJens Wiklander         0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
3983d3b0591SJens Wiklander         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
3993d3b0591SJens Wiklander         0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
4003d3b0591SJens Wiklander     }
4013d3b0591SJens Wiklander };
4023d3b0591SJens Wiklander 
4033d3b0591SJens Wiklander static const unsigned char test_nonce[1][12] =
4043d3b0591SJens Wiklander {
4053d3b0591SJens Wiklander     {
4063d3b0591SJens Wiklander         0x07, 0x00, 0x00, 0x00,                         /* 32-bit common part */
4073d3b0591SJens Wiklander         0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47  /* 64-bit IV */
4083d3b0591SJens Wiklander     }
4093d3b0591SJens Wiklander };
4103d3b0591SJens Wiklander 
4113d3b0591SJens Wiklander static const unsigned char test_aad[1][12] =
4123d3b0591SJens Wiklander {
4133d3b0591SJens Wiklander     {
4143d3b0591SJens Wiklander         0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,
4153d3b0591SJens Wiklander         0xc4, 0xc5, 0xc6, 0xc7
4163d3b0591SJens Wiklander     }
4173d3b0591SJens Wiklander };
4183d3b0591SJens Wiklander 
4193d3b0591SJens Wiklander static const size_t test_aad_len[1] =
4203d3b0591SJens Wiklander {
4213d3b0591SJens Wiklander     12U
4223d3b0591SJens Wiklander };
4233d3b0591SJens Wiklander 
4243d3b0591SJens Wiklander static const unsigned char test_input[1][114] =
4253d3b0591SJens Wiklander {
4263d3b0591SJens Wiklander     {
4273d3b0591SJens Wiklander         0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,
4283d3b0591SJens Wiklander         0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,
4293d3b0591SJens Wiklander         0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,
4303d3b0591SJens Wiklander         0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,
4313d3b0591SJens Wiklander         0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,
4323d3b0591SJens Wiklander         0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,
4333d3b0591SJens Wiklander         0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,
4343d3b0591SJens Wiklander         0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,
4353d3b0591SJens Wiklander         0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,
4363d3b0591SJens Wiklander         0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,
4373d3b0591SJens Wiklander         0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,
4383d3b0591SJens Wiklander         0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,
4393d3b0591SJens Wiklander         0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
4403d3b0591SJens Wiklander         0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,
4413d3b0591SJens Wiklander         0x74, 0x2e
4423d3b0591SJens Wiklander     }
4433d3b0591SJens Wiklander };
4443d3b0591SJens Wiklander 
4453d3b0591SJens Wiklander static const unsigned char test_output[1][114] =
4463d3b0591SJens Wiklander {
4473d3b0591SJens Wiklander     {
4483d3b0591SJens Wiklander         0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
4493d3b0591SJens Wiklander         0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
4503d3b0591SJens Wiklander         0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
4513d3b0591SJens Wiklander         0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
4523d3b0591SJens Wiklander         0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
4533d3b0591SJens Wiklander         0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
4543d3b0591SJens Wiklander         0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
4553d3b0591SJens Wiklander         0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
4563d3b0591SJens Wiklander         0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
4573d3b0591SJens Wiklander         0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
4583d3b0591SJens Wiklander         0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
4593d3b0591SJens Wiklander         0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
4603d3b0591SJens Wiklander         0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
4613d3b0591SJens Wiklander         0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
4623d3b0591SJens Wiklander         0x61, 0x16
4633d3b0591SJens Wiklander     }
4643d3b0591SJens Wiklander };
4653d3b0591SJens Wiklander 
4663d3b0591SJens Wiklander static const size_t test_input_len[1] =
4673d3b0591SJens Wiklander {
4683d3b0591SJens Wiklander     114U
4693d3b0591SJens Wiklander };
4703d3b0591SJens Wiklander 
4713d3b0591SJens Wiklander static const unsigned char test_mac[1][16] =
4723d3b0591SJens Wiklander {
4733d3b0591SJens Wiklander     {
4743d3b0591SJens Wiklander         0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
4753d3b0591SJens Wiklander         0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
4763d3b0591SJens Wiklander     }
4773d3b0591SJens Wiklander };
4783d3b0591SJens Wiklander 
4793d3b0591SJens Wiklander #define ASSERT( cond, args )            \
4803d3b0591SJens Wiklander     do                                  \
4813d3b0591SJens Wiklander     {                                   \
4823d3b0591SJens Wiklander         if( ! ( cond ) )                \
4833d3b0591SJens Wiklander         {                               \
4843d3b0591SJens Wiklander             if( verbose != 0 )          \
4853d3b0591SJens Wiklander                 mbedtls_printf args;    \
4863d3b0591SJens Wiklander                                         \
4873d3b0591SJens Wiklander             return( -1 );               \
4883d3b0591SJens Wiklander         }                               \
4893d3b0591SJens Wiklander     }                                   \
4903d3b0591SJens Wiklander     while( 0 )
4913d3b0591SJens Wiklander 
4923d3b0591SJens Wiklander int mbedtls_chachapoly_self_test( int verbose )
4933d3b0591SJens Wiklander {
4943d3b0591SJens Wiklander     mbedtls_chachapoly_context ctx;
4953d3b0591SJens Wiklander     unsigned i;
496*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
4973d3b0591SJens Wiklander     unsigned char output[200];
4983d3b0591SJens Wiklander     unsigned char mac[16];
4993d3b0591SJens Wiklander 
5003d3b0591SJens Wiklander     for( i = 0U; i < 1U; i++ )
5013d3b0591SJens Wiklander     {
5023d3b0591SJens Wiklander         if( verbose != 0 )
5033d3b0591SJens Wiklander             mbedtls_printf( "  ChaCha20-Poly1305 test %u ", i );
5043d3b0591SJens Wiklander 
5053d3b0591SJens Wiklander         mbedtls_chachapoly_init( &ctx );
5063d3b0591SJens Wiklander 
5073d3b0591SJens Wiklander         ret = mbedtls_chachapoly_setkey( &ctx, test_key[i] );
5083d3b0591SJens Wiklander         ASSERT( 0 == ret, ( "setkey() error code: %i\n", ret ) );
5093d3b0591SJens Wiklander 
5103d3b0591SJens Wiklander         ret = mbedtls_chachapoly_encrypt_and_tag( &ctx,
5113d3b0591SJens Wiklander                                                   test_input_len[i],
5123d3b0591SJens Wiklander                                                   test_nonce[i],
5133d3b0591SJens Wiklander                                                   test_aad[i],
5143d3b0591SJens Wiklander                                                   test_aad_len[i],
5153d3b0591SJens Wiklander                                                   test_input[i],
5163d3b0591SJens Wiklander                                                   output,
5173d3b0591SJens Wiklander                                                   mac );
5183d3b0591SJens Wiklander 
5193d3b0591SJens Wiklander         ASSERT( 0 == ret, ( "crypt_and_tag() error code: %i\n", ret ) );
5203d3b0591SJens Wiklander 
5213d3b0591SJens Wiklander         ASSERT( 0 == memcmp( output, test_output[i], test_input_len[i] ),
5223d3b0591SJens Wiklander                 ( "failure (wrong output)\n" ) );
5233d3b0591SJens Wiklander 
5243d3b0591SJens Wiklander         ASSERT( 0 == memcmp( mac, test_mac[i], 16U ),
5253d3b0591SJens Wiklander                 ( "failure (wrong MAC)\n" ) );
5263d3b0591SJens Wiklander 
5273d3b0591SJens Wiklander         mbedtls_chachapoly_free( &ctx );
5283d3b0591SJens Wiklander 
5293d3b0591SJens Wiklander         if( verbose != 0 )
5303d3b0591SJens Wiklander             mbedtls_printf( "passed\n" );
5313d3b0591SJens Wiklander     }
5323d3b0591SJens Wiklander 
5333d3b0591SJens Wiklander     if( verbose != 0 )
5343d3b0591SJens Wiklander         mbedtls_printf( "\n" );
5353d3b0591SJens Wiklander 
5363d3b0591SJens Wiklander     return( 0 );
5373d3b0591SJens Wiklander }
5383d3b0591SJens Wiklander 
5393d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST */
5403d3b0591SJens Wiklander 
5413d3b0591SJens Wiklander #endif /* MBEDTLS_CHACHAPOLY_C */
542