Path: blob/master/thirdparty/mbedtls/library/chacha20.c
9898 views
/**1* \file chacha20.c2*3* \brief ChaCha20 cipher.4*5* \author Daniel King <[email protected]>6*7* Copyright The Mbed TLS Contributors8* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later9*/1011#include "common.h"1213#if defined(MBEDTLS_CHACHA20_C)1415#include "mbedtls/chacha20.h"16#include "mbedtls/platform_util.h"17#include "mbedtls/error.h"1819#include <stddef.h>20#include <string.h>2122#include "mbedtls/platform.h"2324#if !defined(MBEDTLS_CHACHA20_ALT)2526#define ROTL32(value, amount) \27((uint32_t) ((value) << (amount)) | ((value) >> (32 - (amount))))2829#define CHACHA20_CTR_INDEX (12U)3031#define CHACHA20_BLOCK_SIZE_BYTES (4U * 16U)3233/**34* \brief ChaCha20 quarter round operation.35*36* The quarter round is defined as follows (from RFC 7539):37* 1. a += b; d ^= a; d <<<= 16;38* 2. c += d; b ^= c; b <<<= 12;39* 3. a += b; d ^= a; d <<<= 8;40* 4. c += d; b ^= c; b <<<= 7;41*42* \param state ChaCha20 state to modify.43* \param a The index of 'a' in the state.44* \param b The index of 'b' in the state.45* \param c The index of 'c' in the state.46* \param d The index of 'd' in the state.47*/48static inline void chacha20_quarter_round(uint32_t state[16],49size_t a,50size_t b,51size_t c,52size_t d)53{54/* a += b; d ^= a; d <<<= 16; */55state[a] += state[b];56state[d] ^= state[a];57state[d] = ROTL32(state[d], 16);5859/* c += d; b ^= c; b <<<= 12 */60state[c] += state[d];61state[b] ^= state[c];62state[b] = ROTL32(state[b], 12);6364/* a += b; d ^= a; d <<<= 8; */65state[a] += state[b];66state[d] ^= state[a];67state[d] = ROTL32(state[d], 8);6869/* c += d; b ^= c; b <<<= 7; */70state[c] += state[d];71state[b] ^= state[c];72state[b] = ROTL32(state[b], 7);73}7475/**76* \brief Perform the ChaCha20 inner block operation.77*78* This function performs two rounds: the column round and the79* diagonal round.80*81* \param state The ChaCha20 state to update.82*/83static void chacha20_inner_block(uint32_t state[16])84{85chacha20_quarter_round(state, 0, 4, 8, 12);86chacha20_quarter_round(state, 1, 5, 9, 13);87chacha20_quarter_round(state, 2, 6, 10, 14);88chacha20_quarter_round(state, 3, 7, 11, 15);8990chacha20_quarter_round(state, 0, 5, 10, 15);91chacha20_quarter_round(state, 1, 6, 11, 12);92chacha20_quarter_round(state, 2, 7, 8, 13);93chacha20_quarter_round(state, 3, 4, 9, 14);94}9596/**97* \brief Generates a keystream block.98*99* \param initial_state The initial ChaCha20 state (key, nonce, counter).100* \param keystream Generated keystream bytes are written to this buffer.101*/102static void chacha20_block(const uint32_t initial_state[16],103unsigned char keystream[64])104{105uint32_t working_state[16];106size_t i;107108memcpy(working_state,109initial_state,110CHACHA20_BLOCK_SIZE_BYTES);111112for (i = 0U; i < 10U; i++) {113chacha20_inner_block(working_state);114}115116working_state[0] += initial_state[0];117working_state[1] += initial_state[1];118working_state[2] += initial_state[2];119working_state[3] += initial_state[3];120working_state[4] += initial_state[4];121working_state[5] += initial_state[5];122working_state[6] += initial_state[6];123working_state[7] += initial_state[7];124working_state[8] += initial_state[8];125working_state[9] += initial_state[9];126working_state[10] += initial_state[10];127working_state[11] += initial_state[11];128working_state[12] += initial_state[12];129working_state[13] += initial_state[13];130working_state[14] += initial_state[14];131working_state[15] += initial_state[15];132133for (i = 0U; i < 16; i++) {134size_t offset = i * 4U;135136MBEDTLS_PUT_UINT32_LE(working_state[i], keystream, offset);137}138139mbedtls_platform_zeroize(working_state, sizeof(working_state));140}141142void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx)143{144mbedtls_platform_zeroize(ctx->state, sizeof(ctx->state));145mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));146147/* Initially, there's no keystream bytes available */148ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;149}150151void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx)152{153if (ctx != NULL) {154mbedtls_platform_zeroize(ctx, sizeof(mbedtls_chacha20_context));155}156}157158int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx,159const unsigned char key[32])160{161/* ChaCha20 constants - the string "expand 32-byte k" */162ctx->state[0] = 0x61707865;163ctx->state[1] = 0x3320646e;164ctx->state[2] = 0x79622d32;165ctx->state[3] = 0x6b206574;166167/* Set key */168ctx->state[4] = MBEDTLS_GET_UINT32_LE(key, 0);169ctx->state[5] = MBEDTLS_GET_UINT32_LE(key, 4);170ctx->state[6] = MBEDTLS_GET_UINT32_LE(key, 8);171ctx->state[7] = MBEDTLS_GET_UINT32_LE(key, 12);172ctx->state[8] = MBEDTLS_GET_UINT32_LE(key, 16);173ctx->state[9] = MBEDTLS_GET_UINT32_LE(key, 20);174ctx->state[10] = MBEDTLS_GET_UINT32_LE(key, 24);175ctx->state[11] = MBEDTLS_GET_UINT32_LE(key, 28);176177return 0;178}179180int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx,181const unsigned char nonce[12],182uint32_t counter)183{184/* Counter */185ctx->state[12] = counter;186187/* Nonce */188ctx->state[13] = MBEDTLS_GET_UINT32_LE(nonce, 0);189ctx->state[14] = MBEDTLS_GET_UINT32_LE(nonce, 4);190ctx->state[15] = MBEDTLS_GET_UINT32_LE(nonce, 8);191192mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));193194/* Initially, there's no keystream bytes available */195ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;196197return 0;198}199200int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx,201size_t size,202const unsigned char *input,203unsigned char *output)204{205size_t offset = 0U;206207/* Use leftover keystream bytes, if available */208while (size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES) {209output[offset] = input[offset]210^ ctx->keystream8[ctx->keystream_bytes_used];211212ctx->keystream_bytes_used++;213offset++;214size--;215}216217/* Process full blocks */218while (size >= CHACHA20_BLOCK_SIZE_BYTES) {219/* Generate new keystream block and increment counter */220chacha20_block(ctx->state, ctx->keystream8);221ctx->state[CHACHA20_CTR_INDEX]++;222223mbedtls_xor(output + offset, input + offset, ctx->keystream8, 64U);224225offset += CHACHA20_BLOCK_SIZE_BYTES;226size -= CHACHA20_BLOCK_SIZE_BYTES;227}228229/* Last (partial) block */230if (size > 0U) {231/* Generate new keystream block and increment counter */232chacha20_block(ctx->state, ctx->keystream8);233ctx->state[CHACHA20_CTR_INDEX]++;234235mbedtls_xor(output + offset, input + offset, ctx->keystream8, size);236237ctx->keystream_bytes_used = size;238239}240241return 0;242}243244int mbedtls_chacha20_crypt(const unsigned char key[32],245const unsigned char nonce[12],246uint32_t counter,247size_t data_len,248const unsigned char *input,249unsigned char *output)250{251mbedtls_chacha20_context ctx;252int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;253254mbedtls_chacha20_init(&ctx);255256ret = mbedtls_chacha20_setkey(&ctx, key);257if (ret != 0) {258goto cleanup;259}260261ret = mbedtls_chacha20_starts(&ctx, nonce, counter);262if (ret != 0) {263goto cleanup;264}265266ret = mbedtls_chacha20_update(&ctx, data_len, input, output);267268cleanup:269mbedtls_chacha20_free(&ctx);270return ret;271}272273#endif /* !MBEDTLS_CHACHA20_ALT */274275#if defined(MBEDTLS_SELF_TEST)276277static const unsigned char test_keys[2][32] =278{279{2800x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2810x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2820x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2830x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00284},285{2860x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2870x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2880x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2890x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01290}291};292293static const unsigned char test_nonces[2][12] =294{295{2960x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,2970x00, 0x00, 0x00, 0x00298},299{3000x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3010x00, 0x00, 0x00, 0x02302}303};304305static const uint32_t test_counters[2] =306{3070U,3081U309};310311static const unsigned char test_input[2][375] =312{313{3140x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3150x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3160x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3170x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3180x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3190x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3200x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,3210x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00322},323{3240x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d,3250x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74,3260x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45,3270x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,3280x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,3290x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72,3300x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66,3310x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69,3320x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,3330x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72,3340x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66,3350x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46,3360x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,3370x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20,3380x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61,3390x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73,3400x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,3410x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69,3420x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,3430x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,3440x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49,3450x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69,3460x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,3470x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72,3480x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49,3490x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74,3500x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,3510x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20,3520x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,3530x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75,3540x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20,3550x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,3560x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45,3570x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69,3580x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20,3590x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20,3600x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20,3610x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63,3620x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63,3630x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,3640x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61,3650x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e,3660x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f,3670x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c,3680x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61,3690x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,3700x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f371}372};373374static const unsigned char test_output[2][375] =375{376{3770x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,3780x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,3790xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,3800xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,3810xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,3820x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,3830x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,3840xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86385},386{3870xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde,3880x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70,3890x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd,3900x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec,3910x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,3920xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05,3930x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f,3940x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d,3950x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa,3960x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,3970x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7,3980xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50,3990x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05,4000x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c,4010x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,4020xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a,4030xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0,4040xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66,4050x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4,4060x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,4070xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91,4080x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28,4090xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87,4100x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b,4110x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,4120x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f,4130xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76,4140x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c,4150xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b,4160x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,4170xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd,4180xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b,4190xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe,4200x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0,4210x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,4220xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f,4230x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3,4240x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62,4250xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91,4260x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,4270x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64,4280x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85,4290x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41,4300xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab,4310x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,4320x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd,4330xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21434}435};436437static const size_t test_lengths[2] =438{43964U,440375U441};442443/* Make sure no other definition is already present. */444#undef ASSERT445446#define ASSERT(cond, args) \447do \448{ \449if (!(cond)) \450{ \451if (verbose != 0) \452mbedtls_printf args; \453\454return -1; \455} \456} \457while (0)458459int mbedtls_chacha20_self_test(int verbose)460{461unsigned char output[381];462unsigned i;463int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;464465for (i = 0U; i < 2U; i++) {466if (verbose != 0) {467mbedtls_printf(" ChaCha20 test %u ", i);468}469470ret = mbedtls_chacha20_crypt(test_keys[i],471test_nonces[i],472test_counters[i],473test_lengths[i],474test_input[i],475output);476477ASSERT(0 == ret, ("error code: %i\n", ret));478479ASSERT(0 == memcmp(output, test_output[i], test_lengths[i]),480("failed (output)\n"));481482if (verbose != 0) {483mbedtls_printf("passed\n");484}485}486487if (verbose != 0) {488mbedtls_printf("\n");489}490491return 0;492}493494#endif /* MBEDTLS_SELF_TEST */495496#endif /* !MBEDTLS_CHACHA20_C */497498499