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