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