mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
267 lines
7.9 KiB
C
267 lines
7.9 KiB
C
/* ccm_mode.c - TinyCrypt implementation of CCM mode */
|
|
|
|
/*
|
|
* Copyright (C) 2017 by Intel Corporation, All Rights Reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* - Neither the name of Intel Corporation nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <tinycrypt/ccm_mode.h>
|
|
#include <tinycrypt/constants.h>
|
|
#include <tinycrypt/utils.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
int tc_ccm_config(TCCcmMode_t c, TCAesKeySched_t sched, uint8_t *nonce,
|
|
unsigned int nlen, unsigned int mlen)
|
|
{
|
|
|
|
/* input sanity check: */
|
|
if (c == (TCCcmMode_t) 0 ||
|
|
sched == (TCAesKeySched_t) 0 ||
|
|
nonce == (uint8_t *) 0) {
|
|
return TC_CRYPTO_FAIL;
|
|
} else if (nlen != 13) {
|
|
return TC_CRYPTO_FAIL; /* The allowed nonce size is: 13. See documentation.*/
|
|
} else if ((mlen < 4) || (mlen > 16) || (mlen & 1)) {
|
|
return TC_CRYPTO_FAIL; /* The allowed mac sizes are: 4, 6, 8, 10, 12, 14, 16.*/
|
|
}
|
|
|
|
c->mlen = mlen;
|
|
c->sched = sched;
|
|
c->nonce = nonce;
|
|
|
|
return TC_CRYPTO_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Variation of CBC-MAC mode used in CCM.
|
|
*/
|
|
static void ccm_cbc_mac(uint8_t *T, const uint8_t *data, unsigned int dlen,
|
|
unsigned int flag, TCAesKeySched_t sched)
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
if (flag > 0) {
|
|
T[0] ^= (uint8_t)(dlen >> 8);
|
|
T[1] ^= (uint8_t)(dlen);
|
|
dlen += 2; i = 2;
|
|
} else {
|
|
i = 0;
|
|
}
|
|
|
|
while (i < dlen) {
|
|
T[i++ % (Nb * Nk)] ^= *data++;
|
|
if (((i % (Nb * Nk)) == 0) || dlen == i) {
|
|
(void) tc_aes_encrypt(T, T, sched);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Variation of CTR mode used in CCM.
|
|
* The CTR mode used by CCM is slightly different than the conventional CTR
|
|
* mode (the counter is increased before encryption, instead of after
|
|
* encryption). Besides, it is assumed that the counter is stored in the last
|
|
* 2 bytes of the nonce.
|
|
*/
|
|
static int ccm_ctr_mode(uint8_t *out, unsigned int outlen, const uint8_t *in,
|
|
unsigned int inlen, uint8_t *ctr, const TCAesKeySched_t sched)
|
|
{
|
|
|
|
uint8_t buffer[TC_AES_BLOCK_SIZE];
|
|
uint8_t nonce[TC_AES_BLOCK_SIZE];
|
|
uint16_t block_num;
|
|
unsigned int i;
|
|
|
|
/* input sanity check: */
|
|
if (out == (uint8_t *) 0 ||
|
|
in == (uint8_t *) 0 ||
|
|
ctr == (uint8_t *) 0 ||
|
|
sched == (TCAesKeySched_t) 0 ||
|
|
inlen == 0 ||
|
|
outlen == 0 ||
|
|
outlen != inlen) {
|
|
return TC_CRYPTO_FAIL;
|
|
}
|
|
|
|
/* copy the counter to the nonce */
|
|
(void) _copy(nonce, sizeof(nonce), ctr, sizeof(nonce));
|
|
|
|
/* select the last 2 bytes of the nonce to be incremented */
|
|
block_num = (uint16_t) ((nonce[14] << 8)|(nonce[15]));
|
|
for (i = 0; i < inlen; ++i) {
|
|
if ((i % (TC_AES_BLOCK_SIZE)) == 0) {
|
|
block_num++;
|
|
nonce[14] = (uint8_t)(block_num >> 8);
|
|
nonce[15] = (uint8_t)(block_num);
|
|
if (!tc_aes_encrypt(buffer, nonce, sched)) {
|
|
return TC_CRYPTO_FAIL;
|
|
}
|
|
}
|
|
/* update the output */
|
|
*out++ = buffer[i % (TC_AES_BLOCK_SIZE)] ^ *in++;
|
|
}
|
|
|
|
/* update the counter */
|
|
ctr[14] = nonce[14]; ctr[15] = nonce[15];
|
|
|
|
return TC_CRYPTO_SUCCESS;
|
|
}
|
|
|
|
int tc_ccm_generation_encryption(uint8_t *out, unsigned int olen,
|
|
const uint8_t *associated_data,
|
|
unsigned int alen, const uint8_t *payload,
|
|
unsigned int plen, TCCcmMode_t c)
|
|
{
|
|
|
|
/* input sanity check: */
|
|
if ((out == (uint8_t *) 0) ||
|
|
(c == (TCCcmMode_t) 0) ||
|
|
((plen > 0) && (payload == (uint8_t *) 0)) ||
|
|
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
|
|
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
|
|
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
|
|
(olen < (plen + c->mlen))) { /* invalid output buffer size */
|
|
return TC_CRYPTO_FAIL;
|
|
}
|
|
|
|
uint8_t b[Nb * Nk];
|
|
uint8_t tag[Nb * Nk];
|
|
unsigned int i;
|
|
|
|
/* GENERATING THE AUTHENTICATION TAG: */
|
|
|
|
/* formatting the sequence b for authentication: */
|
|
b[0] = ((alen > 0) ? 0x40:0) | (((c->mlen - 2) / 2 << 3)) | (1);
|
|
for (i = 1; i <= 13; ++i) {
|
|
b[i] = c->nonce[i - 1];
|
|
}
|
|
b[14] = (uint8_t)(plen >> 8);
|
|
b[15] = (uint8_t)(plen);
|
|
|
|
/* computing the authentication tag using cbc-mac: */
|
|
(void) tc_aes_encrypt(tag, b, c->sched);
|
|
if (alen > 0) {
|
|
ccm_cbc_mac(tag, associated_data, alen, 1, c->sched);
|
|
}
|
|
if (plen > 0) {
|
|
ccm_cbc_mac(tag, payload, plen, 0, c->sched);
|
|
}
|
|
|
|
/* ENCRYPTION: */
|
|
|
|
/* formatting the sequence b for encryption: */
|
|
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
|
|
b[14] = b[15] = TC_ZERO_BYTE;
|
|
|
|
/* encrypting payload using ctr mode: */
|
|
ccm_ctr_mode(out, plen, payload, plen, b, c->sched);
|
|
|
|
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter for ctr_mode (0):*/
|
|
|
|
/* encrypting b and adding the tag to the output: */
|
|
(void) tc_aes_encrypt(b, b, c->sched);
|
|
out += plen;
|
|
for (i = 0; i < c->mlen; ++i) {
|
|
*out++ = tag[i] ^ b[i];
|
|
}
|
|
|
|
return TC_CRYPTO_SUCCESS;
|
|
}
|
|
|
|
int tc_ccm_decryption_verification(uint8_t *out, unsigned int olen,
|
|
const uint8_t *associated_data,
|
|
unsigned int alen, const uint8_t *payload,
|
|
unsigned int plen, TCCcmMode_t c)
|
|
{
|
|
|
|
/* input sanity check: */
|
|
if ((out == (uint8_t *) 0) ||
|
|
(c == (TCCcmMode_t) 0) ||
|
|
((plen > 0) && (payload == (uint8_t *) 0)) ||
|
|
((alen > 0) && (associated_data == (uint8_t *) 0)) ||
|
|
(alen >= TC_CCM_AAD_MAX_BYTES) || /* associated data size unsupported */
|
|
(plen >= TC_CCM_PAYLOAD_MAX_BYTES) || /* payload size unsupported */
|
|
(olen < plen - c->mlen)) { /* invalid output buffer size */
|
|
return TC_CRYPTO_FAIL;
|
|
}
|
|
|
|
uint8_t b[Nb * Nk];
|
|
uint8_t tag[Nb * Nk];
|
|
unsigned int i;
|
|
|
|
/* DECRYPTION: */
|
|
|
|
/* formatting the sequence b for decryption: */
|
|
b[0] = 1; /* q - 1 = 2 - 1 = 1 */
|
|
for (i = 1; i < 14; ++i) {
|
|
b[i] = c->nonce[i - 1];
|
|
}
|
|
b[14] = b[15] = TC_ZERO_BYTE; /* initial counter value is 0 */
|
|
|
|
/* decrypting payload using ctr mode: */
|
|
ccm_ctr_mode(out, plen - c->mlen, payload, plen - c->mlen, b, c->sched);
|
|
|
|
b[14] = b[15] = TC_ZERO_BYTE; /* restoring initial counter value (0) */
|
|
|
|
/* encrypting b and restoring the tag from input: */
|
|
(void) tc_aes_encrypt(b, b, c->sched);
|
|
for (i = 0; i < c->mlen; ++i) {
|
|
tag[i] = *(payload + plen - c->mlen + i) ^ b[i];
|
|
}
|
|
|
|
/* VERIFYING THE AUTHENTICATION TAG: */
|
|
|
|
/* formatting the sequence b for authentication: */
|
|
b[0] = ((alen > 0) ? 0x40:0)|(((c->mlen - 2) / 2 << 3)) | (1);
|
|
for (i = 1; i < 14; ++i) {
|
|
b[i] = c->nonce[i - 1];
|
|
}
|
|
b[14] = (uint8_t)((plen - c->mlen) >> 8);
|
|
b[15] = (uint8_t)(plen - c->mlen);
|
|
|
|
/* computing the authentication tag using cbc-mac: */
|
|
(void) tc_aes_encrypt(b, b, c->sched);
|
|
if (alen > 0) {
|
|
ccm_cbc_mac(b, associated_data, alen, 1, c->sched);
|
|
}
|
|
if (plen > 0) {
|
|
ccm_cbc_mac(b, out, plen - c->mlen, 0, c->sched);
|
|
}
|
|
|
|
/* comparing the received tag and the computed one: */
|
|
if (_compare(b, tag, c->mlen) == 0) {
|
|
return TC_CRYPTO_SUCCESS;
|
|
} else {
|
|
/* erase the decrypted buffer in case of mac validation failure: */
|
|
_set(out, 0, plen - c->mlen);
|
|
return TC_CRYPTO_FAIL;
|
|
}
|
|
}
|