mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-02-01 10:09:21 +01:00
Automated replacement with ``` git ls-files -z wolfcrypt/src/port/ IDE/ | xargs -0 pcre2grep -l '[^_]AES_BLOCK_SIZE' | xargs sed --regexp-extended --in-place 's/([^_])AES_BLOCK_SIZE/\1WC_AES_BLOCK_SIZE/g' ``` Checked for mis-transformations with ``` git ls-files -z | xargs -0 pcre2grep '[^-[()+*/[:space:]]WC_AES_BLOCK_SIZE' | less ``` Checked for residual hits with ``` git ls-files -z | xargs -0 pcre2grep '[^_]AES_BLOCK_SIZE' | less ``` Deliberately excluded: * ChangeLog.md -- do not alter history. * doc/ -- do not confuse documentation with newly prefixed macro, because AES_BLOCK_SIZE is available unless -DOPENSSL_COEXIST. * tests/api.c -- the unit tests deliberately use compatibility names, and are not compatible with -DOPENSSL_COEXIST. * wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs -- false positive hits on C# names. * wrapper/CSharp/wolfCrypt-Test/wolfCrypt-Test.cs -- false positive hits on C# names. * reference in wolfssl/wolfcrypt/aes.h that defines AES_BLOCK_SIZE when -UOPENSSL_COEXIST. * reference in wolfssl/wolfcrypt/settings.h that defines WC_AES_BLOCK_SIZE for old FIPS when -UWC_AES_BLOCK_SIZE.
394 lines
11 KiB
C
394 lines
11 KiB
C
/* devcrypto_aes.c
|
|
*
|
|
* Copyright (C) 2006-2024 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
#include <wolfssl/wolfcrypt/error-crypt.h>
|
|
|
|
#if !defined(NO_AES) && defined(WOLFSSL_DEVCRYPTO)
|
|
|
|
#include <wolfssl/wolfcrypt/aes.h>
|
|
#include <wolfssl/wolfcrypt/logging.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;
|
|
}
|
|
|
|
/* encrypt only up to AES block size of date */
|
|
sz = sz - (sz % 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_ENCRYPT);
|
|
ret = ioctl(aes->ctx.cfd, CIOCCRYPT, &crt);
|
|
if (ret != 0) {
|
|
return WC_DEVCRYPTO_E;
|
|
}
|
|
|
|
/* store iv for next call */
|
|
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;
|
|
}
|
|
|
|
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 /* HAVE_AES_DECRYPT */
|
|
#endif /* HAVE_AES_CBC && WOLFSSL_DEVCRYPTO_CBC */
|
|
|
|
|
|
#ifdef WOLFSSL_DEVCRYPTO_AES /* all AES algorithms supported */
|
|
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)
|
|
/* Check key length */
|
|
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);
|
|
}
|
|
|
|
|
|
/* AES-DIRECT */
|
|
#if defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AES_ECB)
|
|
|
|
/* common code between ECB encrypt and decrypt
|
|
* returns 0 on success */
|
|
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
|
|
|
|
|
|
/* AES-CTR */
|
|
#if defined(WOLFSSL_AES_COUNTER)
|
|
|
|
/* Increment AES counter */
|
|
static WC_INLINE void IncrementAesCounter(byte* inOutCtr)
|
|
{
|
|
/* in network byte order so start at end and work back */
|
|
int i;
|
|
for (i = WC_AES_BLOCK_SIZE - 1; i >= 0; i--) {
|
|
if (++inOutCtr[i]) /* we're done unless we overflow */
|
|
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;
|
|
}
|
|
|
|
/* consume any unused bytes left in aes->tmp */
|
|
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) {
|
|
/* clear previously leftover data */
|
|
tmp = (byte*)aes->tmp;
|
|
XMEMSET(tmp, 0, WC_AES_BLOCK_SIZE);
|
|
|
|
/* update IV */
|
|
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;
|
|
}
|
|
|
|
/* adjust counter after call to hardware */
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* create key stream for later if needed */
|
|
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 /* WOLFSSL_AES_COUNTER */
|
|
|
|
|
|
#ifdef HAVE_AESGCM
|
|
|
|
int wc_AesGcmSetKey(Aes* aes, const byte* key, word32 len)
|
|
{
|
|
return wc_AesSetKey(aes, key, len, NULL, AES_ENCRYPTION);
|
|
}
|
|
|
|
|
|
|
|
/* common code for AES-GCM encrypt/decrypt */
|
|
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];
|
|
|
|
/* argument checks */
|
|
if (aes == NULL || authTagSz > WC_AES_BLOCK_SIZE) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Account for NULL in/out buffers. Up to tag size is still written into
|
|
* in/out buffers */
|
|
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 decrypting then the tag is expected to be at the end of "in" buffer */
|
|
if (dir == COP_DECRYPT) {
|
|
XMEMCPY(in + sz, authTag, authTagSz);
|
|
sz += authTagSz;
|
|
}
|
|
else{
|
|
/* get full tag from hardware */
|
|
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 WOLFSSL_DEBUG
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* after encryption the tag has been placed at the end of "out" buffer */
|
|
if (dir == COP_ENCRYPT) {
|
|
XMEMCPY(authTag, out + sz, authTagSz);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* it is assumed that "out" buffer has enough room for cipher text + tag */
|
|
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)
|
|
/* it is assumed that "in" buffer has enough room for cipher text + tag */
|
|
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 /* HAVE_AES_DECRYPT || HAVE_AESGCM_DECRYPT */
|
|
#endif /* HAVE_AESGCM */
|
|
|
|
|
|
#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 /* HAVE_AES_ECB */
|
|
#endif /* WOLFSSL_DEVCRYPTO_AES */
|
|
#endif /* !NO_AES && WOLFSSL_DEVCRYPTO */
|
|
|