M467 Support crypto AES-CCM H/W with one-shot & cascade mode

pull/15337/head
cyliangtw 2022-05-26 16:08:45 +08:00 committed by Chun-Chieh Li
parent 88a529180f
commit a430d70c0d
4 changed files with 1059 additions and 0 deletions

View File

@ -9,6 +9,7 @@ target_include_directories(mbed-mbedtls
./rsa
./sha
./gcm
./ccm
)
target_sources(mbed-mbedtls
@ -22,4 +23,5 @@ target_sources(mbed-mbedtls
sha/sha512_alt.c
sha/sha_alt_hw.c
gcm/gcm_alt.c
ccm/ccm_alt.c
)

View File

@ -0,0 +1,738 @@
/*
* NIST SP800-38C compliant CCM implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Copyright (c) 2022, Nuvoton Technology Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*/
#include "common.h"
#include "mbedtls/aes.h"
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#if defined(MBEDTLS_CCM_ALT)
#include "M460.h"
#include "mbed_assert.h"
#include "mbed_error.h"
#include "nu_bitutil.h"
#include "crypto-misc.h"
#define CCM_VALIDATE_RET( cond ) \
MBEDTLS_INTERNAL_VALIDATE_RET( cond, MBEDTLS_ERR_CCM_BAD_INPUT )
#define CCM_VALIDATE( cond ) \
MBEDTLS_INTERNAL_VALIDATE( cond )
#define CCM_ENCRYPT 1
#define CCM_DECRYPT 0
#define CCM_MODE (AES_MODE_CCM << CRPT_AES_CTL_OPMODE_Pos)
#define START CRPT_AES_CTL_START_Msk
#define DMAEN CRPT_AES_CTL_DMAEN_Msk
#define DMALAST CRPT_AES_CTL_DMALAST_Msk
#define DMACC CRPT_AES_CTL_DMACSCAD_Msk
#define START CRPT_AES_CTL_START_Msk
#define FBIN CRPT_AES_CTL_FBIN_Msk
#define FBOUT CRPT_AES_CTL_FBOUT_Msk
#define Debug_CCM_Info(x) {}
//#define Debug_CCM_Info(x) { printf x; }
int32_t ToBigEndian(uint8_t *pbuf, uint32_t u32Size)
{
uint32_t i;
uint8_t u8Tmp;
uint32_t u32Tmp;
/* pbuf must be word alignment */
if((uint32_t)pbuf & 0x3)
{
printf("The buffer must be 32-bit alignment.");
return -1;
}
while(u32Size >= 4)
{
u8Tmp = *pbuf;
*(pbuf) = *(pbuf + 3);
*(pbuf + 3) = u8Tmp;
u8Tmp = *(pbuf + 1);
*(pbuf + 1) = *(pbuf + 2);
*(pbuf + 2) = u8Tmp;
u32Size -= 4;
pbuf += 4;
}
if(u32Size > 0)
{
u32Tmp = 0;
for(i = 0; i < u32Size; i++)
{
u32Tmp |= *(pbuf + i) << (24 - i * 8);
}
*((uint32_t *)pbuf) = u32Tmp;
}
return 0;
}
/*
CCM input format must be block alignment. The block size is 16 bytes.
----------------------------------------------------------------------
Block B0
Formatting of the Control Information and the Nonce
----------------------------------------------------------------------
First block B_0:
0 .. 0 flags
1 .. iv_len nonce (aka iv)
iv_len+1 .. 15 length
flags:
With flags as (bits):
7 0
6 add present?
5 .. 3 (t - 2) / 2
2 .. 0 q - 1
*/
int32_t CCMPacker(const uint8_t *iv, uint32_t ivlen, const uint8_t *A, uint32_t alen, const uint8_t *P, uint32_t plen, uint8_t *pbuf, uint32_t *psize, uint32_t tlen, int32_t enc)
{
uint32_t i, j;
uint32_t alen_aligned, plen_aligned;
uint32_t u32Offset = 0;
uint8_t u8Tmp;
uint32_t q = 0;
/* Flags in B0
*With flags as(bits) :
7 0
6 add present ?
5 .. 3 (t - 2) / 2
2 .. 0 q - 1, q = 15 - nlen
*/
if( tlen > 0 )
{
q = 15 - ivlen;
u8Tmp = (q - 1) | ((tlen - 2) / 2 << 3) | ((alen > 0) ? 0x40 : 0);
pbuf[0] = u8Tmp; // flags
for(i = 0; i < ivlen; i++) // N
pbuf[i + 1] = iv[i];
for(i = ivlen + 1, j = q - 1; i < 16; i++, j--) // Q
{
if(j >= 4)
pbuf[i] = 0;
else
{
pbuf[i] = (plen >> j * 8) & 0xfful;
}
}
u32Offset = 16;
}
/* Formatting addition data */
/* alen. It is limited to be smaller than 2^16-2^8 */
if(alen > 0)
{
pbuf[u32Offset] = (alen >> 8) & 0xfful;
pbuf[u32Offset + 1] = alen & 0xfful;
for(i = 0; i < alen; i++)
pbuf[u32Offset + i + 2] = A[i];
alen_aligned = ((alen + 2 + 15) / 16) * 16;
for(i = u32Offset + 2 + alen; i < alen_aligned; i++)
{
pbuf[i] = (enc) ? 0:0xff; // padding zero or 0xff
}
u32Offset += alen_aligned;
}
/* Formatting payload */
if( (plen > 0) && (P != 0x00))
{
plen_aligned = ((plen + 15) / 16) * 16;
for(i = 0; i < plen; i++)
{
pbuf[u32Offset + i] = P[i];
}
for(; i < plen_aligned; i++)
{
pbuf[u32Offset + i] = 0; // padding zero
}
u32Offset += plen_aligned;
}
/* Formatting Ctr0 */
if( ivlen > 0 )
{
pbuf[u32Offset] = q - 1; // Flags
for(i = 0; i < ivlen; i++) // N
{
pbuf[u32Offset + 1 + i] = iv[i];
}
for(; i < 16; i++)
{
pbuf[u32Offset + 1 + i] = 0; // padding zero to block alignment
}
}
*psize = u32Offset;
return 0;
}
#ifdef NVT_CCM_DEBUG
static void DumpBuffHex(uint8_t *pucBuff, int nBytes)
{
int32_t i32Idx, i, len;
i32Idx = 0;
while(nBytes > 0)
{
printf("0x%04X ", i32Idx);
len = (nBytes < 16) ? nBytes : 16;
for(i = 0; i < len; i++)
printf("%02x ", pucBuff[i32Idx + i]);
for(; i < 16; i++)
{
printf(" ");
}
printf(" ");
for(i = 0; i < len; i++)
{
if((pucBuff[i32Idx + i] >= 0x20) && (pucBuff[i32Idx + i] < 127))
printf("%c", pucBuff[i32Idx + i]);
else
printf(".");
nBytes--;
}
i32Idx += len;
printf("\n");
}
printf("\n");
}
static void DumpBuffHex2(uint8_t *pucBuff, int nBytes)
{
int32_t i32Idx, i;
i32Idx = 0;
while(nBytes > 0)
{
printf("0x%04X ", i32Idx);
for(i = 0; i < 16; i += 4)
printf("%08x ", *((uint32_t *)&pucBuff[i32Idx + i]));
i32Idx += 16;
nBytes -= 16;
printf("\n");
}
printf("\n");
}
#endif
static int32_t _CCM_OneShot(mbedtls_ccm_context *ctx, int32_t encDec, const uint8_t *iv, uint32_t ivlen, const uint8_t *A, uint32_t alen, const uint8_t *P, uint32_t plen, uint8_t *buf, uint8_t *tag, uint32_t tlen)
{
uint32_t size, plen_aligned;
const uint8_t* pIn;
uint8_t* pOut;
bool ret;
Debug_CCM_Info(("## FUNC: %s, alen=%lu, plen=%lu, ivlen=%lu, tlen=%lu\n", __FUNCTION__, alen, plen, ivlen, tlen));
#ifdef NVT_CCM_DEBUG
printf("\n");
printf("key (%d):\n", (4 + 2*ctx->keySize)*4 );
DumpBuffHex(ctx->keys, (4 + 2*ctx->keySize)*4);
printf("N (%d):\n", ivlen);
DumpBuffHex(iv, ivlen);
printf("A (%d):\n", alen);
DumpBuffHex(A, alen);
printf("P (%d):\n", plen);
DumpBuffHex(P, plen);
printf("T len = %d\n", tlen);
#endif
/* Prepare the blocked buffer for CCM */
memset(ctx->ccm_buf, 0, MAX_CCM_BUF);
CCMPacker(iv, ivlen, A, alen, P, plen, ctx->ccm_buf, &size, tlen, encDec);
ToBigEndian(ctx->ccm_buf, size + 16);
plen_aligned = (plen & 0xful) ? ((plen + 15) / 16) * 16 : plen;
#ifdef NVT_CCM_DEBUG
printf("input blocks (%d):\n", size);
DumpBuffHex2(ctx->ccm_buf, size);
printf("input key (%d):\n", size);
DumpBuffHex2(ctx->keys, (4 + 2*ctx->keySize)*4);
printf("input Ctr0:\n");
DumpBuffHex2(&(ctx->ccm_buf[size]), 16);
#endif
AES_Open(CRPT, 0, encDec, ctx->opMode, ctx->keySize, AES_OUT_SWAP);
/* Set AES Key into H/W */
AES_SetKey(CRPT, 0, ctx->keys, ctx->keySize);
/* For ctr0 */
AES_SetInitVect(CRPT, 0, (uint32_t *)&ctx->ccm_buf[size]);
/* Set bytes count of A */
CRPT->AES_GCM_ACNT[0] = size - plen_aligned;
CRPT->AES_GCM_ACNT[1] = 0;
CRPT->AES_GCM_PCNT[0] = plen;
CRPT->AES_GCM_PCNT[1] = 0;
pIn = ctx->ccm_buf;
pOut = ctx->out_buf;
AES_SetDMATransfer(CRPT, 0, (uint32_t)pIn, (uint32_t)pOut, size);
crypto_aes_prestart();
/* Start AES crypt */
AES_Start(CRPT, 0, CRYPTO_DMA_ONE_SHOT);
/* Waiting for AES calculation */
ret = crypto_aes_wait();
if( ret == false )
{
printf("###[WARN] AES CCM got NU_CRYPTO_DONE_ERR \n");
return (-1);
}
memcpy(buf, ctx->out_buf, plen);
if(tlen > 16)
{
tlen = 16;
}
memcpy(tag, &ctx->out_buf[plen_aligned], tlen);
Debug_CCM_Info(("OneShot output blocks (%lu)(%lu):\n", size, plen));
#ifdef NVT_CCM_DEBUG
DumpBuffHex2(buf, plen);
printf("OneShot output blocks Tag :\n");
DumpBuffHex2(&ctx->out_buf[plen_aligned], 16);
#endif
return 0;
}
static int32_t AES_Run(mbedtls_ccm_context *ctx, uint32_t u32Option)
{
bool ret;
crypto_aes_prestart();
CRPT->AES_CTL = u32Option | START;
ret = crypto_aes_wait();
if( ret == false )
{
printf("###[WARN] AES CCM got NU_CRYPTO_DONE_ERR \n");
}
return 0;
}
static int32_t _CCM_Cascade(mbedtls_ccm_context *ctx, int32_t encDec, const uint8_t *iv, uint32_t ivlen, const uint8_t *A, uint32_t alen, const uint8_t *P, uint32_t plen, uint8_t *buf, uint8_t *tag, uint32_t tlen)
{
uint32_t size, plen_aligned;
uint32_t u32OptBasic;
int32_t plen_cur;
int32_t len;
const uint8_t *pin;
uint8_t *pout;
Debug_CCM_Info(("## FUNC: %s, alen=%lu, plen=%lu, ivlen=%lu, tlen=%lu\n", __FUNCTION__, alen, plen, ivlen, tlen));
/* Prepare the blocked buffer for CCM */
memset(ctx->ccm_buf, 0, MAX_CCM_BUF);
CCMPacker(iv, ivlen, A, alen, 0, plen, ctx->ccm_buf, &size, tlen, encDec);
ToBigEndian(ctx->ccm_buf, size + 16);
plen_aligned = (plen & 0xful) ? ((plen + 15) / 16) * 16 : plen;
AES_Open(CRPT, 0, encDec, ctx->opMode, ctx->keySize, AES_OUT_SWAP);
/* Set AES Key into H/W */
AES_SetKey(CRPT, 0, ctx->keys, ctx->keySize);
#ifdef NVT_CCM_DEBUG
printf("input blocks (%d):\n", size);
DumpBuffHex2(ctx->ccm_buf, size);
printf("input Ctr0:\n");
DumpBuffHex2(&(ctx->ccm_buf[size]), 16);
#endif
/* For ctr0 */
AES_SetInitVect(CRPT, 0, (uint32_t *)&ctx->ccm_buf[size]);
/* Set bytes count of A */
CRPT->AES_GCM_ACNT[0] = size;
CRPT->AES_GCM_ACNT[1] = 0;
CRPT->AES_GCM_PCNT[0] = plen; //plen_aligned; /* set plen_aligned will get wrong tag @plen=24 */
CRPT->AES_GCM_PCNT[1] = 0;
AES_SetDMATransfer(CRPT, 0, (uint32_t)ctx->ccm_buf, (uint32_t)ctx->out_buf, size);
/* feedback buffer is necessary for cascade mode */
CRPT->AES_FBADDR = (uint32_t)ctx->fb_buf;;
u32OptBasic = CRPT->AES_CTL ;
AES_Run(ctx, u32OptBasic | CCM_MODE | FBOUT | DMAEN);
plen_cur = plen;
pin = P;
pout = buf;
while(plen_cur)
{
len = plen_cur;
if(len > CCM_PBLOCK_SIZE)
{
len = CCM_PBLOCK_SIZE;
}
plen_cur -= len;
/* Prepare the blocked buffer for CCM */
CCMPacker(0, 0, 0, 0, pin, len, ctx->ccm_buf, &size, 0, encDec);
ToBigEndian(ctx->ccm_buf, size);
AES_SetDMATransfer(CRPT, 0, (uint32_t)ctx->ccm_buf, (uint32_t)pout, size);
/* Start AES Eecrypt */
if(plen_cur)
{
/* casecade n */
AES_Run(ctx, u32OptBasic | CCM_MODE | FBIN | FBOUT | DMAEN | DMACC);
}
else
{
/* last cascade */
AES_SetDMATransfer(CRPT, 0, (uint32_t)ctx->ccm_buf, (uint32_t)ctx->out_buf, size);
AES_Run(ctx, u32OptBasic | CCM_MODE | FBIN | FBOUT | DMAEN | DMACC | DMALAST);
memcpy(pout, ctx->out_buf, len);
}
Debug_CCM_Info(("output blocks (%lu)(%lu):\n", size, len));
#ifdef NVT_CCM_DEBUG
DumpBuffHex2(pout, len);
#endif
pin += len;
pout += size;
}
#ifdef NVT_CCM_DEBUG
printf("output blocks Tag :\n");
DumpBuffHex2(&ctx->out_buf[size], 16);
#endif
if(tlen > 16)
{
tlen = 16;
}
memcpy(tag, &ctx->out_buf[size], tlen);
return 0;
}
static int32_t _CCM(mbedtls_ccm_context *ctx, int32_t encDec, const uint8_t *iv, uint32_t ivlen, const uint8_t *A, uint32_t alen, const uint8_t *P, uint32_t plen, uint8_t *buf, uint8_t *tag, uint32_t tlen)
{
uint32_t plen_aligned, alen_aligned;
int32_t ret;
Debug_CCM_Info(("## FUNC: %s, alen=%lu, plen=%lu, ivlen=%lu, tlen=%lu\n", __FUNCTION__, alen, plen, ivlen, tlen));
if(ivlen > 16)
return -1;
/* Formatting addition data: 2 bytes to store A's length */
alen_aligned = ((alen + 2 + 15) / 16) * 16;
plen_aligned = ((plen + 15) / 16) * 16;
/* Length of B0's formatting nonce (aka iv): 16 */
if( (16 + alen_aligned + plen_aligned ) < CCM_PBLOCK_SIZE )
{
ret = _CCM_OneShot(ctx, encDec, iv, ivlen, A, alen, P, plen, buf, tag, tlen);
} else {
ret = _CCM_Cascade(ctx, encDec, iv, ivlen, A, alen, P, plen, buf, tag, tlen);
}
return(ret);
}
/*
* Initialize context
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
{
CCM_VALIDATE( ctx != NULL );
memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
ctx->opMode = AES_MODE_CCM;
/* Init crypto module */
crypto_init();
}
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits )
{
int32_t klen;
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( key != NULL );
CCM_VALIDATE_RET( keybits == 128 || keybits == 192 || keybits == 256 );
klen = keybits / 8;
memcpy(ctx->keys, key, klen);
ToBigEndian((uint8_t *)ctx->keys, klen);
switch( keybits ) {
case 128:
ctx->keySize = AES_KEY_SIZE_128;
break;
case 192:
ctx->keySize = AES_KEY_SIZE_192;
break;
case 256:
ctx->keySize = AES_KEY_SIZE_256;
break;
default :
return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
{
if( ctx == NULL )
return;
/* Uninit crypto module */
crypto_uninit();
mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
}
/*
* Authenticated encryption or decryption
*/
static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
int ret;
/*
* Check length requirements: SP800-38C A.1
* Additional requirement: a < 2^16 - 2^8 to simplify the code.
* 'length' checked later (when writing it to the first block)
*
* Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
*/
if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Also implies q is within bounds */
if( iv_len < 7 || iv_len > 13 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( add_len >= 0xFF00 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
ctx->opMode = AES_MODE_CCM;
ctx->encDec = mode;
/* Acquire ownership of AES H/W */
crypto_aes_acquire();
#if 1
/* Force AES free */
CRPT->AES_CTL = CRPT_AES_CTL_STOP_Msk;
#endif
AES_ENABLE_INT(CRPT);
ret = _CCM(ctx, mode, iv, iv_len, add, add_len, input, length, output, tag, tag_len);
/* Release ownership of AES H/W */
crypto_aes_release();
return( ret );
}
/*
* Authenticated encryption
*/
int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
Debug_CCM_Info(("## FUNC: %s, alen=%u, plen=%u, ivlen=%u, tlen=%u\n", __FUNCTION__, add_len, length, iv_len, tag_len));
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
add, add_len, input, output, tag, tag_len ) );
}
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
Debug_CCM_Info(("## FUNC: %s, alen=%u, plen=%u, ivlen=%u, tlen=%u\n", __FUNCTION__, add_len, length, iv_len, tag_len));
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( tag_len == 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
return( mbedtls_ccm_star_encrypt_and_tag( ctx, length, iv, iv_len, add,
add_len, input, output, tag, tag_len ) );
}
/*
* Authenticated decryption
*/
int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
int ret;
unsigned char check_tag[16];
unsigned char i;
int diff;
Debug_CCM_Info(("## FUNC: %s, alen=%u, plen=%u, ivlen=%u, tlen=%u\n", __FUNCTION__, add_len, length, iv_len, tag_len));
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
iv, iv_len, add, add_len,
input, output, check_tag, tag_len ) ) != 0 )
{
return( ret );
}
/* Check tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
{
mbedtls_platform_zeroize( output, length );
return( MBEDTLS_ERR_CCM_AUTH_FAILED );
}
return( 0 );
}
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
Debug_CCM_Info(("## FUNC: %s, alen=%u, plen=%u, ivlen=%u, tlen=%u\n", __FUNCTION__, add_len, length, iv_len, tag_len));
CCM_VALIDATE_RET( ctx != NULL );
CCM_VALIDATE_RET( iv != NULL );
CCM_VALIDATE_RET( add_len == 0 || add != NULL );
CCM_VALIDATE_RET( length == 0 || input != NULL );
CCM_VALIDATE_RET( length == 0 || output != NULL );
CCM_VALIDATE_RET( tag_len == 0 || tag != NULL );
if( tag_len == 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
return( mbedtls_ccm_star_auth_decrypt( ctx, length, iv, iv_len, add,
add_len, input, output, tag, tag_len ) );
}
#endif /* MBEDTLS_CCM_ALT */
#endif /* MBEDTLS_CCM_C */

