13d3b0591SJens Wiklander /* SPDX-License-Identifier: Apache-2.0 */ 23d3b0591SJens Wiklander /** 33d3b0591SJens Wiklander * \file chacha20.c 43d3b0591SJens Wiklander * 53d3b0591SJens Wiklander * \brief ChaCha20 cipher. 63d3b0591SJens Wiklander * 73d3b0591SJens Wiklander * \author Daniel King <damaki.gh@gmail.com> 83d3b0591SJens Wiklander * 93d3b0591SJens Wiklander * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved 103d3b0591SJens Wiklander * 113d3b0591SJens Wiklander * Licensed under the Apache License, Version 2.0 (the "License"); you may 123d3b0591SJens Wiklander * not use this file except in compliance with the License. 133d3b0591SJens Wiklander * You may obtain a copy of the License at 143d3b0591SJens Wiklander * 153d3b0591SJens Wiklander * http://www.apache.org/licenses/LICENSE-2.0 163d3b0591SJens Wiklander * 173d3b0591SJens Wiklander * Unless required by applicable law or agreed to in writing, software 183d3b0591SJens Wiklander * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 193d3b0591SJens Wiklander * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 203d3b0591SJens Wiklander * See the License for the specific language governing permissions and 213d3b0591SJens Wiklander * limitations under the License. 223d3b0591SJens Wiklander * 233d3b0591SJens Wiklander * This file is part of mbed TLS (https://tls.mbed.org) 243d3b0591SJens Wiklander */ 253d3b0591SJens Wiklander 263d3b0591SJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE) 273d3b0591SJens Wiklander #include "mbedtls/config.h" 283d3b0591SJens Wiklander #else 293d3b0591SJens Wiklander #include MBEDTLS_CONFIG_FILE 303d3b0591SJens Wiklander #endif 313d3b0591SJens Wiklander 323d3b0591SJens Wiklander #if defined(MBEDTLS_CHACHA20_C) 333d3b0591SJens Wiklander 343d3b0591SJens Wiklander #include "mbedtls/chacha20.h" 353d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 36*11fa71b9SJerome Forissier #include "mbedtls/error.h" 373d3b0591SJens Wiklander 383d3b0591SJens Wiklander #include <stddef.h> 393d3b0591SJens Wiklander #include <string.h> 403d3b0591SJens Wiklander 413d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) 423d3b0591SJens Wiklander #if defined(MBEDTLS_PLATFORM_C) 433d3b0591SJens Wiklander #include "mbedtls/platform.h" 443d3b0591SJens Wiklander #else 453d3b0591SJens Wiklander #include <stdio.h> 463d3b0591SJens Wiklander #define mbedtls_printf printf 473d3b0591SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */ 483d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 493d3b0591SJens Wiklander 503d3b0591SJens Wiklander #if !defined(MBEDTLS_CHACHA20_ALT) 513d3b0591SJens Wiklander 523d3b0591SJens Wiklander #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ 533d3b0591SJens Wiklander !defined(inline) && !defined(__cplusplus) 543d3b0591SJens Wiklander #define inline __inline 553d3b0591SJens Wiklander #endif 563d3b0591SJens Wiklander 573d3b0591SJens Wiklander /* Parameter validation macros */ 583d3b0591SJens Wiklander #define CHACHA20_VALIDATE_RET( cond ) \ 593d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) 603d3b0591SJens Wiklander #define CHACHA20_VALIDATE( cond ) \ 613d3b0591SJens Wiklander MBEDTLS_INTERNAL_VALIDATE( cond ) 623d3b0591SJens Wiklander 633d3b0591SJens Wiklander #define BYTES_TO_U32_LE( data, offset ) \ 645b25c76aSJerome Forissier ( (uint32_t) (data)[offset] \ 655b25c76aSJerome Forissier | (uint32_t) ( (uint32_t) (data)[( offset ) + 1] << 8 ) \ 665b25c76aSJerome Forissier | (uint32_t) ( (uint32_t) (data)[( offset ) + 2] << 16 ) \ 675b25c76aSJerome Forissier | (uint32_t) ( (uint32_t) (data)[( offset ) + 3] << 24 ) \ 683d3b0591SJens Wiklander ) 693d3b0591SJens Wiklander 703d3b0591SJens Wiklander #define ROTL32( value, amount ) \ 715b25c76aSJerome Forissier ( (uint32_t) ( (value) << (amount) ) | ( (value) >> ( 32 - (amount) ) ) ) 723d3b0591SJens Wiklander 733d3b0591SJens Wiklander #define CHACHA20_CTR_INDEX ( 12U ) 743d3b0591SJens Wiklander 753d3b0591SJens Wiklander #define CHACHA20_BLOCK_SIZE_BYTES ( 4U * 16U ) 763d3b0591SJens Wiklander 773d3b0591SJens Wiklander /** 783d3b0591SJens Wiklander * \brief ChaCha20 quarter round operation. 793d3b0591SJens Wiklander * 803d3b0591SJens Wiklander * The quarter round is defined as follows (from RFC 7539): 813d3b0591SJens Wiklander * 1. a += b; d ^= a; d <<<= 16; 823d3b0591SJens Wiklander * 2. c += d; b ^= c; b <<<= 12; 833d3b0591SJens Wiklander * 3. a += b; d ^= a; d <<<= 8; 843d3b0591SJens Wiklander * 4. c += d; b ^= c; b <<<= 7; 853d3b0591SJens Wiklander * 863d3b0591SJens Wiklander * \param state ChaCha20 state to modify. 873d3b0591SJens Wiklander * \param a The index of 'a' in the state. 883d3b0591SJens Wiklander * \param b The index of 'b' in the state. 893d3b0591SJens Wiklander * \param c The index of 'c' in the state. 903d3b0591SJens Wiklander * \param d The index of 'd' in the state. 913d3b0591SJens Wiklander */ 923d3b0591SJens Wiklander static inline void chacha20_quarter_round( uint32_t state[16], 933d3b0591SJens Wiklander size_t a, 943d3b0591SJens Wiklander size_t b, 953d3b0591SJens Wiklander size_t c, 963d3b0591SJens Wiklander size_t d ) 973d3b0591SJens Wiklander { 983d3b0591SJens Wiklander /* a += b; d ^= a; d <<<= 16; */ 993d3b0591SJens Wiklander state[a] += state[b]; 1003d3b0591SJens Wiklander state[d] ^= state[a]; 1013d3b0591SJens Wiklander state[d] = ROTL32( state[d], 16 ); 1023d3b0591SJens Wiklander 1033d3b0591SJens Wiklander /* c += d; b ^= c; b <<<= 12 */ 1043d3b0591SJens Wiklander state[c] += state[d]; 1053d3b0591SJens Wiklander state[b] ^= state[c]; 1063d3b0591SJens Wiklander state[b] = ROTL32( state[b], 12 ); 1073d3b0591SJens Wiklander 1083d3b0591SJens Wiklander /* a += b; d ^= a; d <<<= 8; */ 1093d3b0591SJens Wiklander state[a] += state[b]; 1103d3b0591SJens Wiklander state[d] ^= state[a]; 1113d3b0591SJens Wiklander state[d] = ROTL32( state[d], 8 ); 1123d3b0591SJens Wiklander 1133d3b0591SJens Wiklander /* c += d; b ^= c; b <<<= 7; */ 1143d3b0591SJens Wiklander state[c] += state[d]; 1153d3b0591SJens Wiklander state[b] ^= state[c]; 1163d3b0591SJens Wiklander state[b] = ROTL32( state[b], 7 ); 1173d3b0591SJens Wiklander } 1183d3b0591SJens Wiklander 1193d3b0591SJens Wiklander /** 1203d3b0591SJens Wiklander * \brief Perform the ChaCha20 inner block operation. 1213d3b0591SJens Wiklander * 1223d3b0591SJens Wiklander * This function performs two rounds: the column round and the 1233d3b0591SJens Wiklander * diagonal round. 1243d3b0591SJens Wiklander * 1253d3b0591SJens Wiklander * \param state The ChaCha20 state to update. 1263d3b0591SJens Wiklander */ 1273d3b0591SJens Wiklander static void chacha20_inner_block( uint32_t state[16] ) 1283d3b0591SJens Wiklander { 1293d3b0591SJens Wiklander chacha20_quarter_round( state, 0, 4, 8, 12 ); 1303d3b0591SJens Wiklander chacha20_quarter_round( state, 1, 5, 9, 13 ); 1313d3b0591SJens Wiklander chacha20_quarter_round( state, 2, 6, 10, 14 ); 1323d3b0591SJens Wiklander chacha20_quarter_round( state, 3, 7, 11, 15 ); 1333d3b0591SJens Wiklander 1343d3b0591SJens Wiklander chacha20_quarter_round( state, 0, 5, 10, 15 ); 1353d3b0591SJens Wiklander chacha20_quarter_round( state, 1, 6, 11, 12 ); 1363d3b0591SJens Wiklander chacha20_quarter_round( state, 2, 7, 8, 13 ); 1373d3b0591SJens Wiklander chacha20_quarter_round( state, 3, 4, 9, 14 ); 1383d3b0591SJens Wiklander } 1393d3b0591SJens Wiklander 1403d3b0591SJens Wiklander /** 1413d3b0591SJens Wiklander * \brief Generates a keystream block. 1423d3b0591SJens Wiklander * 1433d3b0591SJens Wiklander * \param initial_state The initial ChaCha20 state (key, nonce, counter). 1443d3b0591SJens Wiklander * \param keystream Generated keystream bytes are written to this buffer. 1453d3b0591SJens Wiklander */ 1463d3b0591SJens Wiklander static void chacha20_block( const uint32_t initial_state[16], 1473d3b0591SJens Wiklander unsigned char keystream[64] ) 1483d3b0591SJens Wiklander { 1493d3b0591SJens Wiklander uint32_t working_state[16]; 1503d3b0591SJens Wiklander size_t i; 1513d3b0591SJens Wiklander 1523d3b0591SJens Wiklander memcpy( working_state, 1533d3b0591SJens Wiklander initial_state, 1543d3b0591SJens Wiklander CHACHA20_BLOCK_SIZE_BYTES ); 1553d3b0591SJens Wiklander 1563d3b0591SJens Wiklander for( i = 0U; i < 10U; i++ ) 1573d3b0591SJens Wiklander chacha20_inner_block( working_state ); 1583d3b0591SJens Wiklander 1593d3b0591SJens Wiklander working_state[ 0] += initial_state[ 0]; 1603d3b0591SJens Wiklander working_state[ 1] += initial_state[ 1]; 1613d3b0591SJens Wiklander working_state[ 2] += initial_state[ 2]; 1623d3b0591SJens Wiklander working_state[ 3] += initial_state[ 3]; 1633d3b0591SJens Wiklander working_state[ 4] += initial_state[ 4]; 1643d3b0591SJens Wiklander working_state[ 5] += initial_state[ 5]; 1653d3b0591SJens Wiklander working_state[ 6] += initial_state[ 6]; 1663d3b0591SJens Wiklander working_state[ 7] += initial_state[ 7]; 1673d3b0591SJens Wiklander working_state[ 8] += initial_state[ 8]; 1683d3b0591SJens Wiklander working_state[ 9] += initial_state[ 9]; 1693d3b0591SJens Wiklander working_state[10] += initial_state[10]; 1703d3b0591SJens Wiklander working_state[11] += initial_state[11]; 1713d3b0591SJens Wiklander working_state[12] += initial_state[12]; 1723d3b0591SJens Wiklander working_state[13] += initial_state[13]; 1733d3b0591SJens Wiklander working_state[14] += initial_state[14]; 1743d3b0591SJens Wiklander working_state[15] += initial_state[15]; 1753d3b0591SJens Wiklander 1763d3b0591SJens Wiklander for( i = 0U; i < 16; i++ ) 1773d3b0591SJens Wiklander { 1783d3b0591SJens Wiklander size_t offset = i * 4U; 1793d3b0591SJens Wiklander 1803d3b0591SJens Wiklander keystream[offset ] = (unsigned char)( working_state[i] ); 1813d3b0591SJens Wiklander keystream[offset + 1U] = (unsigned char)( working_state[i] >> 8 ); 1823d3b0591SJens Wiklander keystream[offset + 2U] = (unsigned char)( working_state[i] >> 16 ); 1833d3b0591SJens Wiklander keystream[offset + 3U] = (unsigned char)( working_state[i] >> 24 ); 1843d3b0591SJens Wiklander } 1853d3b0591SJens Wiklander 1863d3b0591SJens Wiklander mbedtls_platform_zeroize( working_state, sizeof( working_state ) ); 1873d3b0591SJens Wiklander } 1883d3b0591SJens Wiklander 1893d3b0591SJens Wiklander void mbedtls_chacha20_init( mbedtls_chacha20_context *ctx ) 1903d3b0591SJens Wiklander { 1913d3b0591SJens Wiklander CHACHA20_VALIDATE( ctx != NULL ); 1923d3b0591SJens Wiklander 1933d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx->state, sizeof( ctx->state ) ); 1943d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); 1953d3b0591SJens Wiklander 1963d3b0591SJens Wiklander /* Initially, there's no keystream bytes available */ 1973d3b0591SJens Wiklander ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; 1983d3b0591SJens Wiklander } 1993d3b0591SJens Wiklander 2003d3b0591SJens Wiklander void mbedtls_chacha20_free( mbedtls_chacha20_context *ctx ) 2013d3b0591SJens Wiklander { 2023d3b0591SJens Wiklander if( ctx != NULL ) 2033d3b0591SJens Wiklander { 2043d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx, sizeof( mbedtls_chacha20_context ) ); 2053d3b0591SJens Wiklander } 2063d3b0591SJens Wiklander } 2073d3b0591SJens Wiklander 2083d3b0591SJens Wiklander int mbedtls_chacha20_setkey( mbedtls_chacha20_context *ctx, 2093d3b0591SJens Wiklander const unsigned char key[32] ) 2103d3b0591SJens Wiklander { 2113d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( ctx != NULL ); 2123d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( key != NULL ); 2133d3b0591SJens Wiklander 2143d3b0591SJens Wiklander /* ChaCha20 constants - the string "expand 32-byte k" */ 2153d3b0591SJens Wiklander ctx->state[0] = 0x61707865; 2163d3b0591SJens Wiklander ctx->state[1] = 0x3320646e; 2173d3b0591SJens Wiklander ctx->state[2] = 0x79622d32; 2183d3b0591SJens Wiklander ctx->state[3] = 0x6b206574; 2193d3b0591SJens Wiklander 2203d3b0591SJens Wiklander /* Set key */ 2213d3b0591SJens Wiklander ctx->state[4] = BYTES_TO_U32_LE( key, 0 ); 2223d3b0591SJens Wiklander ctx->state[5] = BYTES_TO_U32_LE( key, 4 ); 2233d3b0591SJens Wiklander ctx->state[6] = BYTES_TO_U32_LE( key, 8 ); 2243d3b0591SJens Wiklander ctx->state[7] = BYTES_TO_U32_LE( key, 12 ); 2253d3b0591SJens Wiklander ctx->state[8] = BYTES_TO_U32_LE( key, 16 ); 2263d3b0591SJens Wiklander ctx->state[9] = BYTES_TO_U32_LE( key, 20 ); 2273d3b0591SJens Wiklander ctx->state[10] = BYTES_TO_U32_LE( key, 24 ); 2283d3b0591SJens Wiklander ctx->state[11] = BYTES_TO_U32_LE( key, 28 ); 2293d3b0591SJens Wiklander 2303d3b0591SJens Wiklander return( 0 ); 2313d3b0591SJens Wiklander } 2323d3b0591SJens Wiklander 2333d3b0591SJens Wiklander int mbedtls_chacha20_starts( mbedtls_chacha20_context* ctx, 2343d3b0591SJens Wiklander const unsigned char nonce[12], 2353d3b0591SJens Wiklander uint32_t counter ) 2363d3b0591SJens Wiklander { 2373d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( ctx != NULL ); 2383d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( nonce != NULL ); 2393d3b0591SJens Wiklander 2403d3b0591SJens Wiklander /* Counter */ 2413d3b0591SJens Wiklander ctx->state[12] = counter; 2423d3b0591SJens Wiklander 2433d3b0591SJens Wiklander /* Nonce */ 2443d3b0591SJens Wiklander ctx->state[13] = BYTES_TO_U32_LE( nonce, 0 ); 2453d3b0591SJens Wiklander ctx->state[14] = BYTES_TO_U32_LE( nonce, 4 ); 2463d3b0591SJens Wiklander ctx->state[15] = BYTES_TO_U32_LE( nonce, 8 ); 2473d3b0591SJens Wiklander 2483d3b0591SJens Wiklander mbedtls_platform_zeroize( ctx->keystream8, sizeof( ctx->keystream8 ) ); 2493d3b0591SJens Wiklander 2503d3b0591SJens Wiklander /* Initially, there's no keystream bytes available */ 2513d3b0591SJens Wiklander ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES; 2523d3b0591SJens Wiklander 2533d3b0591SJens Wiklander return( 0 ); 2543d3b0591SJens Wiklander } 2553d3b0591SJens Wiklander 2563d3b0591SJens Wiklander int mbedtls_chacha20_update( mbedtls_chacha20_context *ctx, 2573d3b0591SJens Wiklander size_t size, 2583d3b0591SJens Wiklander const unsigned char *input, 2593d3b0591SJens Wiklander unsigned char *output ) 2603d3b0591SJens Wiklander { 2613d3b0591SJens Wiklander size_t offset = 0U; 2623d3b0591SJens Wiklander size_t i; 2633d3b0591SJens Wiklander 2643d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( ctx != NULL ); 2653d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( size == 0 || input != NULL ); 2663d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( size == 0 || output != NULL ); 2673d3b0591SJens Wiklander 2683d3b0591SJens Wiklander /* Use leftover keystream bytes, if available */ 2693d3b0591SJens Wiklander while( size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES ) 2703d3b0591SJens Wiklander { 2713d3b0591SJens Wiklander output[offset] = input[offset] 2723d3b0591SJens Wiklander ^ ctx->keystream8[ctx->keystream_bytes_used]; 2733d3b0591SJens Wiklander 2743d3b0591SJens Wiklander ctx->keystream_bytes_used++; 2753d3b0591SJens Wiklander offset++; 2763d3b0591SJens Wiklander size--; 2773d3b0591SJens Wiklander } 2783d3b0591SJens Wiklander 2793d3b0591SJens Wiklander /* Process full blocks */ 2803d3b0591SJens Wiklander while( size >= CHACHA20_BLOCK_SIZE_BYTES ) 2813d3b0591SJens Wiklander { 2823d3b0591SJens Wiklander /* Generate new keystream block and increment counter */ 2833d3b0591SJens Wiklander chacha20_block( ctx->state, ctx->keystream8 ); 2843d3b0591SJens Wiklander ctx->state[CHACHA20_CTR_INDEX]++; 2853d3b0591SJens Wiklander 2863d3b0591SJens Wiklander for( i = 0U; i < 64U; i += 8U ) 2873d3b0591SJens Wiklander { 2883d3b0591SJens Wiklander output[offset + i ] = input[offset + i ] ^ ctx->keystream8[i ]; 2893d3b0591SJens Wiklander output[offset + i+1] = input[offset + i+1] ^ ctx->keystream8[i+1]; 2903d3b0591SJens Wiklander output[offset + i+2] = input[offset + i+2] ^ ctx->keystream8[i+2]; 2913d3b0591SJens Wiklander output[offset + i+3] = input[offset + i+3] ^ ctx->keystream8[i+3]; 2923d3b0591SJens Wiklander output[offset + i+4] = input[offset + i+4] ^ ctx->keystream8[i+4]; 2933d3b0591SJens Wiklander output[offset + i+5] = input[offset + i+5] ^ ctx->keystream8[i+5]; 2943d3b0591SJens Wiklander output[offset + i+6] = input[offset + i+6] ^ ctx->keystream8[i+6]; 2953d3b0591SJens Wiklander output[offset + i+7] = input[offset + i+7] ^ ctx->keystream8[i+7]; 2963d3b0591SJens Wiklander } 2973d3b0591SJens Wiklander 2983d3b0591SJens Wiklander offset += CHACHA20_BLOCK_SIZE_BYTES; 2993d3b0591SJens Wiklander size -= CHACHA20_BLOCK_SIZE_BYTES; 3003d3b0591SJens Wiklander } 3013d3b0591SJens Wiklander 3023d3b0591SJens Wiklander /* Last (partial) block */ 3033d3b0591SJens Wiklander if( size > 0U ) 3043d3b0591SJens Wiklander { 3053d3b0591SJens Wiklander /* Generate new keystream block and increment counter */ 3063d3b0591SJens Wiklander chacha20_block( ctx->state, ctx->keystream8 ); 3073d3b0591SJens Wiklander ctx->state[CHACHA20_CTR_INDEX]++; 3083d3b0591SJens Wiklander 3093d3b0591SJens Wiklander for( i = 0U; i < size; i++) 3103d3b0591SJens Wiklander { 3113d3b0591SJens Wiklander output[offset + i] = input[offset + i] ^ ctx->keystream8[i]; 3123d3b0591SJens Wiklander } 3133d3b0591SJens Wiklander 3143d3b0591SJens Wiklander ctx->keystream_bytes_used = size; 3153d3b0591SJens Wiklander 3163d3b0591SJens Wiklander } 3173d3b0591SJens Wiklander 3183d3b0591SJens Wiklander return( 0 ); 3193d3b0591SJens Wiklander } 3203d3b0591SJens Wiklander 3213d3b0591SJens Wiklander int mbedtls_chacha20_crypt( const unsigned char key[32], 3223d3b0591SJens Wiklander const unsigned char nonce[12], 3233d3b0591SJens Wiklander uint32_t counter, 3243d3b0591SJens Wiklander size_t data_len, 3253d3b0591SJens Wiklander const unsigned char* input, 3263d3b0591SJens Wiklander unsigned char* output ) 3273d3b0591SJens Wiklander { 3283d3b0591SJens Wiklander mbedtls_chacha20_context ctx; 329*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3303d3b0591SJens Wiklander 3313d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( key != NULL ); 3323d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( nonce != NULL ); 3333d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( data_len == 0 || input != NULL ); 3343d3b0591SJens Wiklander CHACHA20_VALIDATE_RET( data_len == 0 || output != NULL ); 3353d3b0591SJens Wiklander 3363d3b0591SJens Wiklander mbedtls_chacha20_init( &ctx ); 3373d3b0591SJens Wiklander 3383d3b0591SJens Wiklander ret = mbedtls_chacha20_setkey( &ctx, key ); 3393d3b0591SJens Wiklander if( ret != 0 ) 3403d3b0591SJens Wiklander goto cleanup; 3413d3b0591SJens Wiklander 3423d3b0591SJens Wiklander ret = mbedtls_chacha20_starts( &ctx, nonce, counter ); 3433d3b0591SJens Wiklander if( ret != 0 ) 3443d3b0591SJens Wiklander goto cleanup; 3453d3b0591SJens Wiklander 3463d3b0591SJens Wiklander ret = mbedtls_chacha20_update( &ctx, data_len, input, output ); 3473d3b0591SJens Wiklander 3483d3b0591SJens Wiklander cleanup: 3493d3b0591SJens Wiklander mbedtls_chacha20_free( &ctx ); 3503d3b0591SJens Wiklander return( ret ); 3513d3b0591SJens Wiklander } 3523d3b0591SJens Wiklander 3533d3b0591SJens Wiklander #endif /* !MBEDTLS_CHACHA20_ALT */ 3543d3b0591SJens Wiklander 3553d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) 3563d3b0591SJens Wiklander 3573d3b0591SJens Wiklander static const unsigned char test_keys[2][32] = 3583d3b0591SJens Wiklander { 3593d3b0591SJens Wiklander { 3603d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3613d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3623d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3633d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 3643d3b0591SJens Wiklander }, 3653d3b0591SJens Wiklander { 3663d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3673d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3683d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3693d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 3703d3b0591SJens Wiklander } 3713d3b0591SJens Wiklander }; 3723d3b0591SJens Wiklander 3733d3b0591SJens Wiklander static const unsigned char test_nonces[2][12] = 3743d3b0591SJens Wiklander { 3753d3b0591SJens Wiklander { 3763d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3773d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00 3783d3b0591SJens Wiklander }, 3793d3b0591SJens Wiklander { 3803d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3813d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x02 3823d3b0591SJens Wiklander } 3833d3b0591SJens Wiklander }; 3843d3b0591SJens Wiklander 3853d3b0591SJens Wiklander static const uint32_t test_counters[2] = 3863d3b0591SJens Wiklander { 3873d3b0591SJens Wiklander 0U, 3883d3b0591SJens Wiklander 1U 3893d3b0591SJens Wiklander }; 3903d3b0591SJens Wiklander 3913d3b0591SJens Wiklander static const unsigned char test_input[2][375] = 3923d3b0591SJens Wiklander { 3933d3b0591SJens Wiklander { 3943d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3953d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3963d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3973d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3983d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3993d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 4003d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 4013d3b0591SJens Wiklander 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 4023d3b0591SJens Wiklander }, 4033d3b0591SJens Wiklander { 4043d3b0591SJens Wiklander 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, 4053d3b0591SJens Wiklander 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 4063d3b0591SJens Wiklander 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, 4073d3b0591SJens Wiklander 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, 4083d3b0591SJens Wiklander 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 4093d3b0591SJens Wiklander 0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 4103d3b0591SJens Wiklander 0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, 4113d3b0591SJens Wiklander 0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 4123d3b0591SJens Wiklander 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, 4133d3b0591SJens Wiklander 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, 4143d3b0591SJens Wiklander 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 4153d3b0591SJens Wiklander 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 4163d3b0591SJens Wiklander 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 4173d3b0591SJens Wiklander 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, 4183d3b0591SJens Wiklander 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, 4193d3b0591SJens Wiklander 0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, 4203d3b0591SJens Wiklander 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 4213d3b0591SJens Wiklander 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, 4223d3b0591SJens Wiklander 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 4233d3b0591SJens Wiklander 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 4243d3b0591SJens Wiklander 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 4253d3b0591SJens Wiklander 0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, 4263d3b0591SJens Wiklander 0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, 4273d3b0591SJens Wiklander 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 4283d3b0591SJens Wiklander 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, 4293d3b0591SJens Wiklander 0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, 4303d3b0591SJens Wiklander 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 4313d3b0591SJens Wiklander 0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, 4323d3b0591SJens Wiklander 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 4333d3b0591SJens Wiklander 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 4343d3b0591SJens Wiklander 0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, 4353d3b0591SJens Wiklander 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 4363d3b0591SJens Wiklander 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, 4373d3b0591SJens Wiklander 0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, 4383d3b0591SJens Wiklander 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, 4393d3b0591SJens Wiklander 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, 4403d3b0591SJens Wiklander 0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 4413d3b0591SJens Wiklander 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, 4423d3b0591SJens Wiklander 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, 4433d3b0591SJens Wiklander 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 4443d3b0591SJens Wiklander 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, 4453d3b0591SJens Wiklander 0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, 4463d3b0591SJens Wiklander 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, 4473d3b0591SJens Wiklander 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, 4483d3b0591SJens Wiklander 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 4493d3b0591SJens Wiklander 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 4503d3b0591SJens Wiklander 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f 4513d3b0591SJens Wiklander } 4523d3b0591SJens Wiklander }; 4533d3b0591SJens Wiklander 4543d3b0591SJens Wiklander static const unsigned char test_output[2][375] = 4553d3b0591SJens Wiklander { 4563d3b0591SJens Wiklander { 4573d3b0591SJens Wiklander 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 4583d3b0591SJens Wiklander 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, 4593d3b0591SJens Wiklander 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 4603d3b0591SJens Wiklander 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 4613d3b0591SJens Wiklander 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 4623d3b0591SJens Wiklander 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 4633d3b0591SJens Wiklander 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, 4643d3b0591SJens Wiklander 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86 4653d3b0591SJens Wiklander }, 4663d3b0591SJens Wiklander { 4673d3b0591SJens Wiklander 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, 4683d3b0591SJens Wiklander 0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, 4693d3b0591SJens Wiklander 0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd, 4703d3b0591SJens Wiklander 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec, 4713d3b0591SJens Wiklander 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15, 4723d3b0591SJens Wiklander 0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, 4733d3b0591SJens Wiklander 0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, 4743d3b0591SJens Wiklander 0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d, 4753d3b0591SJens Wiklander 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa, 4763d3b0591SJens Wiklander 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e, 4773d3b0591SJens Wiklander 0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, 4783d3b0591SJens Wiklander 0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, 4793d3b0591SJens Wiklander 0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05, 4803d3b0591SJens Wiklander 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c, 4813d3b0591SJens Wiklander 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05, 4823d3b0591SJens Wiklander 0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, 4833d3b0591SJens Wiklander 0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, 4843d3b0591SJens Wiklander 0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66, 4853d3b0591SJens Wiklander 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4, 4863d3b0591SJens Wiklander 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d, 4873d3b0591SJens Wiklander 0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, 4883d3b0591SJens Wiklander 0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, 4893d3b0591SJens Wiklander 0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87, 4903d3b0591SJens Wiklander 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b, 4913d3b0591SJens Wiklander 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2, 4923d3b0591SJens Wiklander 0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, 4933d3b0591SJens Wiklander 0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, 4943d3b0591SJens Wiklander 0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c, 4953d3b0591SJens Wiklander 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b, 4963d3b0591SJens Wiklander 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84, 4973d3b0591SJens Wiklander 0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, 4983d3b0591SJens Wiklander 0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, 4993d3b0591SJens Wiklander 0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe, 5003d3b0591SJens Wiklander 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0, 5013d3b0591SJens Wiklander 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80, 5023d3b0591SJens Wiklander 0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, 5033d3b0591SJens Wiklander 0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, 5043d3b0591SJens Wiklander 0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62, 5053d3b0591SJens Wiklander 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91, 5063d3b0591SJens Wiklander 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6, 5073d3b0591SJens Wiklander 0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, 5083d3b0591SJens Wiklander 0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, 5093d3b0591SJens Wiklander 0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41, 5103d3b0591SJens Wiklander 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab, 5113d3b0591SJens Wiklander 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba, 5123d3b0591SJens Wiklander 0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, 5133d3b0591SJens Wiklander 0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21 5143d3b0591SJens Wiklander } 5153d3b0591SJens Wiklander }; 5163d3b0591SJens Wiklander 5173d3b0591SJens Wiklander static const size_t test_lengths[2] = 5183d3b0591SJens Wiklander { 5193d3b0591SJens Wiklander 64U, 5203d3b0591SJens Wiklander 375U 5213d3b0591SJens Wiklander }; 5223d3b0591SJens Wiklander 5233d3b0591SJens Wiklander #define ASSERT( cond, args ) \ 5243d3b0591SJens Wiklander do \ 5253d3b0591SJens Wiklander { \ 5263d3b0591SJens Wiklander if( ! ( cond ) ) \ 5273d3b0591SJens Wiklander { \ 5283d3b0591SJens Wiklander if( verbose != 0 ) \ 5293d3b0591SJens Wiklander mbedtls_printf args; \ 5303d3b0591SJens Wiklander \ 5313d3b0591SJens Wiklander return( -1 ); \ 5323d3b0591SJens Wiklander } \ 5333d3b0591SJens Wiklander } \ 5343d3b0591SJens Wiklander while( 0 ) 5353d3b0591SJens Wiklander 5363d3b0591SJens Wiklander int mbedtls_chacha20_self_test( int verbose ) 5373d3b0591SJens Wiklander { 5383d3b0591SJens Wiklander unsigned char output[381]; 5393d3b0591SJens Wiklander unsigned i; 540*11fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 5413d3b0591SJens Wiklander 5423d3b0591SJens Wiklander for( i = 0U; i < 2U; i++ ) 5433d3b0591SJens Wiklander { 5443d3b0591SJens Wiklander if( verbose != 0 ) 5453d3b0591SJens Wiklander mbedtls_printf( " ChaCha20 test %u ", i ); 5463d3b0591SJens Wiklander 5473d3b0591SJens Wiklander ret = mbedtls_chacha20_crypt( test_keys[i], 5483d3b0591SJens Wiklander test_nonces[i], 5493d3b0591SJens Wiklander test_counters[i], 5503d3b0591SJens Wiklander test_lengths[i], 5513d3b0591SJens Wiklander test_input[i], 5523d3b0591SJens Wiklander output ); 5533d3b0591SJens Wiklander 5543d3b0591SJens Wiklander ASSERT( 0 == ret, ( "error code: %i\n", ret ) ); 5553d3b0591SJens Wiklander 5563d3b0591SJens Wiklander ASSERT( 0 == memcmp( output, test_output[i], test_lengths[i] ), 5573d3b0591SJens Wiklander ( "failed (output)\n" ) ); 5583d3b0591SJens Wiklander 5593d3b0591SJens Wiklander if( verbose != 0 ) 5603d3b0591SJens Wiklander mbedtls_printf( "passed\n" ); 5613d3b0591SJens Wiklander } 5623d3b0591SJens Wiklander 5633d3b0591SJens Wiklander if( verbose != 0 ) 5643d3b0591SJens Wiklander mbedtls_printf( "\n" ); 5653d3b0591SJens Wiklander 5663d3b0591SJens Wiklander return( 0 ); 5673d3b0591SJens Wiklander } 5683d3b0591SJens Wiklander 5693d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 5703d3b0591SJens Wiklander 5713d3b0591SJens Wiklander #endif /* !MBEDTLS_CHACHA20_C */ 572