added GCM-SIV
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
**A minimalist ANSI-C compatible code for most of the AES-related algorithms**.
|
||||
|
||||
[](https://github.com/polfosol/micro-AES)  [](https://github.com/polfosol/micro-AES) [](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/polfosol/micro-AES)  [](https://github.com/polfosol/micro-AES/releases) [](https://opensource.org/licenses/Apache-2.0)
|
||||
|
||||
This library is a highly flexible, all-in-one implementation of different AES encryption schemes and block ciphers modes. Before you continue, please keep in mind that, most security experts strongly warn *against* implementing your own version of AES—or other ciphering algorithms; AND THEY ARE ABSOLUTELY RIGHT!
|
||||
|
||||
@@ -41,7 +41,7 @@ With that in mind, I shall say that the main purpose of developing µAES was pur
|
||||
|
||||
## Remarks
|
||||
|
||||
For the sake of simplicity, it is mostly assumed that the input parameters of the functions are well defined, and the user knows what they're doing. As a result, many error checks are just skipped. Obviously, this is a naive and sometimes dangerous assumption. One must be aware that in a serious application, anything can be fed into the functions and they must take all the necessary precautions for erroneous parameters.
|
||||
For the sake of simplicity, it is often assumed that the input parameters of the functions are well defined, and the user knows what they're doing. As a result, a bunch of error checks are just skipped. Obviously, this is a naive and sometimes dangerous assumption. One must be aware that in a serious application, anything can be fed into the functions and they must take all the necessary precautions for erroneous parameters.
|
||||
|
||||
µAES is palpably influenced by [kokke's tiny-AES](https://github.com/kokke/tiny-AES-c) library, but I have made some modifications which makes it a bit smaller and faster. I shall give kudos to their great effort which paved the way for many other branches.
|
||||
|
||||
@@ -49,6 +49,6 @@ All the contents of this repository (except the ones that I didn't write!) are s
|
||||
|
||||
Copyright © 2022 - polfosol
|
||||
|
||||
$In$ $loving$ $memory$ $of$ [**_Mahsa Amini_**](https://en.wikipedia.org/wiki/Death_of_Mahsa_Amini) :black_heart:
|
||||
$In$ $sorrowful$ $memory$ $of$ [**_Mahsa Amini_**](https://en.wikipedia.org/wiki/Death_of_Mahsa_Amini) :black_heart:
|
||||
|
||||

|
||||
|
||||
85
main.c
85
main.c
@@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
Name : main.c
|
||||
Author : polfosol
|
||||
Version : 8.9.5.0
|
||||
Version : 9.0.0.0
|
||||
Copyright : copyright © 2022 - polfosol
|
||||
Description : test vectors for µAES ™ library, mostly generated by Crypto++ ®
|
||||
==============================================================================
|
||||
@@ -42,13 +42,9 @@ static const char
|
||||
#endif
|
||||
*xtscipher = "10f9301a157bfceb 3eb9e7bd38500b7e 959e21ba3cc1179a d7f7d7d99460e695\
|
||||
5e8bcb177571c719 6de58ff28c381913 e7c82d0adfd90c45 ca",
|
||||
*cmac_hash = "b887df1fd8c239c3 e8a64d9822e21128",
|
||||
*ccmcipher = "d2575123438338d7 0b2955537fdfcf41 729870884e85af15 f0a74975a72b337d\
|
||||
04d426de87594b9a be3e6dcf07f21c99 db3999f81299d302 ad1e5ba683e9039a\
|
||||
5483685f1bd2c3fa 3b", /* <---- with 16 bytes tag */
|
||||
*sivcipher = "f6d8137b17d58d13 af040e8abadd965b 9bae3a3de90ca6f7 049c2528767da2cf\
|
||||
ef17de85b1d07b59 d26b0595071ae428 3015840928e2c7f5 9abf06003b14b9ee\
|
||||
25111d34bb2bfcc2 25", /* 16 bytes i.v. PREPENDED */
|
||||
*gcmcipher = "5ceab5b7c2d6dede 555a23c7e3e63274 4075a51df482730b a31485ec987ddcc8\
|
||||
73acdcfc6759a47b a424d838e7c0cb71 b9a4d8f4572e2141 18c8ab284ca845c1\
|
||||
4394618703cddf3a fb", /* <---- with 16 bytes tag */
|
||||
@@ -63,9 +59,13 @@ static const char
|
||||
50661c618335a005 47cca55a8f22fbd5 ed5ab4b4a17d0aa3 29febd14ef271bae\
|
||||
986810a504f01ec6 02", /* <---- with 16 bytes tag */
|
||||
#endif
|
||||
*gsvcipher = "XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX\
|
||||
XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX\
|
||||
XXXXXXXXXXXXXXXX XX",
|
||||
*gsvcipher = "2f1488496ada3f70 9760420ac72e5acf a977f6add4c55ac6 85f1b9dff8f381e0\
|
||||
2a64bbdd64cdd778 525462949bb0b141 db908c5cfa365750 3666f879ac879fcb\
|
||||
f25c15d496a1e6f7 f8", /* <---- with 16 bytes tag */
|
||||
*sivcipher = "f6d8137b17d58d13 af040e8abadd965b 9bae3a3de90ca6f7 049c2528767da2cf\
|
||||
ef17de85b1d07b59 d26b0595071ae428 3015840928e2c7f5 9abf06003b14b9ee\
|
||||
25111d34bb2bfcc2 25", /* 16 bytes i.v. PREPENDED */
|
||||
*cmac_hash = "b887df1fd8c239c3 e8a64d9822e21128",
|
||||
*wrapped = "1FA68B0A8112B447 AEF34BD8FB5A7B82 9D3E862371D2CFE5";
|
||||
#elif AES_KEY_LENGTH == 24 /* ↓↓↓↓ PKCS#7 is enabled */
|
||||
*ecbcipher = "af1893f0fbb09a43 7f6b0fd4f4977890 7bb85cccf1e9d2e3 ebe5bae935107868\
|
||||
@@ -200,6 +200,13 @@ int main()
|
||||
*output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
|
||||
check("SIV decryption", output, input, st);
|
||||
#endif
|
||||
#if GCM_SIV && AES_KEY_LENGTH == 16
|
||||
str2bytes(gsvcipher, test);
|
||||
GCM_SIV_encrypt(key, iv, input, st, a, sa, output);
|
||||
check("GCMSIV encrypt", output, test, st + 16);
|
||||
*output ^= GCM_SIV_decrypt(key, iv, test, st + 16, a, sa, output);
|
||||
check("GCMSIV decrypt", output, input, st);
|
||||
#endif
|
||||
#if EAX && AES_KEY_LENGTH == 16
|
||||
str2bytes(eaxcipher, test);
|
||||
#if EAXP
|
||||
@@ -213,13 +220,6 @@ int main()
|
||||
#endif
|
||||
check("EAX decryption", output, input, st);
|
||||
#endif
|
||||
#if GCM_SIV && AES_KEY_LENGTH == 16
|
||||
str2bytes(gsvcipher, test);
|
||||
GCM_SIV_encrypt(key, iv, input, st, a, sa, output, output + st);
|
||||
check("GCMSIV encrypt", output, test, st + 16);
|
||||
*output ^= GCM_SIV_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
|
||||
check("GCMSIV decrypt", output, input, st);
|
||||
#endif
|
||||
#if KWA
|
||||
str2bytes(wrapped, test);
|
||||
AES_KEY_wrap(mainKey, key + 32, AES_KEY_LENGTH, output);
|
||||
@@ -244,6 +244,16 @@ int main()
|
||||
*output ^= AES_OCB_decrypt(key, iv, test, st, a, sa, test + st, OCB_TAG_LEN, output);
|
||||
check("OCB decryption", output, input, st);
|
||||
|
||||
st = 11; sa = 7; /* taken from RFC 8452: */
|
||||
str2bytes("ee8e1ed9ff2540ae8f2ba9f50bc2f27c", key);
|
||||
str2bytes("752abad3e0afb5f434dc4310", iv);
|
||||
str2bytes("6578616d706c65", a);
|
||||
str2bytes("48656c6c6f20776f726c64", input);
|
||||
str2bytes("5d349ead175ef6b1def6fd4fbcdeb7e4793f4a1d7e4faa70100af1", test);
|
||||
GCM_SIV_encrypt(key, iv, input, st, a, sa, output);
|
||||
check("GCMSIV encrypt", output, test, st + 16);
|
||||
*output ^= GCM_SIV_decrypt(key, iv, test, st + 16, a, sa, output);
|
||||
check("GCMSIV decrypt", output, input, st);
|
||||
st = 12; sa = 1; /* taken from RFC 8452: */
|
||||
str2bytes("01000000000000000000000000000000", key);
|
||||
str2bytes("030000000000000000000000", iv);
|
||||
@@ -251,31 +261,10 @@ int main()
|
||||
str2bytes("020000000000000000000000", input);
|
||||
str2bytes("296c7889fd99f41917f4462008299c51\
|
||||
02745aaa3a0c469fad9e075a", test);
|
||||
GCM_SIV_encrypt(key, iv, input, st, a, sa, output, output + st);
|
||||
GCM_SIV_encrypt(key, iv, input, st, a, sa, output);
|
||||
check("GCMSIV encrypt", output, test, st + 16);
|
||||
*output ^= GCM_SIV_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
|
||||
*output ^= GCM_SIV_decrypt(key, iv, test, st + 16, a, sa, output);
|
||||
check("GCMSIV decrypt", output, input, st);
|
||||
|
||||
st = 14; sa = 24; /* taken from RFC 5297: */
|
||||
str2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
|
||||
f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff", key);
|
||||
str2bytes("10111213 14151617 18191a1b 1c1d1e1f\
|
||||
20212223 24252627", a);
|
||||
str2bytes("11223344 55667788 99aabbcc ddee", input);
|
||||
str2bytes("85632d07 c6e8f37f 950acd32 0a2ecc93\
|
||||
40c02b96 90c4dc04 daef7f6a fe5c", test);
|
||||
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
|
||||
check("SIV encryption", output, test, st + 16);
|
||||
*output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
|
||||
check("SIV decryption", output, input, st);
|
||||
st = 16; sa = 0; /* from miscreant: https://bit.ly/3yc2GBs */
|
||||
str2bytes("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", key);
|
||||
str2bytes("00112233445566778899aabbccddeeff", input);
|
||||
str2bytes("f304f912863e303d5b540e5057c7010c942ffaf45b0e5ca5fb9a56a5263bb065", test);
|
||||
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
|
||||
check("SIV encryption", output, test, st + 16);
|
||||
*output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
|
||||
check("SIV decryption", output, input, st);
|
||||
#if EAXP
|
||||
st = 0; sa = 50; /* from Annex G of the IEEE Std 1703-2012 */
|
||||
str2bytes("01020304050607080102030405060708", mainKey);
|
||||
@@ -315,5 +304,25 @@ int main()
|
||||
#endif
|
||||
check("EAX decryption", output, input, st);
|
||||
#endif
|
||||
st = 16; sa = 0; /* from miscreant: https://bit.ly/3yc2GBs */
|
||||
str2bytes("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", key);
|
||||
str2bytes("00112233445566778899aabbccddeeff", input);
|
||||
str2bytes("f304f912863e303d5b540e5057c7010c942ffaf45b0e5ca5fb9a56a5263bb065", test);
|
||||
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
|
||||
check("SIV encryption", output, test, st + 16);
|
||||
*output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
|
||||
check("SIV decryption", output, input, st);
|
||||
st = 14; sa = 24; /* taken from RFC 5297: */
|
||||
str2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
|
||||
f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff", key);
|
||||
str2bytes("10111213 14151617 18191a1b 1c1d1e1f\
|
||||
20212223 24252627", a);
|
||||
str2bytes("11223344 55667788 99aabbcc ddee", input);
|
||||
str2bytes("85632d07 c6e8f37f 950acd32 0a2ecc93\
|
||||
40c02b96 90c4dc04 daef7f6a fe5c", test);
|
||||
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
|
||||
check("SIV encryption", output, test, st + 16);
|
||||
*output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
|
||||
check("SIV decryption", output, input, st);
|
||||
return 0;
|
||||
}
|
||||
|
||||
316
micro_aes.c
316
micro_aes.c
@@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
Name : micro_aes.c
|
||||
Author : polfosol
|
||||
Version : 8.9.5.0
|
||||
Version : 9.0.1.0
|
||||
Copyright : copyright © 2022 - polfosol
|
||||
Description : ANSI-C compatible implementation of µAES ™ library.
|
||||
==============================================================================
|
||||
@@ -20,10 +20,12 @@
|
||||
#define Nk (KEYSIZE/4) /* The number of 32 bit words in a key. */
|
||||
#define ROUNDS (Nk+6) /* The number of rounds in AES Cipher. */
|
||||
|
||||
/** Since the RoundKey is a static array, it might be exposed to some attacks.
|
||||
* By enabling this macro, the RoundKey buffer is wiped at the end of ciphering
|
||||
* operations. However, this is NOT A GUARANTEE against side-channel attacks. */
|
||||
/** The rationale of these macros is explained at the bottom of header file: */
|
||||
#define INCREASE_SECURITY 0
|
||||
#define SMALL_CIPHER 0
|
||||
#define REDUCE_CODE_SIZE 1
|
||||
|
||||
#define IMPLEMENT(x) (x) > 0
|
||||
|
||||
/** state_t represents rijndael state matrix. fixed-size memory blocks have an
|
||||
* essential role in all algorithms. so it may be a good aide for readability to
|
||||
@@ -38,8 +40,6 @@ typedef unsigned char count_t;
|
||||
typedef size_t count_t;
|
||||
#endif
|
||||
|
||||
#define IMPLEMENT(x) (x) > 0
|
||||
|
||||
/**--------------------------------------------------------------------------**\
|
||||
Private variables:
|
||||
\*----------------------------------------------------------------------------*/
|
||||
@@ -53,7 +53,6 @@ static uint8_t RoundKey[BLOCKSIZE * ROUNDS + KEYSIZE];
|
||||
* limited. Please refer to: https://en.wikipedia.org/wiki/Rijndael_S-box */
|
||||
static const uint8_t sbox[256] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
@@ -95,7 +94,7 @@ static const uint8_t rsbox[256] =
|
||||
#endif
|
||||
|
||||
/**--------------------------------------------------------------------------**\
|
||||
Auxiliary functions for Rijndael algorithm
|
||||
Auxiliary functions for the Rijndael algorithm
|
||||
\*----------------------------------------------------------------------------*/
|
||||
|
||||
#define getSBoxValue(num) (sbox[(num)])
|
||||
@@ -127,20 +126,13 @@ static void xorBlock( const block_t src, block_t dest )
|
||||
}
|
||||
#endif
|
||||
|
||||
#if INCREASE_SECURITY
|
||||
#define BURN_AFTER_READ memset( RoundKey, 0, sizeof RoundKey );
|
||||
#else
|
||||
#define BURN_AFTER_READ {}
|
||||
#endif
|
||||
|
||||
/**--------------------------------------------------------------------------**\
|
||||
Main functions for the Rijndael encryption algorithm
|
||||
\*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief produces (ROUNDS+1) round keys, which are used in each round
|
||||
* to encrypt/decrypt the intermediate states
|
||||
* @param key encryption key with a fixed size specified by KEYSIZE
|
||||
* produces (ROUNDS+1) round keys from the main encryption key, which are used
|
||||
* in each round to encrypt/decrypt the intermediate states.
|
||||
*/
|
||||
static void KeyExpansion( const uint8_t* key )
|
||||
{
|
||||
@@ -440,6 +432,51 @@ static void mixThenXor( const block_t b, fmix_t mix, block_t tmp,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CTR
|
||||
|
||||
typedef void (*finc_t)( block_t ); /* function-ptr to increment */
|
||||
|
||||
/** increment value of big-endian counter block. */
|
||||
static void incB( block_t block )
|
||||
{
|
||||
#if SMALL_CIPHER /* <-- use it with CAUTION */
|
||||
++block[BLOCKSIZE - 1];
|
||||
#else
|
||||
uint8_t i; /* inc until no overflow */
|
||||
for (i = BLOCKSIZE - 1; !++block[i] && i--; );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SMALL_CIPHER
|
||||
#define putValueB(block, pos, val) block[pos - 1] = val >> 8; block[pos] = val
|
||||
#else
|
||||
|
||||
/** copy big endian value to the block, starting at the specified position... */
|
||||
static void putValueB( block_t block, uint8_t pos, size_t val )
|
||||
{
|
||||
do
|
||||
block[pos--] = (uint8_t) val;
|
||||
while (val >>= 8);
|
||||
}
|
||||
#endif
|
||||
#endif /* CTR */
|
||||
|
||||
#if XTS || GCM_SIV
|
||||
|
||||
#if SMALL_CIPHER
|
||||
#define putValueL(block, pos, val) block[pos + 1] = val >> 8; block[pos] = val
|
||||
#else
|
||||
|
||||
/** copy little endian value to the block, starting at the specified position */
|
||||
static void putValueL( block_t block, uint8_t pos, size_t val )
|
||||
{
|
||||
do
|
||||
block[pos++] = (uint8_t) val;
|
||||
while (val >>= 8);
|
||||
}
|
||||
#endif
|
||||
#endif /* XTS */
|
||||
|
||||
#if EAX && !EAXP || SIV || OCB || CMAC
|
||||
|
||||
/** Multiply a block by two in Galois bit field GF(2^128): big-endian version */
|
||||
@@ -513,6 +550,53 @@ static void MulGf128( const block_t x, block_t y )
|
||||
}
|
||||
#endif /* GCM */
|
||||
|
||||
#if GCM_SIV
|
||||
|
||||
/** Divide a block by two in GF(2^128) field: the little-endian version (duh) */
|
||||
static void halveGf128L( block_t block )
|
||||
{
|
||||
uint8_t c = 0, l, i;
|
||||
for (i = BLOCKSIZE; i--; ) /* see the explanations for */
|
||||
{ /* ..the above-defined */
|
||||
l = block[i] << 7; /* ..halveGf128B function */
|
||||
block[i] >>= 1;
|
||||
block[i] |= c;
|
||||
c = l;
|
||||
}
|
||||
if (c) block[BLOCKSIZE - 1] ^= 0xe1; /* 0xe1 = 11100001b */
|
||||
}
|
||||
|
||||
/** increase the value of a counter block. this is the little-endian version. */
|
||||
static void incL( block_t block )
|
||||
{
|
||||
#if SMALL_CIPHER /* <-- use it with CAUTION */
|
||||
++block[0];
|
||||
#else
|
||||
uint8_t i; /* inc until no overflow */
|
||||
for (i = 0; !++block[i] && i < 4; ++i);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Dot multiplication in GF(2^128) field: used in POLYVAL hash for GCM-SIV.. */
|
||||
static void DotGf128( const block_t x, block_t y )
|
||||
{
|
||||
uint8_t i, j, result[BLOCKSIZE] = { 0 }; /* working memory */
|
||||
|
||||
for (i = BLOCKSIZE; i--; )
|
||||
{
|
||||
for (j = 0x80; j != 0; j >>= 1) /* check all the bits of X, */
|
||||
{
|
||||
halveGf128L( y ); /* Y_next = (Y / 2) in GF */
|
||||
if (x[i] & j)
|
||||
{ /* if any bit is set: */
|
||||
xorBlock( y, result ); /* M ^= (Y / 2) */
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy( y, result, sizeof result ); /* result is saved into y */
|
||||
}
|
||||
#endif /* GCM-SIV */
|
||||
|
||||
#if OCB
|
||||
|
||||
static void nop( const block_t x, block_t y ) {}
|
||||
@@ -593,80 +677,16 @@ static void cMac( const block_t D, const block_t Q,
|
||||
#endif
|
||||
#endif /* AEAD */
|
||||
|
||||
#if CTR
|
||||
|
||||
typedef void (*finc_t)( block_t ); /* function-ptr to increment */
|
||||
|
||||
/** increment value of big-endian counter block. */
|
||||
static void incB( block_t block )
|
||||
{
|
||||
#if SMALL_CIPHER /* <-- use it with CAUTION */
|
||||
++block[BLOCKSIZE - 1];
|
||||
#else
|
||||
uint8_t i; /* inc until no overflow */
|
||||
for (i = BLOCKSIZE - 1; !++block[i] && i--; );
|
||||
#endif
|
||||
}
|
||||
|
||||
#if SMALL_CIPHER
|
||||
#define putValueB(block, pos, val) block[pos - 1] = val >> 8; block[pos] = val
|
||||
#else
|
||||
|
||||
/** copy big endian value to the block, starting at the specified position... */
|
||||
static void putValueB( block_t block, uint8_t pos, size_t val )
|
||||
{
|
||||
do
|
||||
block[pos--] = (uint8_t) val;
|
||||
while (val >>= 8);
|
||||
}
|
||||
#endif
|
||||
#endif /* CTR */
|
||||
|
||||
#if XTS || GCM_SIV
|
||||
|
||||
#if SMALL_CIPHER
|
||||
#define putValueL(block, pos, val) block[pos + 1] = val >> 8; block[pos] = val
|
||||
#else
|
||||
|
||||
/** copy little endian value to the block, starting at the specified position */
|
||||
static void putValueL( block_t block, uint8_t pos, size_t val )
|
||||
{
|
||||
do
|
||||
block[pos++] = (uint8_t) val;
|
||||
while (val >>= 8);
|
||||
}
|
||||
#endif
|
||||
#if GCM_SIV
|
||||
|
||||
/** increase the value of a counter block. this is the little-endian version. */
|
||||
static void incL( block_t block )
|
||||
{
|
||||
#if SMALL_CIPHER /* <-- use it with CAUTION */
|
||||
++block[0];
|
||||
#else
|
||||
uint8_t i; /* inc until no overflow */
|
||||
for (i = 0; !++block[i] && i < BLOCKSIZE; ++i);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Multiply a block by 2 in GF(2^128) field: the POLYVAL version for GCM_SIV */
|
||||
static void doubleGf128P( block_t block )
|
||||
{
|
||||
uint8_t c = block[BLOCKSIZE - 1] >> 7, m, i;
|
||||
for (i = 0; i < BLOCKSIZE; ++i)
|
||||
{ /* somehow a combination of */
|
||||
m = block[i] >> 7; /* ..doubleGF128L and */
|
||||
block[i] <<= 1; /* ..halveGF128B (that are */
|
||||
block[i] |= c; /* ..introduced above) */
|
||||
c = m; /* ¯\_(●_o)_/¯ .. m(-_-)m */
|
||||
}
|
||||
if (c) block[BLOCKSIZE - 1] ^= 0xc2; /* 0xc2 = 11100001b << 1 */
|
||||
}
|
||||
#endif /* XTS */
|
||||
|
||||
#define GOTO_NEXT_BLOCK x += BLOCKSIZE; y += BLOCKSIZE;
|
||||
|
||||
#if INCREASE_SECURITY
|
||||
#define BURN_AFTER_READ memset( RoundKey, 0, sizeof RoundKey );
|
||||
#define SABOTAGE_RESULT(len) memset( pText, 0, len )
|
||||
#else
|
||||
#define BURN_AFTER_READ
|
||||
#define SABOTAGE_RESULT(len) (void) (len)
|
||||
#endif
|
||||
|
||||
|
||||
/**--------------------------------------------------------------------------**\
|
||||
ECB-AES (electronic codebook mode) functions
|
||||
@@ -1235,11 +1255,11 @@ char AES_GCM_decrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
GHash( H, cText, aData, cTextLen, aDataLen, gsh );
|
||||
|
||||
RijndaelEncrypt( iv, H );
|
||||
xorBlock( H, gsh ); /* tag = Enc(iv) ^ GHASH */
|
||||
if (memcmp( gsh, auTag, tagSize ) != 0) /* compare tags and proceed */
|
||||
{ /* ..if they match. */
|
||||
BURN_AFTER_READ
|
||||
return AUTHENTICATION_FAILURE;
|
||||
xorBlock( H, gsh ); /* tag = Enc(iv) ^ GHASH */
|
||||
if (memcmp( gsh, auTag, tagSize ) != 0) /* compare tags and proceed */
|
||||
{ /* ..if they match. it is */
|
||||
BURN_AFTER_READ /* ..recommended to use a */
|
||||
return AUTHENTICATION_FAILURE; /* ..'secure' compare method */
|
||||
}
|
||||
CTR_Cipher( iv, 1, &incB, cText, cTextLen, pText );
|
||||
BURN_AFTER_READ
|
||||
@@ -1343,8 +1363,9 @@ char AES_CCM_decrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
BURN_AFTER_READ
|
||||
|
||||
xorBlock( iv, cm );
|
||||
if (memcmp( cm, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
|
||||
{ /* memset(pText, 0, Length); */
|
||||
if (memcmp( cm, auTag, tagSize ) != 0) /* memcmp is vulnerable to */
|
||||
{ /* ..timing attacks */
|
||||
SABOTAGE_RESULT( cTextLen );
|
||||
return AUTHENTICATION_FAILURE;
|
||||
}
|
||||
return ENDED_IN_SUCCESS;
|
||||
@@ -1439,6 +1460,7 @@ char AES_SIV_decrypt( const uint8_t* keys, const block_t iv,
|
||||
|
||||
if (memcmp( IV, iv, sizeof IV ) != 0)
|
||||
{
|
||||
SABOTAGE_RESULT( cTextLen );
|
||||
return AUTHENTICATION_FAILURE;
|
||||
}
|
||||
return ENDED_IN_SUCCESS;
|
||||
@@ -1729,8 +1751,9 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
OCB_GetTag( delta, Ls, Ld, pText, aData, cTextLen, aDataLen, delta );
|
||||
BURN_AFTER_READ /* saved the tag into delta! */
|
||||
|
||||
if (memcmp( delta, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
|
||||
{ /* memset(pText, 0, Length); */
|
||||
if (memcmp( delta, auTag, tagSize ) != 0)
|
||||
{
|
||||
SABOTAGE_RESULT( cTextLen );
|
||||
return AUTHENTICATION_FAILURE;
|
||||
}
|
||||
return ENDED_IN_SUCCESS;
|
||||
@@ -1742,45 +1765,110 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
SIV-GCM-AES (Galois counter mode with synthetic i.v): main functions
|
||||
\*----------------------------------------------------------------------------*/
|
||||
#if IMPLEMENT(GCM_SIV)
|
||||
|
||||
/** calculates the POLYVAL of plaintext and AAD using authentication subkey H */
|
||||
static void Polyval( const block_t H, const void* pText, const void* aData,
|
||||
const size_t pTextLen, const size_t aDataLen, block_t pv )
|
||||
{
|
||||
block_t buf = { 0 }; /* save bit-sizes into buf */
|
||||
putValueL( buf, 0, aDataLen * 8 );
|
||||
putValueL( buf, 8, pTextLen * 8 );
|
||||
|
||||
MAC( aData, aDataLen, H, &DotGf128, pv ); /* first digest AAD, then */
|
||||
MAC( pText, pTextLen, H, &DotGf128, pv ); /* ..plaintext, and then */
|
||||
MAC( buf, sizeof buf, H, &DotGf128, pv ); /* ..bit sizes into POLYVAL */
|
||||
}
|
||||
|
||||
/** derive the pair of authentication-encryption-keys from main key and nonce */
|
||||
static void DeriveKeys( const uint8_t* key, const uint8_t* nonce, block_t AK )
|
||||
{
|
||||
uint8_t iv[BLOCKSIZE] = { 0 }, AEKeypair[KEYSIZE + 24];
|
||||
uint8_t i, *k = AEKeypair;
|
||||
memcpy( iv + 4, nonce, 12 );
|
||||
|
||||
AES_SetKey( key );
|
||||
for (i = 0; i < KEYSIZE / 8 + 2; ++i)
|
||||
{
|
||||
RijndaelEncrypt( iv, k ); /* encrypt nonce & take MSB */
|
||||
incL( iv ); /* increment nonce (L.E.) */
|
||||
k += 8;
|
||||
}
|
||||
AES_SetKey( AEKeypair + BLOCKSIZE ); /* set the main cipher-key */
|
||||
memcpy( AK, AEKeypair, BLOCKSIZE ); /* take authentication key */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief encrypt the input plaintext using SIV-GCM-AES block-cipher method
|
||||
* @param key encryption key with a fixed size specified by KEYSIZE
|
||||
* @param nonce a.k.a initialization vector
|
||||
* @param nonce provided 96-bit nonce
|
||||
* @param pText input plain-text buffer
|
||||
* @param pTextLen size of plaintext in bytes
|
||||
* @param aData additional authentication data
|
||||
* @param aDataLen size of additional authentication data
|
||||
* @param cText encrypted cipher-text buffer
|
||||
* @param auTag message authentication tag. buffer must be 16-bytes long
|
||||
* @param cText encrypted cipher-text + 16 bytes MANDATORY tag appended
|
||||
*/
|
||||
void GCM_SIV_encrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
const uint8_t* pText, const size_t pTextLen,
|
||||
const uint8_t* aData, const size_t aDataLen,
|
||||
uint8_t* cText, block_t auTag )
|
||||
uint8_t* cText )
|
||||
{
|
||||
block_t AK, S = { 0 };
|
||||
DeriveKeys( key, nonce, AK ); /* get authentication subkey */
|
||||
|
||||
Polyval( AK, pText, aData, pTextLen, aDataLen, S );
|
||||
for (*AK = 0; *AK < 12; ++*AK)
|
||||
{ /* use AK[0] as counter! */
|
||||
S[*AK] ^= nonce[*AK]; /* xor nonce with POLYVAL */
|
||||
}
|
||||
S[sizeof S - 1] &= 0x7F; /* clear one bit & encrypt, */
|
||||
RijndaelEncrypt( S, S ); /* ..to get auth. tag */
|
||||
memcpy( cText + pTextLen, S, sizeof S );
|
||||
|
||||
S[sizeof S - 1] |= 0x80; /* set 1 bit to get CTR I.V */
|
||||
CTR_Cipher( S, 0, &incL, pText, pTextLen, cText );
|
||||
BURN_AFTER_READ
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief decrypt the input ciphertext using SIV-GCM-AES block-cipher method
|
||||
* @param key decryption key with a fixed size specified by KEYSIZE
|
||||
* @param nonce a.k.a initialization vector
|
||||
* @param cText input cipher-text buffer
|
||||
* @param cTextLen size of ciphertext in bytes
|
||||
* @param nonce provided 96-bit nonce
|
||||
* @param cText input cipher-text buffer + 16 bytes MANDATORY tag appended
|
||||
* @param cTextLen size of ciphertext + 16
|
||||
* @param aData additional authentication data
|
||||
* @param aDataLen size of additional authentication data
|
||||
* @param auTag message authentication tag (if any)
|
||||
* @param tagSize length of authentication tag
|
||||
* @param pText plain-text output buffer
|
||||
* @return whether message authentication was successful
|
||||
* @return whether message authentication/decryption was successful
|
||||
*/
|
||||
char GCM_SIV_decrypt( const uint8_t* key, const uint8_t* nonce,
|
||||
const uint8_t* cText, const size_t cTextLen,
|
||||
const uint8_t* aData, const size_t aDataLen,
|
||||
const uint8_t* auTag, const uint8_t tagSize,
|
||||
uint8_t* pText )
|
||||
{
|
||||
BURN_AFTER_READ
|
||||
block_t AK, S;
|
||||
uint8_t const *tag = cText + cTextLen - 16;
|
||||
if (cTextLen < 16) return DECRYPTION_FAILURE;
|
||||
|
||||
DeriveKeys( key, nonce, AK ); /* get authentication subkey */
|
||||
memcpy( S, tag, sizeof S ); /* tag contains counter I.V. */
|
||||
S[sizeof S - 1] |= 0x80;
|
||||
CTR_Cipher( S, 0, &incL, cText, cTextLen - 16, pText );
|
||||
|
||||
memset( S, 0, sizeof S );
|
||||
Polyval( AK, pText, aData, cTextLen - 16, aDataLen, S );
|
||||
for (*AK = 0; *AK < 12; ++*AK)
|
||||
{ /* using AK[0] as counter! */
|
||||
S[*AK] ^= nonce[*AK]; /* xor nonce with POLYVAL */
|
||||
}
|
||||
S[sizeof S - 1] &= 0x7F; /* clear one bit & encrypt, */
|
||||
RijndaelEncrypt( S, S ); /* ..to get tag & verify it */
|
||||
|
||||
BURN_AFTER_READ /* rfc-8452 RECOMMENDS not */
|
||||
if (memcmp( S, tag, sizeof S ) != 0) /* ..using memcmp to avoid */
|
||||
{ /* ..timing attacks. e.g use */
|
||||
SABOTAGE_RESULT( cTextLen - 16 ); /* ..a constant-time compare */
|
||||
return AUTHENTICATION_FAILURE; /* ..method: timingsafe_bcmp */
|
||||
}
|
||||
return ENDED_IN_SUCCESS;
|
||||
}
|
||||
#endif /* GCM-SIV */
|
||||
@@ -1869,10 +1957,8 @@ char AES_KEY_unwrap( const uint8_t* kek,
|
||||
}
|
||||
BURN_AFTER_READ
|
||||
|
||||
for (i = 0; i < S; ++i) /* error checking... */
|
||||
{
|
||||
if (A[i] != 0xA6) return DECRYPTION_FAILURE;
|
||||
}
|
||||
return ENDED_IN_SUCCESS;
|
||||
for (i = 0; i < S; ++i) j |= A[i] ^ 0xA6; /* authenticate/error check */
|
||||
|
||||
return j ? DECRYPTION_FAILURE : ENDED_IN_SUCCESS;
|
||||
}
|
||||
#endif /* KWA */
|
||||
|
||||
96
micro_aes.h
96
micro_aes.h
@@ -2,7 +2,7 @@
|
||||
==============================================================================
|
||||
Name : micro_aes.h
|
||||
Author : polfosol
|
||||
Version : 8.9.5.0
|
||||
Version : 9.0.1.0
|
||||
Copyright : copyright © 2022 - polfosol
|
||||
Description : μAES ™ is a minimalist all-in-one library for AES encryption
|
||||
==============================================================================
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#ifndef _MICRO__AES_
|
||||
#define _MICRO__AES_
|
||||
#include <string.h>
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
You can use different AES algorithms by changing this macro. Default is AES-128
|
||||
@@ -21,10 +20,10 @@ You can use different AES algorithms by changing this macro. Default is AES-128
|
||||
AES block-cipher modes of operation. The following modes can be enabled/disabled
|
||||
by setting their corresponding macros to TRUE (1) or FALSE (0).
|
||||
-----------------------------------------------------------------------------*/
|
||||
#define BLOCK_CIPHER_MODES 1
|
||||
#define DISABLE_BLOCKCIPHER 0
|
||||
#define AEAD_MODES 1 /* authenticated encryption with associated data. */
|
||||
|
||||
#if BLOCK_CIPHER_MODES
|
||||
#if !DISABLE_BLOCKCIPHER
|
||||
#define ECB 1 /* electronic code-book (NIST SP 800-38A) */
|
||||
#define CBC 1 /* cipher block chaining (NIST SP 800-38A) */
|
||||
#define CFB 1 /* cipher feedback (NIST SP 800-38A) */
|
||||
@@ -32,10 +31,12 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
|
||||
#define CTR 1 /* counter-block (NIST SP 800-38A) */
|
||||
#define XEX 1 /* xor-encrypt-xor (NIST SP 800-38E) */
|
||||
#define KWA 1 /* key wrap with authentication (NIST SP 800-38F) */
|
||||
#define FPE 0 /* format-preserving encryption (NIST SP 800-38G) */
|
||||
#define FPE 1 /* format-preserving encryption (NIST SP 800-38G) */
|
||||
#endif
|
||||
|
||||
#if AEAD_MODES
|
||||
#define CMAC 1 /* message authentication code (NIST SP 800-38B) */
|
||||
|
||||
#if CTR
|
||||
#define CCM 1 /* counter with CBC-MAC (RFC-3610 & SP 800-38C) */
|
||||
#define GCM 1 /* Galois/counter mode with GMAC (NIST SP 800-38D) */
|
||||
@@ -47,8 +48,6 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
|
||||
#if XEX
|
||||
#define OCB 1 /* offset codebook mode (RFC-7253) */
|
||||
#endif
|
||||
|
||||
#define CMAC 1 /* message authentication code (NIST SP 800-38B) */
|
||||
#endif
|
||||
|
||||
#if CBC
|
||||
@@ -67,7 +66,7 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
|
||||
#define EAXP 0 /* EAX-prime, as specified by IEEE Std 1703 */
|
||||
#endif
|
||||
|
||||
#define WTF! (BLOCK_CIPHER_MODES || CMAC)
|
||||
#define WTF (!CMAC && DISABLE_BLOCKCIPHER)
|
||||
#define MICRO_RJNDL WTF /* none of above; just rijndael API. dude.., why? */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
@@ -93,7 +92,7 @@ Refer to the BOTTOM OF THIS DOCUMENT for some explanations about these macros:
|
||||
|
||||
#if CCM
|
||||
#define CCM_NONCE_LEN 11 /* for 32-bit count (since one byte is reserved). */
|
||||
#define CCM_TAG_LEN 16
|
||||
#define CCM_TAG_LEN 16 /* an even number in the range of 4..16 */
|
||||
#endif
|
||||
|
||||
#if GCM
|
||||
@@ -110,10 +109,11 @@ Refer to the BOTTOM OF THIS DOCUMENT for some explanations about these macros:
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Since stdint.h is not a part of ANSI-C, we used a 'trick' that should not cause
|
||||
any problems. You may replace the following two lines by: #include <stdint.h>
|
||||
any problems. Just replace the lines ended by uint8_T with: #include <stdint.h>
|
||||
-----------------------------------------------------------------------------*/
|
||||
typedef unsigned char uint8_T;
|
||||
#define uint8_t uint8_T
|
||||
#include <string.h>
|
||||
typedef unsigned char uint8_T;
|
||||
#define uint8_t uint8_T
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -274,30 +274,6 @@ char AES_GCM_decrypt( const uint8_t* key, /* decryption key */
|
||||
uint8_t* pText ); /* decrypted plain-text */
|
||||
#endif /* GCM */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main functions for GCM-SIV-AES block ciphering
|
||||
-----------------------------------------------------------------------------*/
|
||||
#if GCM_SIV
|
||||
void GCM_SIV_encrypt( const uint8_t* key, /* encryption key */
|
||||
const uint8_t* nonce, /* a.k.a initialization vector */
|
||||
const uint8_t* pText, /* plain text */
|
||||
const size_t pTextLen, /* length of input plain text */
|
||||
const uint8_t* aData, /* added authentication data */
|
||||
const size_t aDataLen, /* size of authentication data */
|
||||
uint8_t* cText, /* cipher-text buffer */
|
||||
uint8_t* auTag ); /* message authentication tag */
|
||||
|
||||
char GCM_SIV_decrypt( const uint8_t* key, /* decryption key */
|
||||
const uint8_t* nonce, /* a.k.a initialization vector */
|
||||
const uint8_t* cText, /* cipher text */
|
||||
const size_t cTextLen, /* length of input cipher-text */
|
||||
const uint8_t* aData, /* added authentication data */
|
||||
const size_t aDataLen, /* size of authentication data */
|
||||
const uint8_t* auTag, /* authentication tag */
|
||||
const uint8_t tagSize, /* size of tag (if any) */
|
||||
uint8_t* pText ); /* decrypted plain-text */
|
||||
#endif /* GCM-SIV */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main functions for CCM-AES block ciphering
|
||||
-----------------------------------------------------------------------------*/
|
||||
@@ -378,6 +354,27 @@ char AES_EAX_decrypt( const uint8_t* key, /* decryption key */
|
||||
uint8_t* pText ); /* decrypted plain-text */
|
||||
#endif /* EAX */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main functions for GCM-SIV-AES block ciphering
|
||||
-----------------------------------------------------------------------------*/
|
||||
#if GCM_SIV
|
||||
void GCM_SIV_encrypt( const uint8_t* key, /* encryption key */
|
||||
const uint8_t* nonce, /* provided 96-bit nonce */
|
||||
const uint8_t* pText, /* plain text */
|
||||
const size_t pTextLen, /* length of input plain text */
|
||||
const uint8_t* aData, /* added authentication data */
|
||||
const size_t aDataLen, /* size of authentication data */
|
||||
uint8_t* cText ); /* cipher-text + 16 bytes tag */
|
||||
|
||||
char GCM_SIV_decrypt( const uint8_t* key, /* decryption key */
|
||||
const uint8_t* nonce, /* provided 96-bit nonce */
|
||||
const uint8_t* cText, /* cipher text + 16 bytes tag */
|
||||
const size_t cTextLen, /* length of cipher-text + 16 */
|
||||
const uint8_t* aData, /* added authentication data */
|
||||
const size_t aDataLen, /* size of authentication data */
|
||||
uint8_t* pText ); /* decrypted plain-text */
|
||||
#endif /* GCM-SIV */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main functions for AES key-wrapping; more info at the bottom of this page.
|
||||
-----------------------------------------------------------------------------*/
|
||||
@@ -393,6 +390,13 @@ char AES_KEY_unwrap( const uint8_t* kek, /* key encryption key */
|
||||
uint8_t* secret ); /* buffer for unwrapped key */
|
||||
#endif /* KWA */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main functions for FPE-AES (to be added soon)
|
||||
-----------------------------------------------------------------------------*/
|
||||
#if FPE
|
||||
|
||||
#endif /* FPE */
|
||||
|
||||
/**----------------------------------------------------------------------------
|
||||
Main function for AES cipher-based message authentication code
|
||||
-----------------------------------------------------------------------------*/
|
||||
@@ -421,9 +425,6 @@ The error codes and key length should be defined here for external references:
|
||||
#define AES_KEY_LENGTH 16
|
||||
#endif
|
||||
|
||||
#define SMALL_CIPHER 0 /* explained at the bottom ↓↓ */
|
||||
#define REDUCE_CODE_SIZE 1
|
||||
|
||||
#endif /* header guard */
|
||||
|
||||
/**--------------------------------------------------------------------------**\
|
||||
@@ -470,12 +471,19 @@ The error codes and key length should be defined here for external references:
|
||||
find some mentions of TKW which is for 3DES and irrelevant here. Anyway, the
|
||||
wrapped output has an additional block, i.e. wrappedSize = secretSize + 8.
|
||||
|
||||
* If the length of the input cipher/plain text is 'always' less than 4KB, you
|
||||
* Let me explain three extra options that are defined in the source file. The
|
||||
most sensitive part of the Rijndael algorithm is the round-keys. In this
|
||||
library they are defined as a static array, which might be exposed to some
|
||||
attacks. By enabling INCREASE_SECURITY macro, the RoundKey buffer is wiped
|
||||
at the end of ciphering operations. However, this is NOT A GUARANTEE against
|
||||
side-channel attacks.
|
||||
If the length of the input cipher/plain text is 'always' less than 4KB, you
|
||||
can enable the SMALL_CIPHER macro to save a few bytes in the compiled code.
|
||||
NOTE that for key-wrapping, this limit is 42 blocks (336 bytes) of secret
|
||||
Note that for key-wrapping, this limit is 42 blocks (336 bytes) of secret
|
||||
key. These assumptions are likely to be valid for some embedded systems and
|
||||
small applications. Furthermore, enabling that other macro, REDUCE_CODE_SIZE
|
||||
had a considerable effect on the size of the compiled code in my own tests.
|
||||
Nonetheless, others might get a different result from them.
|
||||
small applications.
|
||||
Furthermore, enabling that other macro, REDUCE_CODE_SIZE had a considerable
|
||||
effect on the size of the compiled code in my own tests. Nonetheless, others
|
||||
might get a different result from them.
|
||||
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user