#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#if defined(WOLFSSL_CAAM) && !defined(NO_AES)
#include <wolfssl/wolfcrypt/logging.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
#include <wolfssl/wolfcrypt/port/caam/wolfcaam_aes.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#if (defined(HAVE_AESGCM) && defined(WOLFSSL_CAAM_AESGCM)) || \
defined(HAVE_AESCCM)
static int wc_CAAM_AesAeadCommon(Aes* aes, const byte* in, byte* out, word32 sz,
const byte* nonce, word32 nonceSz, byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz, int dir, int type)
{
CAAM_BUFFER buf[7];
int ret, idx = 0;
word32 arg[4];
word32 keySz;
if (aes == NULL) {
return BAD_FUNC_ARG;
}
if (wc_AesGetKeySize(aes, &keySz) != 0 && aes->blackKey == 0) {
return BAD_FUNC_ARG;
}
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)aes->devKey;
buf[idx].Length = keySz;
idx++;
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)nonce;
buf[idx].Length = nonceSz;
idx++;
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)in;
buf[idx].Length = sz;
idx++;
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)out;
buf[idx].Length = sz;
idx++;
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)authTag;
buf[idx].Length = authTagSz;
idx++;
buf[idx].BufferType = DataBuffer | LastBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)authIn;
buf[idx].Length = authInSz;
idx++;
arg[0] = ((authInSz & 0xFFFF) << 16) | (dir & 0xFFFF);
arg[1] = ((nonceSz & 0xFF) << 24) | ((authTagSz & 0xFF) << 16) |
(keySz & 0xFFFF);
arg[2] = sz;
arg[3] = aes->blackKey;
if ((ret = wc_caamAddAndWait(buf, idx, arg, type)) != 0) {
WOLFSSL_MSG("Error with CAAM AES AEAD operation");
return ret;
}
return 0;
}
#endif
#if defined(HAVE_AESCCM)
#ifndef WOLFSSL_SECO_CAAM
static word32 CreateB0CTR(byte* B0Ctr0, const byte* nonce, word32 nonceSz,
word32 authInSz, word32 authTagSz, word32 inSz)
{
word32 i;
word32 lenSz;
byte mask = 0xFF;
const word32 wordSz = (word32)sizeof(word32);
XMEMCPY(B0Ctr0+1, nonce, nonceSz);
XMEMCPY(B0Ctr0+WC_AES_BLOCK_SIZE+1, nonce, nonceSz);
lenSz = WC_AES_BLOCK_SIZE - 1 - (byte)nonceSz;
B0Ctr0[0] = 0;
if (authInSz > 0) {
B0Ctr0[0] |= 0x40;
}
B0Ctr0[0] |= (((byte)authTagSz - 2) / 2) << 3;
B0Ctr0[0] |= lenSz - 1;
for (i = 0; i < lenSz; i++) {
if (mask && i >= wordSz)
mask = 0x00;
B0Ctr0[WC_AES_BLOCK_SIZE - 1 - i] = (inSz >> ((8 * i) & mask)) & mask;
B0Ctr0[WC_AES_BLOCK_SIZE + WC_AES_BLOCK_SIZE - 1 - i] = 0;
}
B0Ctr0[WC_AES_BLOCK_SIZE] = lenSz - 1;
return 0;
}
#endif
int wc_CAAM_AesCcmEncrypt(Aes* aes, const byte* in, byte* out, word32 sz,
const byte* nonce, word32 nonceSz, byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz)
{
#ifndef WOLFSSL_SECO_CAAM
byte B0Ctr0[WC_AES_BLOCK_SIZE + WC_AES_BLOCK_SIZE];
#endif
if (aes == NULL || (sz != 0 && (in == NULL || out == NULL)) ||
nonce == NULL || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
authTagSz > WC_AES_BLOCK_SIZE)
return BAD_FUNC_ARG;
if (wc_AesCcmCheckTagSize(authTagSz) != 0) {
return BAD_FUNC_ARG;
}
#ifndef WOLFSSL_SECO_CAAM
CreateB0CTR(B0Ctr0, nonce, nonceSz, authInSz, authTagSz, sz);
return wc_CAAM_AesAeadCommon(aes, in, out, sz, B0Ctr0, 2*WC_AES_BLOCK_SIZE,
authTag, authTagSz, authIn, authInSz, CAAM_ENC, CAAM_AESCCM);
#else
return wc_CAAM_AesAeadCommon(aes, in, out, sz, nonce, nonceSz,
authTag, authTagSz, authIn, authInSz, CAAM_ENC, CAAM_AESCCM);
#endif
}
int wc_CAAM_AesCcmDecrypt(Aes* aes, const byte* in, byte* out, word32 sz,
const byte* nonce, word32 nonceSz, const byte* authTag,
word32 authTagSz, const byte* authIn, word32 authInSz)
{
int ret;
#ifndef WOLFSSL_SECO_CAAM
byte B0Ctr0[WC_AES_BLOCK_SIZE + WC_AES_BLOCK_SIZE];
#endif
if (aes == NULL || (sz != 0 && (in == NULL || out == NULL)) ||
nonce == NULL || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
authTagSz > WC_AES_BLOCK_SIZE)
return BAD_FUNC_ARG;
if (wc_AesCcmCheckTagSize(authTagSz) != 0) {
return BAD_FUNC_ARG;
}
#ifndef WOLFSSL_SECO_CAAM
CreateB0CTR(B0Ctr0, nonce, nonceSz, authInSz, authTagSz, sz);
ret = wc_CAAM_AesAeadCommon(aes, in, out, sz, B0Ctr0, 2*WC_AES_BLOCK_SIZE,
(byte*)authTag, authTagSz, authIn, authInSz, CAAM_DEC, CAAM_AESCCM);
#else
ret = wc_CAAM_AesAeadCommon(aes, in, out, sz, nonce, nonceSz,
(byte*)authTag, authTagSz, authIn, authInSz, CAAM_DEC, CAAM_AESCCM);
#endif
if (ret != 0) {
#if defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 2) && \
defined(ACVP_VECTOR_TESTING)
WOLFSSL_MSG("Preserve output for vector responses");
#else
if (sz > 0)
XMEMSET(out, 0, sz);
#endif
}
return ret;
}
#endif
#if defined(HAVE_AESGCM) && defined(WOLFSSL_CAAM_AESGCM)
int wc_CAAM_AesGcmEncrypt(Aes* aes, const byte* in, byte* out, word32 sz,
const byte* nonce, word32 nonceSz, byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz)
{
return wc_CAAM_AesAeadCommon(aes, in, out, sz, nonce, nonceSz, authTag,
authTagSz, authIn, authInSz, CAAM_ENC, CAAM_AESGCM);
}
int wc_CAAM_AesGcmDecrypt(Aes* aes, const byte* in, byte* out, word32 sz,
const byte* nonce, word32 nonceSz, const byte* authTag,
word32 authTagSz, const byte* authIn, word32 authInSz)
{
return wc_CAAM_AesAeadCommon(aes, in, out, sz, nonce, nonceSz,
(byte*)authTag, authTagSz, authIn, authInSz, CAAM_DEC, CAAM_AESGCM);
}
#endif
static int wc_CAAM_AesCbcCtrCommon(Aes* aes, byte* out, const byte* in,
word32 sz, int dir, int mode)
{
word32 blocks;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
blocks = sz / WC_AES_BLOCK_SIZE;
if (blocks > 0) {
CAAM_BUFFER buf[5];
word32 arg[4];
word32 keySz;
int ret;
if (wc_AesGetKeySize(aes, &keySz) != 0 && aes->blackKey == 0) {
return BAD_FUNC_ARG;
}
buf[0].BufferType = DataBuffer;
buf[0].TheAddress = (CAAM_ADDRESS)(void*)aes->devKey;
buf[0].Length = keySz;
buf[1].BufferType = DataBuffer;
buf[1].TheAddress = (CAAM_ADDRESS)aes->reg;
buf[1].Length = WC_AES_BLOCK_SIZE;
buf[2].BufferType = DataBuffer;
buf[2].TheAddress = (CAAM_ADDRESS)in;
buf[2].Length = blocks * WC_AES_BLOCK_SIZE;
buf[3].BufferType = DataBuffer | LastBuffer;
buf[3].TheAddress = (CAAM_ADDRESS)out;
buf[3].Length = blocks * WC_AES_BLOCK_SIZE;
buf[4].BufferType = DataBuffer;
buf[4].TheAddress = (CAAM_ADDRESS)aes->reg;
buf[4].Length = WC_AES_BLOCK_SIZE;
arg[0] = dir;
arg[1] = keySz;
arg[2] = blocks * WC_AES_BLOCK_SIZE;
arg[3] = aes->blackKey;
if ((ret = wc_caamAddAndWait(buf, 5, arg, mode)) != 0) {
WOLFSSL_MSG("Error with CAAM AES CBC operation");
return ret;
}
}
return 0;
}
#ifdef WOLFSSL_AES_COUNTER
static WC_INLINE void IncrementAesCounter(byte* inOutCtr)
{
int i;
for (i = WC_AES_BLOCK_SIZE - 1; i >= 0; i--) {
if (++inOutCtr[i])
return;
}
}
int wc_CAAM_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
byte* tmp;
word32 keySz;
int ret, blocks;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if ((ret = wc_AesGetKeySize(aes, &keySz)) != 0) {
return ret;
}
tmp = (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left;
while (aes->left && sz) {
*(out++) = *(in++) ^ *(tmp++);
aes->left--;
sz--;
}
blocks = sz / WC_AES_BLOCK_SIZE;
if (blocks > 0) {
ret = wc_CAAM_AesCbcCtrCommon(aes, out, in, blocks * WC_AES_BLOCK_SIZE,
CAAM_ENC, CAAM_AESCTR);
out += blocks * WC_AES_BLOCK_SIZE;
in += blocks * WC_AES_BLOCK_SIZE;
sz -= blocks * WC_AES_BLOCK_SIZE;
}
if (sz) {
if ((ret = wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg))
!= 0) {
return ret;
}
IncrementAesCounter((byte*)aes->reg);
aes->left = WC_AES_BLOCK_SIZE;
tmp = (byte*)aes->tmp;
while (sz--) {
*(out++) = *(in++) ^ *(tmp++);
aes->left--;
}
}
return ret;
}
#endif
int wc_CAAM_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_CAAM_AesCbcCtrCommon(aes, out, in, sz, CAAM_ENC, CAAM_AESCBC);
}
int wc_CAAM_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_CAAM_AesCbcCtrCommon(aes, out, in, sz, CAAM_DEC, CAAM_AESCBC);
}
#if defined(HAVE_AES_ECB)
static int wc_CAAM_AesEcbCommon(Aes* aes, byte* out, const byte* in, word32 sz,
int dir)
{
word32 blocks;
CAAM_BUFFER buf[4];
word32 arg[4];
word32 keySz = 0;
int ret;
int idx = 0;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
blocks = sz / WC_AES_BLOCK_SIZE;
if (wc_AesGetKeySize(aes, &keySz) != 0 && aes->blackKey == 0) {
return BAD_FUNC_ARG;
}
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)aes->devKey;
buf[idx].Length = keySz;
idx++;
buf[idx].BufferType = DataBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)in;
buf[idx].Length = blocks * WC_AES_BLOCK_SIZE;
idx++;
buf[idx].BufferType = DataBuffer | LastBuffer;
buf[idx].TheAddress = (CAAM_ADDRESS)out;
buf[idx].Length = blocks * WC_AES_BLOCK_SIZE;
idx++;
arg[0] = dir;
arg[1] = keySz;
arg[2] = blocks * WC_AES_BLOCK_SIZE;
arg[3] = aes->blackKey;
if ((ret = wc_caamAddAndWait(buf, idx, arg, CAAM_AESECB)) != 0) {
WOLFSSL_MSG("Error with CAAM AES ECB encrypt");
return ret;
}
return 0;
}
int wc_CAAM_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_CAAM_AesEcbCommon(aes, out, in, sz, CAAM_ENC);
}
int wc_CAAM_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_CAAM_AesEcbCommon(aes, out, in, sz, CAAM_DEC);
}
#endif
#endif