#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if !defined(NO_AES) && defined(WOLFSSL_DEVCRYPTO)
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/port/devcrypto/wc_devcrypto.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#if defined(HAVE_AES_CBC) && defined(WOLFSSL_DEVCRYPTO_CBC)
int wc_AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
struct crypt_op crt;
int ret;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
sz = sz - (sz % WC_AES_BLOCK_SIZE);
if (sz == 0) {
return 0;
}
if (aes->ctx.cfd == -1) {
ret = wc_DevCryptoCreate(&aes->ctx, CRYPTO_AES_CBC,
(byte*)aes->devKey, aes->keylen);
if (ret != 0)
return ret;
}
wc_SetupCryptSym(&crt, &aes->ctx, (byte*)in, sz, out, (byte*)aes->reg,
COP_ENCRYPT);
ret = ioctl(aes->ctx.cfd, CIOCCRYPT, &crt);
if (ret != 0) {
return WC_DEVCRYPTO_E;
}
XMEMCPY(aes->reg, out + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
return 0;
}
#ifdef HAVE_AES_DECRYPT
int wc_AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
struct crypt_op crt;
int ret;
if (aes == NULL || out == NULL || in == NULL || sz % WC_AES_BLOCK_SIZE != 0) {
return BAD_FUNC_ARG;
}
if (sz == 0) {
return 0;
}
XMEMCPY(aes->tmp, in + sz - WC_AES_BLOCK_SIZE, WC_AES_BLOCK_SIZE);
if (aes->ctx.cfd == -1) {
ret = wc_DevCryptoCreate(&aes->ctx, CRYPTO_AES_CBC,
(byte*)aes->devKey, aes->keylen);
if (ret != 0)
return ret;
}
wc_SetupCryptSym(&crt, &aes->ctx, (byte*)in, sz, out, (byte*)aes->reg,
COP_DECRYPT);
ret = ioctl(aes->ctx.cfd, CIOCCRYPT, &crt);
if (ret != 0) {
return WC_DEVCRYPTO_E;
}
XMEMCPY(aes->reg, aes->tmp, WC_AES_BLOCK_SIZE);
return 0;
}
#endif
#endif
#ifdef WOLFSSL_DEVCRYPTO_AES
int wc_AesSetKey(Aes* aes, const byte* userKey, word32 keylen,
const byte* iv, int dir)
{
#if defined(AES_MAX_KEY_SIZE)
const word32 max_key_len = (AES_MAX_KEY_SIZE / 8);
#endif
if (aes == NULL ||
!((keylen == 16) || (keylen == 24) || (keylen == 32))) {
return BAD_FUNC_ARG;
}
#if defined(AES_MAX_KEY_SIZE)
if (keylen > max_key_len) {
return BAD_FUNC_ARG;
}
#endif
aes->keylen = keylen;
aes->rounds = keylen/4 + 6;
#if defined(WOLFSSL_AES_COUNTER) || defined(WOLFSSL_AES_CFB) || \
defined(WOLFSSL_AES_OFB) || defined(WOLFSSL_AES_XTS)
aes->left = 0;
#endif
aes->ctx.cfd = -1;
XMEMCPY(aes->devKey, userKey, keylen);
(void)dir;
return wc_AesSetIV(aes, iv);
}
#if defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AES_ECB)
static int wc_DevCrypto_AesDirect(Aes* aes, byte* out, const byte* in,
word32 sz, int dir)
{
int ret;
struct crypt_op crt;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if (aes->ctx.cfd == -1) {
ret = wc_DevCryptoCreate(&aes->ctx, CRYPTO_AES_ECB, (byte*)aes->devKey,
aes->keylen);
if (ret != 0)
return ret;
}
wc_SetupCryptSym(&crt, &aes->ctx, (byte*)in, sz, out, NULL, dir);
ret = ioctl(aes->ctx.cfd, CIOCCRYPT, &crt);
if (ret != 0) {
return WC_DEVCRYPTO_E;
}
return 0;
}
#endif
#if defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AESCCM)
int wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
{
return wc_DevCrypto_AesDirect(aes, out, in, WC_AES_BLOCK_SIZE, COP_ENCRYPT);
}
int wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
{
return wc_DevCrypto_AesDirect(aes, out, in, WC_AES_BLOCK_SIZE, COP_DECRYPT);
}
int wc_AesSetKeyDirect(Aes* aes, const byte* userKey, word32 keylen,
const byte* iv, int dir)
{
return wc_AesSetKey(aes, userKey, keylen, iv, dir);
}
#endif
#if defined(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_AesCtrEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
int ret;
struct crypt_op crt;
byte* tmp;
if (aes == NULL || out == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
tmp = (byte*)aes->tmp + WC_AES_BLOCK_SIZE - aes->left;
while (aes->left && sz) {
*(out++) = *(in++) ^ *(tmp++);
aes->left--;
sz--;
}
if (aes->ctx.cfd == -1) {
ret = wc_DevCryptoCreate(&aes->ctx, CRYPTO_AES_CTR, (byte*)aes->devKey,
aes->keylen);
if (ret != 0)
return ret;
}
if (sz > 0) {
tmp = (byte*)aes->tmp;
XMEMSET(tmp, 0, WC_AES_BLOCK_SIZE);
wc_SetupCryptSym(&crt, &aes->ctx, (byte*)in, sz, out, (byte*)aes->reg,
COP_ENCRYPT);
ret = ioctl(aes->ctx.cfd, CIOCCRYPT, &crt);
if (ret != 0) {
return WC_DEVCRYPTO_E;
}
while (sz >= WC_AES_BLOCK_SIZE) {
IncrementAesCounter((byte*)aes->reg);
sz -= WC_AES_BLOCK_SIZE;
out += WC_AES_BLOCK_SIZE;
in += WC_AES_BLOCK_SIZE;
}
}
if (sz > 0) {
Aes tmpAes;
if ((ret = wc_AesSetKey(&tmpAes, (byte*)aes->devKey, aes->keylen,
(byte*)aes->reg, AES_ENCRYPTION)) != 0)
return ret;
if ((ret = wc_AesEncryptDirect(&tmpAes, (byte*)aes->tmp,
(const byte*)aes->reg)) != 0)
return ret;
wc_AesFree(&tmpAes);
IncrementAesCounter((byte*)aes->reg);
aes->left = WC_AES_BLOCK_SIZE - (sz % WC_AES_BLOCK_SIZE);
}
return 0;
}
#endif
#ifdef HAVE_AESGCM
int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
{
return wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION);
}
static int wc_DevCrypto_AesGcm(Aes* aes, byte* out, byte* in, word32 sz,
const byte* iv, word32 ivSz,
byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz,
int dir)
{
struct crypt_auth_op crt = {0};
int ret;
byte scratch[WC_AES_BLOCK_SIZE];
if (aes == NULL || authTagSz > WC_AES_BLOCK_SIZE) {
return BAD_FUNC_ARG;
}
if (out == NULL)
out = scratch;
if (in == NULL)
in = scratch;
XMEMSET(scratch, 0, WC_AES_BLOCK_SIZE);
if (aes->ctx.cfd == -1) {
ret = wc_DevCryptoCreate(&aes->ctx, CRYPTO_AES_GCM, (byte*)aes->devKey,
aes->keylen);
if (ret != 0)
return ret;
}
if (dir == COP_DECRYPT) {
XMEMCPY(in + sz, authTag, authTagSz);
sz += authTagSz;
}
else{
authTagSz = WC_AES_BLOCK_SIZE;
}
wc_SetupCryptAead(&crt, &aes->ctx, (byte*)in, sz, out, (byte*)iv, ivSz,
dir, (byte*)authIn, authInSz, authTag, authTagSz);
ret = ioctl(aes->ctx.cfd, CIOCAUTHCRYPT, &crt);
if (ret != 0) {
#ifdef DEBUG_WOLFSSL
if (authInSz > sysconf(_SC_PAGESIZE)) {
WOLFSSL_MSG("authIn Buffer greater than System Page Size");
}
#endif
if (dir == COP_DECRYPT) {
return AES_GCM_AUTH_E;
}
else {
return WC_DEVCRYPTO_E;
}
}
if (dir == COP_ENCRYPT) {
XMEMCPY(authTag, out + sz, authTagSz);
}
return 0;
}
int wc_AesGcmEncrypt(Aes* aes, byte* out, const byte* in, word32 sz,
const byte* iv, word32 ivSz,
byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz)
{
if (authTagSz < WOLFSSL_MIN_AUTH_TAG_SZ) {
WOLFSSL_MSG("GcmEncrypt authTagSz too small error");
return BAD_FUNC_ARG;
}
return wc_DevCrypto_AesGcm(aes, out, (byte*)in, sz, iv, ivSz,
authTag, authTagSz, authIn, authInSz,
COP_ENCRYPT);
}
#if defined(HAVE_AES_DECRYPT) || defined(HAVE_AESGCM_DECRYPT)
int wc_AesGcmDecrypt(Aes* aes, byte* out, const byte* in, word32 sz,
const byte* iv, word32 ivSz,
const byte* authTag, word32 authTagSz,
const byte* authIn, word32 authInSz)
{
return wc_DevCrypto_AesGcm(aes, out, (byte*)in, sz, iv, ivSz,
(byte*)authTag, authTagSz, authIn, authInSz,
COP_DECRYPT);
}
#endif
#endif
#ifdef HAVE_AES_ECB
int wc_AesEcbEncrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_DevCrypto_AesDirect(aes, out, in, sz, COP_ENCRYPT);
}
int wc_AesEcbDecrypt(Aes* aes, byte* out, const byte* in, word32 sz)
{
return wc_DevCrypto_AesDirect(aes, out, in, sz, COP_DECRYPT);
}
#endif
#endif
#endif