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