Merge pull request #1128 from JacobBarthelmeh/AES

AES XTS feature addition
This commit is contained in:
toddouska
2017-09-13 14:38:15 -07:00
committed by GitHub
7 changed files with 1184 additions and 0 deletions

View File

@ -185,6 +185,7 @@ then
enable_psk=yes
enable_idea=yes
enable_cmac=yes
enable_xts=yes
enable_webserver=yes
enable_hc128=yes
enable_rabbit=yes
@ -1749,6 +1750,17 @@ AS_IF([test "x$ENABLED_CMAC" = "xyes"],
AM_CONDITIONAL([BUILD_CMAC], [test "x$ENABLED_CMAC" = "xyes"])
# AES-XTS
AC_ARG_ENABLE([xts],
[AS_HELP_STRING([--enable-xts],[Enable XTS (default: disabled)])],
[ ENABLED_XTS=$enableval ],
[ ENABLED_XTS=no ]
)
AS_IF([test "x$ENABLED_XTS" = "xyes"],
[AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"])
# Web Server Build
AC_ARG_ENABLE([webserver],
[AS_HELP_STRING([--enable-webserver],[Enable Web Server (default: disabled)])],

View File

@ -718,6 +718,9 @@ static void* benchmarks_do(void* args)
bench_aesgcm(1);
#endif
#endif
#ifdef WOLFSSL_AES_XTS
bench_aesxts();
#endif
#ifdef WOLFSSL_AES_COUNTER
bench_aesctr();
#endif
@ -1337,6 +1340,71 @@ exit:
#endif /* HAVE_AESGCM */
#ifdef WOLFSSL_AES_XTS
void bench_aesxts(void)
{
XtsAes aes;
double start;
int i, count, ret;
static unsigned char k1[] = {
0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35,
0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62,
0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18,
0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f
};
static unsigned char i1[] = {
0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6,
0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5
};
ret = wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId);
if (ret != 0) {
printf("wc_AesXtsSetKey failed, ret = %d\n", ret);
return;
}
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
if ((ret = wc_AesXtsEncrypt(&aes, bench_plain, bench_cipher,
BENCH_SIZE, i1, sizeof(i1))) != 0) {
printf("wc_AesXtsEncrypt failed, ret = %d\n", ret);
return;
}
}
count += i;
} while (bench_stats_sym_check(start));
bench_stats_sym_finish("AES-XTS-enc", 0, count, start, ret);
wc_AesXtsFree(&aes);
/* decryption benchmark */
ret = wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_DECRYPTION,
HEAP_HINT, devId);
if (ret != 0) {
printf("wc_AesXtsSetKey failed, ret = %d\n", ret);
return;
}
bench_stats_start(&count, &start);
do {
for (i = 0; i < numBlocks; i++) {
if ((ret = wc_AesXtsDecrypt(&aes, bench_plain, bench_cipher,
BENCH_SIZE, i1, sizeof(i1))) != 0) {
printf("wc_AesXtsDecrypt failed, ret = %d\n", ret);
return;
}
}
count += i;
} while (bench_stats_sym_check(start));
bench_stats_sym_finish("AES-XTS-dec", 0, count, start, ret);
wc_AesXtsFree(&aes);
}
#endif /* WOLFSSL_AES_XTS */
#ifdef WOLFSSL_AES_COUNTER
void bench_aesctr(void)
{

View File

@ -50,6 +50,7 @@ void bench_chacha20_poly1305_aead(void);
void bench_aescbc(int);
void bench_aesgcm(int);
void bench_aesccm(void);
void bench_aesxts(void);
void bench_aesctr(void);
void bench_poly1305(void);
void bench_camellia(void);

View File

@ -8010,5 +8010,354 @@ int wc_AesKeyUnWrap(const byte* key, word32 keySz, const byte* in, word32 inSz,
#endif /* HAVE_AES_KEYWRAP */
#ifdef WOLFSSL_AES_XTS
/* Galios Field to use */
#define GF_XTS 0x87
/* This is to help with setting keys to correct encrypt or decrypt type.
*
* tweak AES key for tweak in XTS
* aes AES key for encrypt/decrypt process
* key buffer holding aes key | tweak key
* len length of key buffer in bytes. Should be twice that of key size. i.e.
* 32 for a 16 byte key.
* dir direction, either AES_ENCRYPTION or AES_DECRYPTION
* heap heap hint to use for memory. Can be NULL
* devId id to use with async crypto. Can be 0
*
* Note: is up to user to call wc_AesFree on tweak and aes key when done.
*
* return 0 on success
*/
int wc_AesXtsSetKey(XtsAes* aes, const byte* key, word32 len, int dir,
void* heap, int devId)
{
word32 keySz;
int ret = 0;
if (aes == NULL || key == NULL) {
return BAD_FUNC_ARG;
}
if ((ret = wc_AesInit(&aes->tweak, heap, devId)) != 0) {
return ret;
}
if ((ret = wc_AesInit(&aes->aes, heap, devId)) != 0) {
return ret;
}
keySz = len/2;
if (keySz != 16 && keySz != 32) {
WOLFSSL_MSG("Unsupported key size");
return WC_KEY_SIZE_E;
}
if ((ret = wc_AesSetKey(&aes->aes, key, keySz, NULL, dir)) == 0) {
ret = wc_AesSetKey(&aes->tweak, key + keySz, keySz, NULL,
AES_ENCRYPTION);
if (ret != 0) {
wc_AesFree(&aes->aes);
}
}
return ret;
}
/* This is used to free up resources used by Aes structs
*
* aes AES keys to free
*
* return 0 on success
*/
int wc_AesXtsFree(XtsAes* aes)
{
if (aes != NULL) {
wc_AesFree(&aes->aes);
wc_AesFree(&aes->tweak);
}
return 0;
}
/* Same process as wc_AesXtsEncrypt but uses a word64 type as the tweak value
* instead of a byte array. This just converts the word64 to a byte array and
* calls wc_AesXtsEncrypt.
*
* aes AES keys to use for block encrypt/decrypt
* out output buffer to hold cipher text
* in input plain text buffer to encrypt
* sz size of both out and in buffers
* sector value to use for tweak
*
* returns 0 on success
*/
int wc_AesXtsEncryptSector(XtsAes* aes, byte* out, const byte* in,
word32 sz, word64 sector)
{
byte* pt;
byte i[AES_BLOCK_SIZE];
XMEMSET(i, 0, AES_BLOCK_SIZE);
#ifdef BIG_ENDIAN_ORDER
sector = ByteReverseWord64(sector);
#endif
pt = (byte*)&sector;
XMEMCPY(i, pt, sizeof(word64));
return wc_AesXtsEncrypt(aes, out, in, sz, (const byte*)i, AES_BLOCK_SIZE);
}
/* Same process as wc_AesXtsDecrypt but uses a word64 type as the tweak value
* instead of a byte array. This just converts the word64 to a byte array.
*
* aes AES keys to use for block encrypt/decrypt
* out output buffer to hold plain text
* in input cipher text buffer to encrypt
* sz size of both out and in buffers
* sector value to use for tweak
*
* returns 0 on success
*/
int wc_AesXtsDecryptSector(XtsAes* aes, byte* out, const byte* in, word32 sz,
word64 sector)
{
byte* pt;
byte i[AES_BLOCK_SIZE];
XMEMSET(i, 0, AES_BLOCK_SIZE);
#ifdef BIG_ENDIAN_ORDER
sector = ByteReverseWord64(sector);
#endif
pt = (byte*)&sector;
XMEMCPY(i, pt, sizeof(word64));
return wc_AesXtsDecrypt(aes, out, in, sz, (const byte*)i, AES_BLOCK_SIZE);
}
/* AES with XTS mode. (XTS) XEX encryption with Tweak and cipher text Stealing.
*
* xaes AES keys to use for block encrypt/decrypt
* out output buffer to hold cipher text
* in input plain text buffer to encrypt
* sz size of both out and in buffers
* i value to use for tweak
* iSz size of i buffer, should always be AES_BLOCK_SIZE but having this input
* adds a sanity check on how the user calls the function.
*
* returns 0 on success
*/
int wc_AesXtsEncrypt(XtsAes* xaes, byte* out, const byte* in, word32 sz,
const byte* i, word32 iSz)
{
int ret = 0;
word32 blocks = (sz / AES_BLOCK_SIZE);
Aes *aes, *tweak;
if (xaes == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
aes = &xaes->aes;
tweak = &xaes->tweak;
if (iSz < AES_BLOCK_SIZE) {
return BAD_FUNC_ARG;
}
if (in == NULL && sz > 0) {
return BAD_FUNC_ARG;
}
if (blocks > 0) {
byte tmp[AES_BLOCK_SIZE];
wc_AesEncryptDirect(tweak, tmp, i);
while (blocks > 0) {
word32 j;
byte carry = 0;
byte buf[AES_BLOCK_SIZE];
XMEMCPY(buf, in, AES_BLOCK_SIZE);
xorbuf(buf, tmp, AES_BLOCK_SIZE);
wc_AesEncryptDirect(aes, out, buf);
xorbuf(out, tmp, AES_BLOCK_SIZE);
/* multiply by shift left and propogate carry */
for (j = 0; j < AES_BLOCK_SIZE; j++) {
byte tmpC;
tmpC = (tmp[j] >> 7) & 0x01;
tmp[j] = ((tmp[j] << 1) + carry) & 0xFF;
carry = tmpC;
}
if (carry) {
tmp[0] ^= GF_XTS;
}
carry = 0;
in += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
sz -= AES_BLOCK_SIZE;
blocks--;
}
/* stealing operation of XTS to handle left overs */
if (sz > 0) {
byte buf[AES_BLOCK_SIZE];
XMEMCPY(buf, out - AES_BLOCK_SIZE, AES_BLOCK_SIZE);
if (sz >= AES_BLOCK_SIZE) { /* extra sanity check before copy */
return BUFFER_E;
}
XMEMCPY(out, buf, sz);
XMEMCPY(buf, in, sz);
xorbuf(buf, tmp, AES_BLOCK_SIZE);
wc_AesEncryptDirect(aes, out - AES_BLOCK_SIZE, buf);
xorbuf(out - AES_BLOCK_SIZE, tmp, AES_BLOCK_SIZE);
}
}
else {
WOLFSSL_MSG("Plain text input too small for encryption");
return BAD_FUNC_ARG;
}
return ret;
}
/* Same process as encryption but Aes key is AES_DECRYPTION type.
*
* xaes AES keys to use for block encrypt/decrypt
* out output buffer to hold plain text
* in input cipher text buffer to decrypt
* sz size of both out and in buffers
* i value to use for tweak
* iSz size of i buffer, should always be AES_BLOCK_SIZE but having this input
* adds a sanity check on how the user calls the function.
*
* returns 0 on success
*/
int wc_AesXtsDecrypt(XtsAes* xaes, byte* out, const byte* in, word32 sz,
const byte* i, word32 iSz)
{
int ret = 0;
word32 blocks = (sz / AES_BLOCK_SIZE);
Aes *aes, *tweak;
if (xaes == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
aes = &xaes->aes;
tweak = &xaes->tweak;
if (iSz < AES_BLOCK_SIZE) {
return BAD_FUNC_ARG;
}
if (in == NULL && sz > 0) {
return BAD_FUNC_ARG;
}
if (blocks > 0) {
word32 j;
byte carry = 0;
byte tmp[AES_BLOCK_SIZE];
byte stl = (sz % AES_BLOCK_SIZE);
wc_AesEncryptDirect(tweak, tmp, i);
/* if Stealing then break out of loop one block early to handle special
* case */
if (stl > 0) {
blocks--;
}
while (blocks > 0) {
byte buf[AES_BLOCK_SIZE];
XMEMCPY(buf, in, AES_BLOCK_SIZE);
xorbuf(buf, tmp, AES_BLOCK_SIZE);
wc_AesDecryptDirect(aes, out, buf);
xorbuf(out, tmp, AES_BLOCK_SIZE);
/* multiply by shift left and propogate carry */
for (j = 0; j < AES_BLOCK_SIZE; j++) {
byte tmpC;
tmpC = (tmp[j] >> 7) & 0x01;
tmp[j] = ((tmp[j] << 1) + carry) & 0xFF;
carry = tmpC;
}
if (carry) {
tmp[0] ^= GF_XTS;
}
carry = 0;
in += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
sz -= AES_BLOCK_SIZE;
blocks--;
}
/* stealing operation of XTS to handle left overs */
if (sz > 0) {
byte buf[AES_BLOCK_SIZE];
byte tmp2[AES_BLOCK_SIZE];
/* multiply by shift left and propogate carry */
for (j = 0; j < AES_BLOCK_SIZE; j++) {
byte tmpC;
tmpC = (tmp[j] >> 7) & 0x01;
tmp2[j] = ((tmp[j] << 1) + carry) & 0xFF;
carry = tmpC;
}
if (carry) {
tmp2[0] ^= GF_XTS;
}
XMEMCPY(buf, in, AES_BLOCK_SIZE);
xorbuf(buf, tmp2, AES_BLOCK_SIZE);
wc_AesDecryptDirect(aes, out, buf);
xorbuf(out, tmp2, AES_BLOCK_SIZE);
/* tmp2 holds partial | last */
XMEMCPY(tmp2, out, AES_BLOCK_SIZE);
in += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
sz -= AES_BLOCK_SIZE;
/* Make buffer with end of cipher text | last */
XMEMCPY(buf, tmp2, AES_BLOCK_SIZE);
if (sz >= AES_BLOCK_SIZE) { /* extra sanity check before copy */
return BUFFER_E;
}
XMEMCPY(buf, in, sz);
XMEMCPY(out, tmp2, sz);
xorbuf(buf, tmp, AES_BLOCK_SIZE);
wc_AesDecryptDirect(aes, tmp2, buf);
xorbuf(tmp2, tmp, AES_BLOCK_SIZE);
XMEMCPY(out - AES_BLOCK_SIZE, tmp2, AES_BLOCK_SIZE);
}
}
else {
WOLFSSL_MSG("Plain text input too small for encryption");
return BAD_FUNC_ARG;
}
return ret;
}
#endif /* WOLFSSL_AES_XTS */
#endif /* HAVE_FIPS */
#endif /* !NO_AES */

View File

@ -4202,6 +4202,509 @@ static int aes_key_size_test(void)
return 0;
}
#if defined(WOLFSSL_AES_XTS)
/* test vectors from http://csrc.nist.gov/groups/STM/cavp/block-cipher-modes.html */
static int aes_xts_128_test(void)
{
XtsAes aes;
int ret = 0;
unsigned char buf[AES_BLOCK_SIZE * 2];
unsigned char cipher[AES_BLOCK_SIZE * 2];
/* 128 key tests */
static unsigned char k1[] = {
0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35,
0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62,
0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18,
0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f
};
static unsigned char i1[] = {
0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6,
0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5
};
static unsigned char p1[] = {
0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d,
0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c
};
/* plain text test of partial block is not from NIST test vector list */
static unsigned char pp[] = {
0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d,
0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c,
0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5
};
static unsigned char c1[] = {
0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a,
0x82, 0x50, 0x81, 0xd5, 0xbe, 0x47, 0x1c, 0x63
};
static unsigned char k2[] = {
0x39, 0x25, 0x79, 0x05, 0xdf, 0xcc, 0x77, 0x76,
0x6c, 0x87, 0x0a, 0x80, 0x6a, 0x60, 0xe3, 0xc0,
0x93, 0xd1, 0x2a, 0xcf, 0xcb, 0x51, 0x42, 0xfa,
0x09, 0x69, 0x89, 0x62, 0x5b, 0x60, 0xdb, 0x16
};
static unsigned char i2[] = {
0x5c, 0xf7, 0x9d, 0xb6, 0xc5, 0xcd, 0x99, 0x1a,
0x1c, 0x78, 0x81, 0x42, 0x24, 0x95, 0x1e, 0x84
};
static unsigned char p2[] = {
0xbd, 0xc5, 0x46, 0x8f, 0xbc, 0x8d, 0x50, 0xa1,
0x0d, 0x1c, 0x85, 0x7f, 0x79, 0x1c, 0x5c, 0xba,
0xb3, 0x81, 0x0d, 0x0d, 0x73, 0xcf, 0x8f, 0x20,
0x46, 0xb1, 0xd1, 0x9e, 0x7d, 0x5d, 0x8a, 0x56
};
static unsigned char c2[] = {
0xd6, 0xbe, 0x04, 0x6d, 0x41, 0xf2, 0x3b, 0x5e,
0xd7, 0x0b, 0x6b, 0x3d, 0x5c, 0x8e, 0x66, 0x23,
0x2b, 0xe6, 0xb8, 0x07, 0xd4, 0xdc, 0xc6, 0x0e,
0xff, 0x8d, 0xbc, 0x1d, 0x9f, 0x7f, 0xc8, 0x22
};
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4000;
ret = wc_AesXtsEncrypt(&aes, buf, p2, sizeof(p2), i2, sizeof(i2));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4001;
if (XMEMCMP(c2, buf, sizeof(c2)))
return -4002;
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4003;
ret = wc_AesXtsEncrypt(&aes, buf, p1, sizeof(p1), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4004;
if (XMEMCMP(c1, buf, AES_BLOCK_SIZE))
return -4005;
/* partial block encryption test */
XMEMSET(cipher, 0, sizeof(cipher));
ret = wc_AesXtsEncrypt(&aes, cipher, pp, sizeof(pp), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4006;
wc_AesXtsFree(&aes);
/* partial block decrypt test */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4007;
ret = wc_AesXtsDecrypt(&aes, buf, cipher, sizeof(pp), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4008;
if (XMEMCMP(pp, buf, sizeof(pp)))
return -4009;
/* NIST decrypt test vector */
XMEMSET(buf, 0, sizeof(buf));
ret = wc_AesXtsDecrypt(&aes, buf, c1, sizeof(c1), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4010;
if (XMEMCMP(p1, buf, AES_BLOCK_SIZE))
return -4011;
/* fail case with decrypting using wrong key */
XMEMSET(buf, 0, sizeof(buf));
ret = wc_AesXtsDecrypt(&aes, buf, c2, sizeof(c2), i2, sizeof(i2));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4012;
if (XMEMCMP(p2, buf, sizeof(p2)) == 0) /* fail case with wrong key */
return -4013;
/* set correct key and retest */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4014;
ret = wc_AesXtsDecrypt(&aes, buf, c2, sizeof(c2), i2, sizeof(i2));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4015;
if (XMEMCMP(p2, buf, sizeof(p2)))
return -4016;
wc_AesXtsFree(&aes);
return ret;
}
static int aes_xts_256_test(void)
{
XtsAes aes;
int ret = 0;
unsigned char buf[AES_BLOCK_SIZE * 3];
unsigned char cipher[AES_BLOCK_SIZE * 3];
/* 256 key tests */
static unsigned char k1[] = {
0x1e, 0xa6, 0x61, 0xc5, 0x8d, 0x94, 0x3a, 0x0e,
0x48, 0x01, 0xe4, 0x2f, 0x4b, 0x09, 0x47, 0x14,
0x9e, 0x7f, 0x9f, 0x8e, 0x3e, 0x68, 0xd0, 0xc7,
0x50, 0x52, 0x10, 0xbd, 0x31, 0x1a, 0x0e, 0x7c,
0xd6, 0xe1, 0x3f, 0xfd, 0xf2, 0x41, 0x8d, 0x8d,
0x19, 0x11, 0xc0, 0x04, 0xcd, 0xa5, 0x8d, 0xa3,
0xd6, 0x19, 0xb7, 0xe2, 0xb9, 0x14, 0x1e, 0x58,
0x31, 0x8e, 0xea, 0x39, 0x2c, 0xf4, 0x1b, 0x08
};
static unsigned char i1[] = {
0xad, 0xf8, 0xd9, 0x26, 0x27, 0x46, 0x4a, 0xd2,
0xf0, 0x42, 0x8e, 0x84, 0xa9, 0xf8, 0x75, 0x64
};
static unsigned char p1[] = {
0x2e, 0xed, 0xea, 0x52, 0xcd, 0x82, 0x15, 0xe1,
0xac, 0xc6, 0x47, 0xe8, 0x10, 0xbb, 0xc3, 0x64,
0x2e, 0x87, 0x28, 0x7f, 0x8d, 0x2e, 0x57, 0xe3,
0x6c, 0x0a, 0x24, 0xfb, 0xc1, 0x2a, 0x20, 0x2e
};
/* plain text test of partial block is not from NIST test vector list */
static unsigned char pp[] = {
0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d,
0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c,
0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5
};
static unsigned char c1[] = {
0xcb, 0xaa, 0xd0, 0xe2, 0xf6, 0xce, 0xa3, 0xf5,
0x0b, 0x37, 0xf9, 0x34, 0xd4, 0x6a, 0x9b, 0x13,
0x0b, 0x9d, 0x54, 0xf0, 0x7e, 0x34, 0xf3, 0x6a,
0xf7, 0x93, 0xe8, 0x6f, 0x73, 0xc6, 0xd7, 0xdb
};
static unsigned char k2[] = {
0xad, 0x50, 0x4b, 0x85, 0xd7, 0x51, 0xbf, 0xba,
0x69, 0x13, 0xb4, 0xcc, 0x79, 0xb6, 0x5a, 0x62,
0xf7, 0xf3, 0x9d, 0x36, 0x0f, 0x35, 0xb5, 0xec,
0x4a, 0x7e, 0x95, 0xbd, 0x9b, 0xa5, 0xf2, 0xec,
0xc1, 0xd7, 0x7e, 0xa3, 0xc3, 0x74, 0xbd, 0x4b,
0x13, 0x1b, 0x07, 0x83, 0x87, 0xdd, 0x55, 0x5a,
0xb5, 0xb0, 0xc7, 0xe5, 0x2d, 0xb5, 0x06, 0x12,
0xd2, 0xb5, 0x3a, 0xcb, 0x47, 0x8a, 0x53, 0xb4
};
static unsigned char i2[] = {
0xe6, 0x42, 0x19, 0xed, 0xe0, 0xe1, 0xc2, 0xa0,
0x0e, 0xf5, 0x58, 0x6a, 0xc4, 0x9b, 0xeb, 0x6f
};
static unsigned char p2[] = {
0x24, 0xcb, 0x76, 0x22, 0x55, 0xb5, 0xa8, 0x00,
0xf4, 0x6e, 0x80, 0x60, 0x56, 0x9e, 0x05, 0x53,
0xbc, 0xfe, 0x86, 0x55, 0x3b, 0xca, 0xd5, 0x89,
0xc7, 0x54, 0x1a, 0x73, 0xac, 0xc3, 0x9a, 0xbd,
0x53, 0xc4, 0x07, 0x76, 0xd8, 0xe8, 0x22, 0x61,
0x9e, 0xa9, 0xad, 0x77, 0xa0, 0x13, 0x4c, 0xfc
};
static unsigned char c2[] = {
0xa3, 0xc6, 0xf3, 0xf3, 0x82, 0x79, 0x5b, 0x10,
0x87, 0xd7, 0x02, 0x50, 0xdb, 0x2c, 0xd3, 0xb1,
0xa1, 0x62, 0xa8, 0xb6, 0xdc, 0x12, 0x60, 0x61,
0xc1, 0x0a, 0x84, 0xa5, 0x85, 0x3f, 0x3a, 0x89,
0xe6, 0x6c, 0xdb, 0xb7, 0x9a, 0xb4, 0x28, 0x9b,
0xc3, 0xea, 0xd8, 0x10, 0xe9, 0xc0, 0xaf, 0x92
};
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4017;
ret = wc_AesXtsEncrypt(&aes, buf, p2, sizeof(p2), i2, sizeof(i2));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4018;
if (XMEMCMP(c2, buf, sizeof(c2)))
return -4019;
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4020;
ret = wc_AesXtsEncrypt(&aes, buf, p1, sizeof(p1), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4021;
if (XMEMCMP(c1, buf, AES_BLOCK_SIZE))
return -4022;
/* partial block encryption test */
XMEMSET(cipher, 0, sizeof(cipher));
ret = wc_AesXtsEncrypt(&aes, cipher, pp, sizeof(pp), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4023;
wc_AesXtsFree(&aes);
/* partial block decrypt test */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4024;
ret = wc_AesXtsDecrypt(&aes, buf, cipher, sizeof(pp), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4025;
if (XMEMCMP(pp, buf, sizeof(pp)))
return -4026;
/* NIST decrypt test vector */
XMEMSET(buf, 0, sizeof(buf));
ret = wc_AesXtsDecrypt(&aes, buf, c1, sizeof(c1), i1, sizeof(i1));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4027;
if (XMEMCMP(p1, buf, AES_BLOCK_SIZE))
return -4028;
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4029;
ret = wc_AesXtsDecrypt(&aes, buf, c2, sizeof(c2), i2, sizeof(i2));
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4030;
if (XMEMCMP(p2, buf, sizeof(p2)))
return -4031;
wc_AesXtsFree(&aes);
return ret;
}
/* both 128 and 256 bit key test */
static int aes_xts_sector_test(void)
{
XtsAes aes;
int ret = 0;
unsigned char buf[AES_BLOCK_SIZE * 2];
/* 128 key tests */
static unsigned char k1[] = {
0xa3, 0xe4, 0x0d, 0x5b, 0xd4, 0xb6, 0xbb, 0xed,
0xb2, 0xd1, 0x8c, 0x70, 0x0a, 0xd2, 0xdb, 0x22,
0x10, 0xc8, 0x11, 0x90, 0x64, 0x6d, 0x67, 0x3c,
0xbc, 0xa5, 0x3f, 0x13, 0x3e, 0xab, 0x37, 0x3c
};
static unsigned char p1[] = {
0x20, 0xe0, 0x71, 0x94, 0x05, 0x99, 0x3f, 0x09,
0xa6, 0x6a, 0xe5, 0xbb, 0x50, 0x0e, 0x56, 0x2c
};
static unsigned char c1[] = {
0x74, 0x62, 0x35, 0x51, 0x21, 0x02, 0x16, 0xac,
0x92, 0x6b, 0x96, 0x50, 0xb6, 0xd3, 0xfa, 0x52
};
word64 s1 = 141;
/* 256 key tests */
static unsigned char k2[] = {
0xef, 0x01, 0x0c, 0xa1, 0xa3, 0x66, 0x3e, 0x32,
0x53, 0x43, 0x49, 0xbc, 0x0b, 0xae, 0x62, 0x23,
0x2a, 0x15, 0x73, 0x34, 0x85, 0x68, 0xfb, 0x9e,
0xf4, 0x17, 0x68, 0xa7, 0x67, 0x4f, 0x50, 0x7a,
0x72, 0x7f, 0x98, 0x75, 0x53, 0x97, 0xd0, 0xe0,
0xaa, 0x32, 0xf8, 0x30, 0x33, 0x8c, 0xc7, 0xa9,
0x26, 0xc7, 0x73, 0xf0, 0x9e, 0x57, 0xb3, 0x57,
0xcd, 0x15, 0x6a, 0xfb, 0xca, 0x46, 0xe1, 0xa0
};
static unsigned char p2[] = {
0xed, 0x98, 0xe0, 0x17, 0x70, 0xa8, 0x53, 0xb4,
0x9d, 0xb9, 0xe6, 0xaa, 0xf8, 0x8f, 0x0a, 0x41,
0xb9, 0xb5, 0x6e, 0x91, 0xa5, 0xa2, 0xb1, 0x1d,
0x40, 0x52, 0x92, 0x54, 0xf5, 0x52, 0x3e, 0x75
};
static unsigned char c2[] = {
0xca, 0x20, 0xc5, 0x5e, 0x8d, 0xc1, 0x49, 0x68,
0x7d, 0x25, 0x41, 0xde, 0x39, 0xc3, 0xdf, 0x63,
0x00, 0xbb, 0x5a, 0x16, 0x3c, 0x10, 0xce, 0xd3,
0x66, 0x6b, 0x13, 0x57, 0xdb, 0x8b, 0xd3, 0x9d
};
word64 s2 = 187;
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4032;
ret = wc_AesXtsEncryptSector(&aes, buf, p1, sizeof(p1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4033;
if (XMEMCMP(c1, buf, AES_BLOCK_SIZE))
return -4034;
/* decrypt test */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4035;
ret = wc_AesXtsDecryptSector(&aes, buf, c1, sizeof(c1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4036;
if (XMEMCMP(p1, buf, AES_BLOCK_SIZE))
return -4037;
wc_AesXtsFree(&aes);
/* 256 bit key tests */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4038;
ret = wc_AesXtsEncryptSector(&aes, buf, p2, sizeof(p2), s2);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4039;
if (XMEMCMP(c2, buf, sizeof(c2)))
return -4040;
/* decrypt test */
XMEMSET(buf, 0, sizeof(buf));
if (wc_AesXtsSetKey(&aes, k2, sizeof(k2), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4041;
ret = wc_AesXtsDecryptSector(&aes, buf, c2, sizeof(c2), s2);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret != 0)
return -4042;
if (XMEMCMP(p2, buf, sizeof(p2)))
return -4043;
wc_AesXtsFree(&aes);
return ret;
}
/* testing of bad arguments */
static int aes_xts_args_test(void)
{
XtsAes aes;
int ret = 0;
unsigned char buf[AES_BLOCK_SIZE * 2];
/* 128 key tests */
static unsigned char k1[] = {
0xa3, 0xe4, 0x0d, 0x5b, 0xd4, 0xb6, 0xbb, 0xed,
0xb2, 0xd1, 0x8c, 0x70, 0x0a, 0xd2, 0xdb, 0x22,
0x10, 0xc8, 0x11, 0x90, 0x64, 0x6d, 0x67, 0x3c,
0xbc, 0xa5, 0x3f, 0x13, 0x3e, 0xab, 0x37, 0x3c
};
static unsigned char p1[] = {
0x20, 0xe0, 0x71, 0x94, 0x05, 0x99, 0x3f, 0x09,
0xa6, 0x6a, 0xe5, 0xbb, 0x50, 0x0e, 0x56, 0x2c
};
static unsigned char c1[] = {
0x74, 0x62, 0x35, 0x51, 0x21, 0x02, 0x16, 0xac,
0x92, 0x6b, 0x96, 0x50, 0xb6, 0xd3, 0xfa, 0x52
};
word64 s1 = 141;
if (wc_AesXtsSetKey(NULL, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) == 0)
return -4044;
if (wc_AesXtsSetKey(&aes, NULL, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) == 0)
return -4045;
/* encryption operations */
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_ENCRYPTION,
HEAP_HINT, devId) != 0)
return -4046;
ret = wc_AesXtsEncryptSector(NULL, buf, p1, sizeof(p1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret == 0)
return -4047;
ret = wc_AesXtsEncryptSector(&aes, NULL, p1, sizeof(p1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret == 0)
return -4048;
wc_AesXtsFree(&aes);
/* decryption operations */
if (wc_AesXtsSetKey(&aes, k1, sizeof(k1), AES_DECRYPTION,
HEAP_HINT, devId) != 0)
return -4046;
ret = wc_AesXtsDecryptSector(NULL, buf, c1, sizeof(c1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret == 0)
return -4049;
ret = wc_AesXtsDecryptSector(&aes, NULL, c1, sizeof(c1), s1);
#if defined(WOLFSSL_ASYNC_CRYPT)
ret = wc_AsyncWait(ret, &enc.asyncDev, WC_ASYNC_FLAG_NONE);
#endif
if (ret == 0)
return -4050;
wc_AesXtsFree(&aes);
return 0;
}
#endif /* WOLFSSL_AES_XTS */
#if defined(HAVE_AES_CBC)
static int aes_cbc_test(void)
{
@ -4647,6 +5150,21 @@ int aes_test(void)
return ret;
#endif
#if defined(WOLFSSL_AES_XTS)
ret = aes_xts_128_test();
if (ret != 0)
return ret;
ret = aes_xts_256_test();
if (ret != 0)
return ret;
ret = aes_xts_sector_test();
if (ret != 0)
return ret;
ret = aes_xts_args_test();
if (ret != 0)
return ret;
#endif
wc_AesFree(&enc);
#ifdef HAVE_AES_DECRYPT
wc_AesFree(&dec);

View File

@ -113,6 +113,12 @@ typedef struct Aes {
void* heap; /* memory hint to use */
} Aes;
#ifdef WOLFSSL_AES_XTS
typedef struct XtsAes {
Aes aes;
Aes tweak;
} XtsAes;
#endif
#ifdef HAVE_AESGCM
typedef struct Gmac {
@ -210,6 +216,230 @@ WOLFSSL_API int wc_AesEcbDecrypt(Aes* aes, byte* out,
const byte* iv);
#endif /* HAVE_AES_KEYWRAP */
#ifdef WOLFSSL_AES_XTS
/*!
\ingroup AES
\brief This is to help with setting keys to correct encrypt or decrypt type.
\note Is up to user to call wc_AesXtsFree on aes key when done.
\return 0 Success
\param aes AES keys for encrypt/decrypt process
\param key buffer holding aes key | tweak key
\param len length of key buffer in bytes. Should be twice that of key size.
i.e. 32 for a 16 byte key.
\param dir direction, either AES_ENCRYPTION or AES_DECRYPTION
\param heap heap hint to use for memory. Can be NULL
\param devId id to use with async crypto. Can be 0
_Example_
\code
XtsAes aes;
if(wc_AesXtsSetKey(&aes, key, sizeof(key), AES_ENCRYPTION, NULL, 0) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsEncrypt
\sa wc_AesXtsDecrypt
\sa wc_AesXtsFree
*/
WOLFSSL_API int wc_AesXtsSetKey(XtsAes* aes, const byte* key,
word32 len, int dir, void* heap, int devId);
/*!
\ingroup AES
\brief Same process as wc_AesXtsEncrypt but uses a word64 type as the tweak
value instead of a byte array. This just converts the word64 to a
byte array and calls wc_AesXtsEncrypt.
\return 0 Success
\param aes AES keys to use for block encrypt/decrypt
\param out output buffer to hold cipher text
\param in input plain text buffer to encrypt
\param sz size of both out and in buffers
\param sector value to use for tweak
_Example_
\code
XtsAes aes;
unsigned char plain[SIZE];
unsigned char cipher[SIZE];
word64 s = VALUE;
//set up keys with AES_ENCRYPTION as dir
if(wc_AesXtsEncryptSector(&aes, cipher, plain, SIZE, s) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsEncrypt
\sa wc_AesXtsDecrypt
\sa wc_AesXtsSetKey
\sa wc_AesXtsFree
*/
WOLFSSL_API int wc_AesXtsEncryptSector(XtsAes* aes, byte* out,
const byte* in, word32 sz, word64 sector);
/*!
\ingroup AES
\brief Same process as wc_AesXtsDecrypt but uses a word64 type as the tweak
value instead of a byte array. This just converts the word64 to a
byte array.
\return 0 Success
\param aes AES keys to use for block encrypt/decrypt
\param out output buffer to hold plain text
\param in input cipher text buffer to decrypt
\param sz size of both out and in buffers
\param sector value to use for tweak
_Example_
\code
XtsAes aes;
unsigned char plain[SIZE];
unsigned char cipher[SIZE];
word64 s = VALUE;
//set up aes key with AES_DECRYPTION as dir and tweak with AES_ENCRYPTION
if(wc_AesXtsDecryptSector(&aes, plain, cipher, SIZE, s) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsEncrypt
\sa wc_AesXtsDecrypt
\sa wc_AesXtsSetKey
\sa wc_AesXtsFree
*/
WOLFSSL_API int wc_AesXtsDecryptSector(XtsAes* aes, byte* out,
const byte* in, word32 sz, word64 sector);
/*!
\ingroup AES
\brief AES with XTS mode. (XTS) XEX encryption with Tweak and cipher text
Stealing.
\return 0 Success
\param aes AES keys to use for block encrypt/decrypt
\param out output buffer to hold cipher text
\param in input plain text buffer to encrypt
\param sz size of both out and in buffers
\param i value to use for tweak
\param iSz size of i buffer, should always be AES_BLOCK_SIZE but having
this input adds a sanity check on how the user calls the
function.
_Example_
\code
XtsAes aes;
unsigned char plain[SIZE];
unsigned char cipher[SIZE];
unsigned char i[AES_BLOCK_SIZE];
//set up key with AES_ENCRYPTION as dir
if(wc_AesXtsEncrypt(&aes, cipher, plain, SIZE, i, sizeof(i)) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsDecrypt
\sa wc_AesXtsSetKey
\sa wc_AesXtsFree
*/
WOLFSSL_API int wc_AesXtsEncrypt(XtsAes* aes, byte* out,
const byte* in, word32 sz, const byte* i, word32 iSz);
/*!
\ingroup AES
\brief Same process as encryption but Aes key is AES_DECRYPTION type.
\return 0 Success
\param aes AES keys to use for block encrypt/decrypt
\param out output buffer to hold plain text
\param in input cipher text buffer to decrypt
\param sz size of both out and in buffers
\param i value to use for tweak
\param iSz size of i buffer, should always be AES_BLOCK_SIZE but having
this input adds a sanity check on how the user calls the
function.
_Example_
\code
XtsAes aes;
unsigned char plain[SIZE];
unsigned char cipher[SIZE];
unsigned char i[AES_BLOCK_SIZE];
//set up key with AES_DECRYPTION as dir and tweak with AES_ENCRYPTION
if(wc_AesXtsDecrypt(&aes, plain, cipher, SIZE, i, sizeof(i)) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsEncrypt
\sa wc_AesXtsSetKey
\sa wc_AesXtsFree
*/
WOLFSSL_API int wc_AesXtsDecrypt(XtsAes* aes, byte* out,
const byte* in, word32 sz, const byte* i, word32 iSz);
/*!
\ingroup AES
\brief This is to free up any resources used by the XtsAes structure
\return 0 Success
\param aes AES keys to free
_Example_
\code
XtsAes aes;
if(wc_AesXtsSetKey(&aes, key, sizeof(key), AES_ENCRYPTION, NULL, 0) != 0)
{
// Handle error
}
wc_AesXtsFree(&aes);
\endcode
\sa wc_AesXtsEncrypt
\sa wc_AesXtsDecrypt
\sa wc_AesXtsSetKey
*/
WOLFSSL_API int wc_AesXtsFree(XtsAes* aes);
#endif
WOLFSSL_API int wc_AesGetKeySize(Aes* aes, word32* keySize);
WOLFSSL_API int wc_AesInit(Aes*, void*, int);

View File

@ -1344,6 +1344,12 @@ extern void uITRON4_free(void *p) ;
#error "AES CBC is required for TLS and can only be disabled for WOLFCRYPT_ONLY builds"
#endif
#endif
#ifdef WOLFSSL_AES_XTS
/* AES-XTS makes calls to AES direct functions */
#ifndef WOLFSSL_AES_DIRECT
#define WOLFSSL_AES_DIRECT
#endif
#endif
#endif
/* if desktop type system and fastmath increase default max bits */