View File

@ -0,0 +1,318 @@
/**
* \file ccm.h
*
* \brief This file provides an API for the CCM authenticated encryption
* mode for block ciphers.
*
* CCM combines Counter mode encryption with CBC-MAC authentication
* for 128-bit block ciphers.
*
* Input to CCM includes the following elements:
* <ul><li>Payload - data that is both authenticated and encrypted.</li>
* <li>Associated data (Adata) - data that is authenticated but not
* encrypted, For example, a header.</li>
* <li>Nonce - A unique value that is assigned to the payload and the
* associated data.</li></ul>
*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*
* Definition of CCM*:
* IEEE 802.15.4 - IEEE Standard for Local and metropolitan area networks
* Integer representation is fixed most-significant-octet-first order and
* the representation of octets is most-significant-bit-first order. This is
* consistent with RFC 3610.
*/
/*
* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved
* Copyright (c) 2022, Nuvoton Technology Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CCM_ALT_H
#define MBEDTLS_CCM_ALT_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "mbed_toolchain.h"
#include "mbedtls/cipher.h"
#include "NuMicro.h"
#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to the function. */
#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */
/* MBEDTLS_ERR_CCM_HW_ACCEL_FAILED is deprecated and should not be used. */
#define MBEDTLS_ERR_CCM_HW_ACCEL_FAILED -0x0011 /**< CCM hardware accelerator failed. */
#ifdef __cplusplus
extern "C" {
#endif
// Regular implementation
//
#define MAX_CCM_BUF 256
#define CCM_PBLOCK_SIZE MAX_CCM_BUF
/**
* \brief The CCM context-type definition. The CCM context is passed
* to the APIs called.
*/
typedef struct mbedtls_ccm_context
{
MBED_ALIGN(4) uint8_t ccm_buf[MAX_CCM_BUF + 16]; /* 16 bytes for ctr0 in packer */
MBED_ALIGN(4) uint8_t out_buf[MAX_CCM_BUF + 16]; /* 16 bytes for tag */
MBED_ALIGN(4) uint8_t fb_buf[72]; /* feedback buffer for GCM DMA */
uint32_t keySize;
uint32_t keys[8]; /* Cipher key */
uint32_t encDec; /* 0: decrypt, 1: encrypt */
uint32_t opMode; /* AES_MODE CCM */
}
mbedtls_ccm_context;
/**
* \brief This function initializes the specified CCM context,
* to make references valid, and prepare the context
* for mbedtls_ccm_setkey() or mbedtls_ccm_free().
*
* \param ctx The CCM context to initialize. This must not be \c NULL.
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx );
/**
* \brief This function initializes the CCM context set in the
* \p ctx parameter and sets the encryption key.
*
* \param ctx The CCM context to initialize. This must be an initialized
* context.
* \param cipher The 128-bit block cipher to use.
* \param key The encryption key. This must not be \c NULL.
* \param keybits The key size in bits. This must be acceptable by the cipher.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits );
/**
* \brief This function releases and clears the specified CCM context
* and underlying cipher sub-context.
*
* \param ctx The CCM context to clear. If this is \c NULL, the function
* has no effect. Otherwise, this must be initialized.
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx );
/**
* \brief This function encrypts a buffer using CCM.
*
* \note The tag is written to a separate buffer. To concatenate
* the \p tag with the \p output, as done in <em>RFC-3610:
* Counter with CBC-MAC (CCM)</em>, use
* \p tag = \p output + \p length, and make sure that the
* output buffer is at least \p length + \p tag_len wide.
*
* \param ctx The CCM context to use for encryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param add The additional data field. If \p add_len is greater than
* zero, \p add must be a readable buffer of at least that
* length.
* \param add_len The length of additional data in Bytes.
* This must be less than `2^16 - 2^8`.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len );
/**
* \brief This function encrypts a buffer using CCM*.
*
* \note The tag is written to a separate buffer. To concatenate
* the \p tag with the \p output, as done in <em>RFC-3610:
* Counter with CBC-MAC (CCM)</em>, use
* \p tag = \p output + \p length, and make sure that the
* output buffer is at least \p length + \p tag_len wide.
*
* \note When using this function in a variable tag length context,
* the tag length has to be encoded into the \p iv passed to
* this function.
*
* \param ctx The CCM context to use for encryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param add The additional data field. This must be a readable buffer of
* at least \p add_len Bytes.
* \param add_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 0, 4, 6, 8, 10, 12, 14 or 16.
*
* \warning Passing \c 0 as \p tag_len means that the message is no
* longer authenticated.
*
* \return \c 0 on success.
* \return A CCM or cipher-specific error code on failure.
*/
int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len );
/**
* \brief This function performs a CCM authenticated decryption of a
* buffer.
*
* \param ctx The CCM context to use for decryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param add The additional data field. This must be a readable buffer
* of at least that \p add_len Bytes..
* \param add_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field to generate in Bytes:
* 4, 6, 8, 10, 12, 14 or 16.
*
* \return \c 0 on success. This indicates that the message is authentic.
* \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match.
* \return A cipher-specific error code on calculation failure.
*/
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len );
/**
* \brief This function performs a CCM* authenticated decryption of a
* buffer.
*
* \note When using this function in a variable tag length context,
* the tag length has to be decoded from \p iv and passed to
* this function as \p tag_len. (\p tag needs to be adjusted
* accordingly.)
*
* \param ctx The CCM context to use for decryption. This must be
* initialized and bound to a key.
* \param length The length of the input data in Bytes.
* \param iv The initialization vector (nonce). This must be a readable
* buffer of at least \p iv_len Bytes.
* \param iv_len The length of the nonce in Bytes: 7, 8, 9, 10, 11, 12,
* or 13. The length L of the message length field is
* 15 - \p iv_len.
* \param add The additional data field. This must be a readable buffer of
* at least that \p add_len Bytes.
* \param add_len The length of additional data in Bytes.
* This must be less than 2^16 - 2^8.
* \param input The buffer holding the input data. If \p length is greater
* than zero, \p input must be a readable buffer of at least
* that length.
* \param output The buffer holding the output data. If \p length is greater
* than zero, \p output must be a writable buffer of at least
* that length.
* \param tag The buffer holding the authentication field. This must be a
* readable buffer of at least \p tag_len Bytes.
* \param tag_len The length of the authentication field in Bytes.
* 0, 4, 6, 8, 10, 12, 14 or 16.
*
* \warning Passing \c 0 as \p tag_len means that the message is nos
* longer authenticated.
*
* \return \c 0 on success.
* \return #MBEDTLS_ERR_CCM_AUTH_FAILED if the tag does not match.
* \return A cipher-specific error code on calculation failure.
*/
int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len );
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
/**
* \brief The CCM checkup routine.
*
* \return \c 0 on success.
* \return \c 1 on failure.
*/
int mbedtls_ccm_self_test( int verbose );
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_CCM_ALT_H */

View File

@ -25,6 +25,7 @@
#define MBEDTLS_AES_ALT
#define MBEDTLS_GCM_ALT
#define MBEDTLS_CCM_ALT
#define MBEDTLS_ECP_INTERNAL_ALT
/* Support for Weierstrass curves with Jacobi representation */