Path: blob/master/thirdparty/mbedtls/library/chachapoly.c
9898 views
/**1* \file chachapoly.c2*3* \brief ChaCha20-Poly1305 AEAD construction based on RFC 7539.4*5* Copyright The Mbed TLS Contributors6* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later7*/8#include "common.h"910#if defined(MBEDTLS_CHACHAPOLY_C)1112#include "mbedtls/chachapoly.h"13#include "mbedtls/platform_util.h"14#include "mbedtls/error.h"15#include "mbedtls/constant_time.h"1617#include <string.h>1819#include "mbedtls/platform.h"2021#if !defined(MBEDTLS_CHACHAPOLY_ALT)2223#define CHACHAPOLY_STATE_INIT (0)24#define CHACHAPOLY_STATE_AAD (1)25#define CHACHAPOLY_STATE_CIPHERTEXT (2) /* Encrypting or decrypting */26#define CHACHAPOLY_STATE_FINISHED (3)2728/**29* \brief Adds nul bytes to pad the AAD for Poly1305.30*31* \param ctx The ChaCha20-Poly1305 context.32*/33static int chachapoly_pad_aad(mbedtls_chachapoly_context *ctx)34{35uint32_t partial_block_len = (uint32_t) (ctx->aad_len % 16U);36unsigned char zeroes[15];3738if (partial_block_len == 0U) {39return 0;40}4142memset(zeroes, 0, sizeof(zeroes));4344return mbedtls_poly1305_update(&ctx->poly1305_ctx,45zeroes,4616U - partial_block_len);47}4849/**50* \brief Adds nul bytes to pad the ciphertext for Poly1305.51*52* \param ctx The ChaCha20-Poly1305 context.53*/54static int chachapoly_pad_ciphertext(mbedtls_chachapoly_context *ctx)55{56uint32_t partial_block_len = (uint32_t) (ctx->ciphertext_len % 16U);57unsigned char zeroes[15];5859if (partial_block_len == 0U) {60return 0;61}6263memset(zeroes, 0, sizeof(zeroes));64return mbedtls_poly1305_update(&ctx->poly1305_ctx,65zeroes,6616U - partial_block_len);67}6869void mbedtls_chachapoly_init(mbedtls_chachapoly_context *ctx)70{71mbedtls_chacha20_init(&ctx->chacha20_ctx);72mbedtls_poly1305_init(&ctx->poly1305_ctx);73ctx->aad_len = 0U;74ctx->ciphertext_len = 0U;75ctx->state = CHACHAPOLY_STATE_INIT;76ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;77}7879void mbedtls_chachapoly_free(mbedtls_chachapoly_context *ctx)80{81if (ctx == NULL) {82return;83}8485mbedtls_chacha20_free(&ctx->chacha20_ctx);86mbedtls_poly1305_free(&ctx->poly1305_ctx);87ctx->aad_len = 0U;88ctx->ciphertext_len = 0U;89ctx->state = CHACHAPOLY_STATE_INIT;90ctx->mode = MBEDTLS_CHACHAPOLY_ENCRYPT;91}9293int mbedtls_chachapoly_setkey(mbedtls_chachapoly_context *ctx,94const unsigned char key[32])95{96int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;9798ret = mbedtls_chacha20_setkey(&ctx->chacha20_ctx, key);99100return ret;101}102103int mbedtls_chachapoly_starts(mbedtls_chachapoly_context *ctx,104const unsigned char nonce[12],105mbedtls_chachapoly_mode_t mode)106{107int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;108unsigned char poly1305_key[64];109110/* Set counter = 0, will be update to 1 when generating Poly1305 key */111ret = mbedtls_chacha20_starts(&ctx->chacha20_ctx, nonce, 0U);112if (ret != 0) {113goto cleanup;114}115116/* Generate the Poly1305 key by getting the ChaCha20 keystream output with117* counter = 0. This is the same as encrypting a buffer of zeroes.118* Only the first 256-bits (32 bytes) of the key is used for Poly1305.119* The other 256 bits are discarded.120*/121memset(poly1305_key, 0, sizeof(poly1305_key));122ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, sizeof(poly1305_key),123poly1305_key, poly1305_key);124if (ret != 0) {125goto cleanup;126}127128ret = mbedtls_poly1305_starts(&ctx->poly1305_ctx, poly1305_key);129130if (ret == 0) {131ctx->aad_len = 0U;132ctx->ciphertext_len = 0U;133ctx->state = CHACHAPOLY_STATE_AAD;134ctx->mode = mode;135}136137cleanup:138mbedtls_platform_zeroize(poly1305_key, 64U);139return ret;140}141142int mbedtls_chachapoly_update_aad(mbedtls_chachapoly_context *ctx,143const unsigned char *aad,144size_t aad_len)145{146if (ctx->state != CHACHAPOLY_STATE_AAD) {147return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;148}149150ctx->aad_len += aad_len;151152return mbedtls_poly1305_update(&ctx->poly1305_ctx, aad, aad_len);153}154155int mbedtls_chachapoly_update(mbedtls_chachapoly_context *ctx,156size_t len,157const unsigned char *input,158unsigned char *output)159{160int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;161162if ((ctx->state != CHACHAPOLY_STATE_AAD) &&163(ctx->state != CHACHAPOLY_STATE_CIPHERTEXT)) {164return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;165}166167if (ctx->state == CHACHAPOLY_STATE_AAD) {168ctx->state = CHACHAPOLY_STATE_CIPHERTEXT;169170ret = chachapoly_pad_aad(ctx);171if (ret != 0) {172return ret;173}174}175176ctx->ciphertext_len += len;177178if (ctx->mode == MBEDTLS_CHACHAPOLY_ENCRYPT) {179ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);180if (ret != 0) {181return ret;182}183184ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, output, len);185if (ret != 0) {186return ret;187}188} else { /* DECRYPT */189ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, input, len);190if (ret != 0) {191return ret;192}193194ret = mbedtls_chacha20_update(&ctx->chacha20_ctx, len, input, output);195if (ret != 0) {196return ret;197}198}199200return 0;201}202203int mbedtls_chachapoly_finish(mbedtls_chachapoly_context *ctx,204unsigned char mac[16])205{206int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;207unsigned char len_block[16];208209if (ctx->state == CHACHAPOLY_STATE_INIT) {210return MBEDTLS_ERR_CHACHAPOLY_BAD_STATE;211}212213if (ctx->state == CHACHAPOLY_STATE_AAD) {214ret = chachapoly_pad_aad(ctx);215if (ret != 0) {216return ret;217}218} else if (ctx->state == CHACHAPOLY_STATE_CIPHERTEXT) {219ret = chachapoly_pad_ciphertext(ctx);220if (ret != 0) {221return ret;222}223}224225ctx->state = CHACHAPOLY_STATE_FINISHED;226227/* The lengths of the AAD and ciphertext are processed by228* Poly1305 as the final 128-bit block, encoded as little-endian integers.229*/230MBEDTLS_PUT_UINT64_LE(ctx->aad_len, len_block, 0);231MBEDTLS_PUT_UINT64_LE(ctx->ciphertext_len, len_block, 8);232233ret = mbedtls_poly1305_update(&ctx->poly1305_ctx, len_block, 16U);234if (ret != 0) {235return ret;236}237238ret = mbedtls_poly1305_finish(&ctx->poly1305_ctx, mac);239240return ret;241}242243static int chachapoly_crypt_and_tag(mbedtls_chachapoly_context *ctx,244mbedtls_chachapoly_mode_t mode,245size_t length,246const unsigned char nonce[12],247const unsigned char *aad,248size_t aad_len,249const unsigned char *input,250unsigned char *output,251unsigned char tag[16])252{253int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;254255ret = mbedtls_chachapoly_starts(ctx, nonce, mode);256if (ret != 0) {257goto cleanup;258}259260ret = mbedtls_chachapoly_update_aad(ctx, aad, aad_len);261if (ret != 0) {262goto cleanup;263}264265ret = mbedtls_chachapoly_update(ctx, length, input, output);266if (ret != 0) {267goto cleanup;268}269270ret = mbedtls_chachapoly_finish(ctx, tag);271272cleanup:273return ret;274}275276int mbedtls_chachapoly_encrypt_and_tag(mbedtls_chachapoly_context *ctx,277size_t length,278const unsigned char nonce[12],279const unsigned char *aad,280size_t aad_len,281const unsigned char *input,282unsigned char *output,283unsigned char tag[16])284{285return chachapoly_crypt_and_tag(ctx, MBEDTLS_CHACHAPOLY_ENCRYPT,286length, nonce, aad, aad_len,287input, output, tag);288}289290int mbedtls_chachapoly_auth_decrypt(mbedtls_chachapoly_context *ctx,291size_t length,292const unsigned char nonce[12],293const unsigned char *aad,294size_t aad_len,295const unsigned char tag[16],296const unsigned char *input,297unsigned char *output)298{299int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;300unsigned char check_tag[16];301int diff;302303if ((ret = chachapoly_crypt_and_tag(ctx,304MBEDTLS_CHACHAPOLY_DECRYPT, length, nonce,305aad, aad_len, input, output, check_tag)) != 0) {306return ret;307}308309/* Check tag in "constant-time" */310diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));311312if (diff != 0) {313mbedtls_platform_zeroize(output, length);314return MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED;315}316317return 0;318}319320#endif /* MBEDTLS_CHACHAPOLY_ALT */321322#if defined(MBEDTLS_SELF_TEST)323324static const unsigned char test_key[1][32] =325{326{3270x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,3280x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,3290x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,3300x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f331}332};333334static const unsigned char test_nonce[1][12] =335{336{3370x07, 0x00, 0x00, 0x00, /* 32-bit common part */3380x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 /* 64-bit IV */339}340};341342static const unsigned char test_aad[1][12] =343{344{3450x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3,3460xc4, 0xc5, 0xc6, 0xc7347}348};349350static const size_t test_aad_len[1] =351{35212U353};354355static const unsigned char test_input[1][114] =356{357{3580x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61,3590x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c,3600x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20,3610x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73,3620x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39,3630x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63,3640x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66,3650x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f,3660x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20,3670x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20,3680x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75,3690x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73,3700x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,3710x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69,3720x74, 0x2e373}374};375376static const unsigned char test_output[1][114] =377{378{3790xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,3800x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,3810xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,3820xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,3830x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,3840x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,3850x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,3860x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,3870x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,3880x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,3890xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,3900x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,3910x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,3920xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,3930x61, 0x16394}395};396397static const size_t test_input_len[1] =398{399114U400};401402static const unsigned char test_mac[1][16] =403{404{4050x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,4060x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91407}408};409410/* Make sure no other definition is already present. */411#undef ASSERT412413#define ASSERT(cond, args) \414do \415{ \416if (!(cond)) \417{ \418if (verbose != 0) \419mbedtls_printf args; \420\421return -1; \422} \423} \424while (0)425426int mbedtls_chachapoly_self_test(int verbose)427{428mbedtls_chachapoly_context ctx;429unsigned i;430int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;431unsigned char output[200];432unsigned char mac[16];433434for (i = 0U; i < 1U; i++) {435if (verbose != 0) {436mbedtls_printf(" ChaCha20-Poly1305 test %u ", i);437}438439mbedtls_chachapoly_init(&ctx);440441ret = mbedtls_chachapoly_setkey(&ctx, test_key[i]);442ASSERT(0 == ret, ("setkey() error code: %i\n", ret));443444ret = mbedtls_chachapoly_encrypt_and_tag(&ctx,445test_input_len[i],446test_nonce[i],447test_aad[i],448test_aad_len[i],449test_input[i],450output,451mac);452453ASSERT(0 == ret, ("crypt_and_tag() error code: %i\n", ret));454455ASSERT(0 == memcmp(output, test_output[i], test_input_len[i]),456("failure (wrong output)\n"));457458ASSERT(0 == memcmp(mac, test_mac[i], 16U),459("failure (wrong MAC)\n"));460461mbedtls_chachapoly_free(&ctx);462463if (verbose != 0) {464mbedtls_printf("passed\n");465}466}467468if (verbose != 0) {469mbedtls_printf("\n");470}471472return 0;473}474475#endif /* MBEDTLS_SELF_TEST */476477#endif /* MBEDTLS_CHACHAPOLY_C */478479480