#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_CAAM) && defined(WOLFSSL_CMAC) && defined(WOLFSSL_CAAM_CMAC)
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
#include <wolfssl/wolfcrypt/port/caam/wolfcaam_cmac.h>
int wc_CAAM_Cmac(Cmac* cmac, const byte* key, word32 keySz, const byte* in,
word32 inSz, byte* out, word32* outSz, int type, void* ctx)
{
word32 args[4] = {0};
CAAM_BUFFER buf[9];
word32 idx = 0;
byte scratch[WC_AES_BLOCK_SIZE];
int ret;
int blocks = 0;
byte* pt = (byte*)in;
int sz = inSz;
(void)type;
args[0] = 0;
if (outSz != NULL && *outSz > 16) {
return BAD_FUNC_ARG;
}
if (out != NULL && outSz == NULL) {
return BAD_FUNC_ARG;
}
if (key != NULL || ctx != NULL) {
XMEMSET(&cmac->aes, 0, sizeof(Aes));
if (cmac->blackKey == 0) {
if (ctx != NULL) {
cmac->blackKey = 1;
XMEMCPY((byte*)cmac->aes.key, (byte*)ctx, keySz + 16);
}
else {
XMEMCPY((byte*)cmac->aes.key, (byte*)key, keySz);
}
}
cmac->keylen = keySz;
cmac->initialized = 0;
cmac->bufferSz = 0;
XMEMSET(cmac->buffer, 0, WC_AES_BLOCK_SIZE);
return 0;
}
buf[idx].TheAddress = (CAAM_ADDRESS)cmac->aes.key;
buf[idx].Length = cmac->keylen;
idx++;
buf[idx].TheAddress = (CAAM_ADDRESS)cmac->ctx;
buf[idx].Length = sizeof(cmac->ctx);
idx++;
if (in != NULL) {
#ifdef WOLFSSL_HASH_KEEP
if (wc_CMAC_Grow(cmac, in, inSz) != 0) {
WOLFSSL_MSG("Error growing CMAC buffer");
return -1;
}
#else
args[0] |= CAAM_ALG_UPDATE;
if (cmac->bufferSz > 0) {
word32 add;
if (cmac->bufferSz > WC_AES_BLOCK_SIZE) {
WOLFSSL_MSG("Error with CMAC buffer size");
return -1;
}
add = (sz < ((int)(WC_AES_BLOCK_SIZE - cmac->bufferSz))) ? sz :
(int)(WC_AES_BLOCK_SIZE - cmac->bufferSz);
XMEMCPY(&cmac->buffer[cmac->bufferSz], pt, add);
cmac->bufferSz += add;
pt += add;
sz -= add;
}
if (cmac->bufferSz == WC_AES_BLOCK_SIZE && (sz > 0)) {
buf[idx].TheAddress = (CAAM_ADDRESS)scratch;
buf[idx].Length = cmac->bufferSz;
idx++;
blocks++;
cmac->bufferSz = 0;
XMEMCPY(scratch, (byte*)cmac->buffer, WC_AES_BLOCK_SIZE);
}
if ((sz >= WC_AES_BLOCK_SIZE) && (sz % WC_AES_BLOCK_SIZE == 0)) {
if (cmac->bufferSz > 0) {
return BAD_FUNC_ARG;
}
XMEMCPY(&cmac->buffer[0], pt + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
cmac->bufferSz = WC_AES_BLOCK_SIZE;
sz -= WC_AES_BLOCK_SIZE;
}
if (sz >= WC_AES_BLOCK_SIZE) {
buf[idx].TheAddress = (CAAM_ADDRESS)pt;
buf[idx].Length = sz - (sz % WC_AES_BLOCK_SIZE);
blocks += sz / WC_AES_BLOCK_SIZE;
sz -= buf[idx].Length;
pt += buf[idx].Length;
idx++;
}
#endif
}
if (out != NULL) {
#ifdef WOLFSSL_HASH_KEEP
if (cmac->msg != NULL) {
buf[idx].TheAddress = (CAAM_ADDRESS)cmac->msg;
buf[idx].Length = cmac->used;
idx++;
}
#else
if (cmac->bufferSz > 0) {
buf[idx].TheAddress = (CAAM_ADDRESS)cmac->buffer;
buf[idx].Length = cmac->bufferSz;
idx++;
}
#endif
args[0] |= CAAM_ALG_FINAL;
blocks++;
}
args[1] = cmac->keylen;
args[2] = cmac->blackKey;
if (blocks > 0) {
if (cmac->initialized == 0) {
args[0] |= CAAM_ALG_INIT;
cmac->initialized = 1;
}
ret = wc_caamAddAndWait(buf, idx, args, CAAM_CMAC);
if (ret != 0) {
return -1;
}
}
if (out != NULL) {
XMEMCPY(out, cmac->ctx, *outSz);
}
if (sz > 0) {
word32 add = (sz < (int)(WC_AES_BLOCK_SIZE - cmac->bufferSz))?
(word32)sz :
(WC_AES_BLOCK_SIZE - cmac->bufferSz);
if (pt == NULL) {
return MEMORY_E;
}
XMEMCPY(&cmac->buffer[cmac->bufferSz], pt, add);
cmac->bufferSz += add;
}
(void)scratch;
return 0;
}
#endif