merged commits

This commit is contained in:
polfosol
2022-10-03 22:40:02 +03:30
parent 7b4fccb231
commit 0d25733207
11 changed files with 1467 additions and 312 deletions

View File

@@ -11,17 +11,17 @@ With that in mind, I shall say that the main purpose of developing µAES was pur
## Features
* **Comprehensive —** supports any form of the AES standard with all different key sizes, i.e. you can use AES-128 or AES-192 or AES-256 simply by setting a macro.
* **All in one —** all popular (and some unpopular) blocks ciphering modes of the AES are implemented into a single file; such as **_ECB_**, **_CBC_**, **_CFB_**, **_OFB_**, **_CTR_**, **_XTS_**, **_KW_** / **_KWA_**, FPE, **_GCM_**, **_CCM_**, **_OCB_**, **_EAX_**, **_SIV_**, and GCM-SIV.
* **Clear and readable code —** hopefully, the code is written in a layman-friendly way. Lots of comments are added along the way to make its purpose more understandable. Also the code styling is a bit different, and IMO more eye-catching, than what you might see in other implementations.
* **Flexible —** many features of µAES are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These macros are defined in the header file `micro_aes.h` and comments are added for each of them to explain what they represent. *Please read those comments carefully before using the code*.
* **Lightweight —** the API has very little memory footprint and compiled code size. In my own tests and benchmarks, the amount of RAM used by the functions didn't exceed a few hundred bytes in most extreme cases. I might update this repo later with some of those benchmarks, and you are also cheerfully welcome to run yours.
* $\textrm{\textbf{Comprehensive}}$ — supports any form of the AES standard with all different key sizes, i.e. you can use AES-128 or AES-192 or AES-256 simply by setting a macro.
* $\textrm{\textbf{All in one}}$ — all popular (and some unpopular) block ciphering modes of the AES are implemented into a single file; such as [**_ECB_**, **_CBC_**, **_CFB_**, **_OFB_**, **_CTR_**](https://csrc.nist.gov/publications/detail/sp/800-38a/final), [**_GCM_**](https://csrc.nist.gov/publications/detail/sp/800-38d/final), [**_CCM_**](https://csrc.nist.gov/publications/detail/sp/800-38c/final), [**_XTS_**](https://csrc.nist.gov/publications/detail/sp/800-38e/final), [**_OCB_**](https://www.rfc-editor.org/rfc/rfc7253.html), [**_EAX_**](https://en.wikipedia.org/wiki/EAX_mode), [**_KW_** (**_KWA_**)](https://csrc.nist.gov/publications/detail/sp/800-38f/final), [**_SIV_**](https://www.rfc-editor.org/rfc/rfc5297.html), [**_GCM-SIV_**](https://www.rfc-editor.org/rfc/rfc8452.html), FPE, and furthermore, a [**_CMAC_**](https://csrc.nist.gov/publications/detail/sp/800-38b/final) authentication API.
* $\textrm{\textbf{Clear and readable code}}$ — hopefully, the code is written in a layman-friendly way. Lots of comments are added along the way to make its purpose more understandable. Also the code styling is a bit different, and IMHO more eye-catching, than what you might see in other implementations.
* $\textrm{\textbf{Flexible}}$ — many features of µAES are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These macros are defined in the header file `micro_aes.h` and comments are added for each of them to explain what they represent. *Please read those comments carefully before using the code*.
* $\textrm{\textbf{Lightweight}}$ — the API has very little memory footprint and compiled code size. In my own tests and benchmarks, the amount of RAM used by the functions didn't exceed a few hundred bytes in most extreme cases. I might update this repo later with some of those benchmarks, and you are also cheerfully welcome to run yours.
Furthermore, the ROM space of µAES is optimized as much as possible. For example, if you disable all other macros and just stick with the GCM, the compiled code size will be less than 3.5KB on an x86 machine for either AES-128-GCM or AES-256-GCM.
* **Fast —** the encryption or decryption speed is often an order of magnitude higher than some .net based implementations and even C++ libraries. Since code simplicity and portability was a main concern, paralellization or advanced CPU optimizations are not a feature of µAES, which might affect its overall speed.
Moreover, the ROM space of µAES is optimized as much as possible. For example, if you disable all other macros and just stick with the GCM, the compiled code size will be less than 3.5KB on an x86 machine for either AES-128-GCM or AES-256-GCM.
* $\textrm{\textbf{Fast}}$ — the encryption or decryption speed is often an order of magnitude higher than some .net based implementations and surprisingly, even a couple of C++ APIs. Since code simplicity and portability was a main concern, paralellization or advanced CPU optimizations are not a feature of µAES, which will affect its overall speed.
Anyway, speed is not always a blessing in cryptography and even sometimes slower codes turn out to be more secure. One must be wary of those speedups that make the code more susceptible to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
* **Portable —** µAES is all-in-one with no dependencies on any other library. It is fully compatible with ANSI-C or C89 standard which, combined with its small size, makes it a competent candidate for embedded systems and mini applications.
As a side note, speed is not always a blessing in cryptography and sometimes slower codes turn out to be more secure. One must be wary of those speedups that make the code more susceptible to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
* $\textrm{\textbf{Portable}}$ — µAES is all-in-one with no dependencies on any other library. It is fully compatible with ANSI-C or C89 standard which, combined with its small size, makes it a competent candidate for embedded systems and mini applications.
You can even compile it with [Tiny C Compiler](https://bellard.org/tcc/):
@@ -33,7 +33,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 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 very 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 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.
µAES is heavily 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.
@@ -41,4 +41,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) 🖤
![The foot-shooting prevention agreement taken from Jeff Moser's blog](https://i.stack.imgur.com/SoY7x.png)

82
main.c
View File

@@ -2,7 +2,7 @@
==============================================================================
Name : main.c
Author : polfosol
Version : 8.7.0.0
Version : 8.9.0.1
Copyright : copyright © 2022 - polfosol
Description : test vectors for µAES ™ library, mostly generated by Crypto++ ®
==============================================================================
@@ -33,10 +33,10 @@ static const char
3f9c56525efbe64a 876ad1d761d3fc93 59fb4f5b2354acd4 90",
*ofbcipher = "edab3105e673bc9e b9102539a9f457bc d28c8e4c92995f5c d9426926be1e775d\
e22b8ce4d0278b18 181b8bec93b9726f 959aa5d701d46102 f0",
#if ~INIT_CTR_VALUE == 0
#if CTR_IV_LENGTH == 16
*ctrcipher = "edab3105e673bc9e b9102539a9f457bc f2e2606dfa3f93c5 c51b910a89cddb67\
191a118531ea0427 97626c9bfd370426 fdf3f59158bf7d4d 43",
#else
#elif CTR_STARTVALUE == 1
*ctrcipher = "6c6bae886c235d8c 7997d45c1bf0bca2 48b4bca9eb396d1b f6945e5b7a4fc10f\
488cfe76fd5eaeff 2b8fb469f78fa61e 285e4cf9b9aee3d0 a8",
#endif
@@ -129,14 +129,14 @@ int main()
str2bytes(ecbcipher, test);
AES_ECB_encrypt(key, input, st, output);
check("ECB encryption", output, test, sizeof input);
AES_ECB_decrypt(key, test, sizeof input, output);
*output ^= AES_ECB_decrypt(key, test, sizeof input, output);
check("ECB decryption", output, input, st);
#endif
#if CBC && AES_KEY_LENGTH == 16
str2bytes(cbccipher, test);
AES_CBC_encrypt(key, iv, input, st, output);
check("CBC encryption", output, test, st);
AES_CBC_decrypt(key, iv, test, CTS ? st : sizeof input, output);
check("CBC encryption", output, test, CTS ? st : sizeof input);
*output ^= AES_CBC_decrypt(key, iv, test, CTS ? st : sizeof input, output);
check("CBC decryption", output, input, st);
#endif
#if CFB && AES_KEY_LENGTH == 16
@@ -162,45 +162,43 @@ int main()
#endif
#if XTS && AES_KEY_LENGTH != 24
str2bytes(xtscipher, test);
AES_XTS_encrypt(key, iv, input, st, output);
*output ^= AES_XTS_encrypt(key, iv, input, st, output);
check("XTS encryption", output, test, st);
AES_XTS_decrypt(key, iv, test, st, output);
*output ^= AES_XTS_decrypt(key, iv, test, st, output);
check("XTS decryption", output, input, st);
#endif
#if CMAC && AES_KEY_LENGTH == 16
str2bytes("2b7e1516 28aed2a6 abf71588 09cf4f3c", output);
str2bytes("", output + 16);
str2bytes("bb1d6929 e9593728 7fa37d12 9b756746", output + 64);
AES_CMAC(output, output + 16, 0, output + 48);
check("calculate CMAC", output + 48, output + 64, 16);
str2bytes(cmac_hash, test);
AES_CMAC(key, input, st, output);
check("CMAC obtaining", output, test, 16);
#endif
a = mainKey + 1; /* aad */
#if GCM && AES_KEY_LENGTH == 16
str2bytes(gcmcipher, test);
AES_GCM_encrypt(key, iv, input, st, a, sa, output, output + st);
check("GCM encryption", output, test, st + 16);
AES_GCM_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
*output ^= AES_GCM_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
check("GCM decryption", output, input, st);
#endif
#if CCM && AES_KEY_LENGTH == 16
str2bytes(ccmcipher, test);
AES_CCM_encrypt(key, iv, input, st, a, sa, output, output + st);
check("CCM encryption", output, test, st + CCM_TAG_LEN);
AES_CCM_decrypt(key, iv, test, st, a, sa, test + st, CCM_TAG_LEN, output);
*output ^= AES_CCM_decrypt(key, iv, test, st, a, sa, test + st, CCM_TAG_LEN, output);
check("CCM decryption", output, input, st);
#endif
#if OCB && AES_KEY_LENGTH == 16
str2bytes(ocbcipher, test);
AES_OCB_encrypt(key, iv, input, st, a, sa, output, output + st);
check("OCB encryption", output, test, st + OCB_TAG_LEN);
AES_OCB_decrypt(key, iv, test, st, a, sa, test + st, OCB_TAG_LEN, output);
*output ^= AES_OCB_decrypt(key, iv, test, st, a, sa, test + st, OCB_TAG_LEN, output);
check("OCB decryption", output, input, st);
#endif
#if SIV && AES_KEY_LENGTH == 16
str2bytes(sivcipher, test);
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
check("SIV encryption", output, test, st + 16);
AES_SIV_decrypt(key, test + 16, st, a, sa, test, output);
*output ^= AES_SIV_decrypt(key, test + 16, st, a, sa, test, output);
check("SIV decryption", output, input, st);
#endif
#if EAX && AES_KEY_LENGTH == 16
@@ -208,29 +206,31 @@ int main()
#if EAXP
AES_EAX_encrypt(key, a, input, st, sa, output, output + st);
check("EAX encryption", output, test, st + 4);
AES_EAX_decrypt(key, a, test, st, sa, output);
*output ^= AES_EAX_decrypt(key, a, test, st, sa, output);
#else
AES_EAX_encrypt(key, iv, input, st, a, sa, output, output + st);
check("EAX encryption", output, test, st + 16);
AES_EAX_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
*output ^= AES_EAX_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
#endif
check("EAX decryption", output, input, st);
#endif
#if GCM_SIV && AES_KEY_LENGTH == 16
str2bytes(gsvcipher, test);
check("GCM-SIV encryption", output, test, st + 16);
check("GCM-SIV decryption", output, input, st);
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);
check("key wrapping ", output, test, AES_KEY_LENGTH + 8);
AES_KEY_unwrap(mainKey, test, AES_KEY_LENGTH + 8, output);
*output ^= AES_KEY_unwrap(mainKey, test, AES_KEY_LENGTH + 8, output);
check("key unwrapping", output, key + 32, AES_KEY_LENGTH);
#endif
/** a template for "OFFICIAL TEST VECTORS": */
#if OCB && EAX && SIV && AES_KEY_LENGTH == 16
#if OCB && EAX && SIV && GCM_SIV && AES_KEY_LENGTH == 16
printf("+-> Let's do some extra tests\n");
st = sa = 24; /* taken from RFC 7253: */
@@ -242,9 +242,21 @@ int main()
C92C62241051F57356D7F3C90BB0E07F", test);
AES_OCB_encrypt(key, iv, input, st, a, sa, output, output + st);
check("OCB encryption", output, test, st + OCB_TAG_LEN);
AES_OCB_decrypt(key, iv, test, st, a, sa, test + st, OCB_TAG_LEN, output);
*output ^= AES_OCB_decrypt(key, iv, test, st, a, sa, test + st, OCB_TAG_LEN, output);
check("OCB decryption", output, input, st);
st = 12; sa = 1; /* taken from RFC 8452: */
str2bytes("01000000000000000000000000000000", key);
str2bytes("030000000000000000000000", iv);
str2bytes("01", a);
str2bytes("020000000000000000000000", input);
str2bytes("296c7889fd99f41917f4462008299c51\
02745aaa3a0c469fad9e075a", 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);
st = 14; sa = 24; /* taken from RFC 5297: */
str2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff", key);
@@ -255,18 +267,28 @@ int main()
40c02b96 90c4dc04 daef7f6a fe5c", test);
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
check("SIV encryption", output, test, st + 16);
AES_SIV_decrypt(key, test + 16, st, a, sa, test, output);
*output ^= AES_SIV_decrypt(key, test + 16, st, a, sa, test, output);
check("SIV decryption", output, input, st);
st = 16; sa = 0; /* from miscreant: https://bit.ly/3yc2GBs */
str2bytes("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", key);
str2bytes("", a);
str2bytes("00112233445566778899aabbccddeeff", input);
str2bytes("f304f912863e303d5b540e5057c7010c942ffaf45b0e5ca5fb9a56a5263bb065", test);
AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
check("SIV encryption", output, test, st + 16);
AES_SIV_decrypt(key, test + 16, st, a, sa, test, output);
*output ^= AES_SIV_decrypt(key, test + 16, st, a, sa, test, 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);
str2bytes("A20D060B607C86F7540116007BC175A8\
03020100BE0D280B810984A60C060A60\
7C86F7540116007B040248F3C2040330\
0005", test);
str2bytes("515AE775", key);
AES_EAX_encrypt(mainKey, test, input, st, sa, output, output + st);
check("EAX encryption", output, key, st + 4);
*output ^= AES_EAX_decrypt(mainKey, test, key, st, sa, output);
check("EAX decryption", output, input, st);
st = 28; sa = 65; /* from Moise-Beroset-Phinney-Burns paper: */
str2bytes("10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 00", mainKey);
str2bytes("a2 0e 06 0c 60 86 48 01 86 fc 2f 81 1c aa 4e 01\
@@ -278,9 +300,9 @@ int main()
30 30 30 30 30 30 00 00 03 30 00 01", input);
str2bytes("9c f3 2c 7e c2 4c 25 0b e7 b0 74 9f ee e7 1a 22\
0d 0e ee 97 6e c2 3d bf 0c aa 08 ea 00 54 3e 66", key);
AES_EAX_encrypt(mainKey, test, sa, input, st, output, output + st);
AES_EAX_encrypt(mainKey, test, input, st, sa, output, output + st);
check("EAX encryption", output, key, st + 4);
AES_EAX_decrypt(mainKey, test, sa, key, st, output);
*output ^= AES_EAX_decrypt(mainKey, test, key, st, sa, output);
#else
st = 12; sa = 8; /* from Bellare-Rogaway-Wagner 2004 paper: */
str2bytes("BD8E6E11475E60B268784C38C62FEB22", key);
@@ -290,7 +312,7 @@ int main()
str2bytes("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F", test);
AES_EAX_encrypt(key, iv, input, st, a, sa, output, output + st);
check("EAX encryption", output, test, st + 16);
AES_EAX_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
*output ^= AES_EAX_decrypt(key, iv, test, st, a, sa, test + st, 16, output);
#endif
check("EAX decryption", output, input, st);
#endif

View File

@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.c
Author : polfosol
Version : 8.7.0.0
Version : 8.9.0.0
Copyright : copyright © 2022 - polfosol
Description : ANSI-C compatible implementation of µAES ™ library.
==============================================================================
@@ -246,7 +246,7 @@ static void RijndaelEncrypt( const block_t input, block_t output )
/* copy the input to the state matrix, and beware of undefined behavior.. */
if (input != output) memcpy( output, input, BLOCKSIZE );
/* The encryption process is done in #ROUNDS iterations, of which the first
/* The encryption is carried out in #ROUNDS iterations, of which the first
* #ROUNDS-1 are identical. The last round doesn't involve mixing columns */
do
{
@@ -364,7 +364,7 @@ static void RijndaelDecrypt( const block_t input, block_t output )
#endif /* DECRYPTION */
#if !BLOCK_CIPHERS_MODES
#if !BLOCK_CIPHER_MODES
/**
* @brief encrypt or decrypt a single block with a given key
* @param key a byte array with a fixed size specified by KEYSIZE
@@ -408,8 +408,7 @@ static char padBlock( const uint8_t* input, const uint8_t len, block_t output )
#if defined(AEAD_MODES) || CTS
/** The input block `y` is xor-ed with a (partial) block `x` up to length `len`.
* And then the result is mixed with block `src` via a digest/mixing function */
/** The input block `y` is xor-ed with `x` and then mixed with block `src`... */
static void xorThenMix( const uint8_t* x, const uint8_t len,
const block_t src, fmix_t mix, block_t y )
{
@@ -476,7 +475,7 @@ static void putValueB( block_t block, uint8_t pos, size_t val )
#endif
#endif /* CTR */
#if OCB || SIV || (EAX && !EAXP)
#if EAX && !EAXP || SIV || OCB
/** Multiply a block by two in GF(2^128) field: the big-endian version ...... */
static void doubleGf128B( block_t block )
@@ -529,7 +528,7 @@ static void halveGf128B( block_t block )
if (c) block[0] ^= 0xe1; /* B ^= 11100001b << 120 */
}
/** This function performs multiplications in 128 bit Galois bit field ...... */
/** This function carries out multiplication in 128bit Galois field GF(2^128) */
static void MulGf128( const block_t x, block_t y )
{
uint8_t i, j, result[BLOCKSIZE] = { 0 }; /* working memory */
@@ -554,9 +553,9 @@ static void MulGf128( const block_t x, block_t y )
static void nop( const block_t x, block_t y ) {}
/** get the offset block (Δ_i) at a specified index for a given L$ and Δ_0 .. */
static void getOffset( const block_t Ld, const count_T index, block_t delta )
static void getOffset( const block_t Ld, const count_t index, block_t delta )
{
count_T b = 1;
count_t b = 1;
block_t L;
memcpy( L, Ld, sizeof L );
@@ -576,11 +575,11 @@ static void getOffset( const block_t Ld, const count_T index, block_t delta )
/** the overall scheme of CMAC or GMAC hash functions: divide data into 128-bit
* blocks; then xor and apply the digest/mixing function to each xor-ed block */
static void MAC( const void* data, const size_T dataSize,
static void MAC( const void* data, const size_t dataSize,
const block_t seed, fmix_t mix, block_t result )
{
const uint8_t *x = (const uint8_t*) data;
count_T n = dataSize / BLOCKSIZE; /* number of full blocks */
const uint8_t *x = data;
count_t n = dataSize / BLOCKSIZE; /* number of full blocks */
while (n--)
{
@@ -620,10 +619,10 @@ static void MAC( const void* data, const size_T dataSize,
* @param cText cipher-text buffer
*/
void AES_ECB_encrypt( const uint8_t* key,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
uint8_t *p = (uint8_t*) pText, *c = cText;
count_T n = pTextLen / BLOCKSIZE; /* number of full blocks */
count_t n = pTextLen / BLOCKSIZE; /* number of full blocks */
AES_SetKey( key );
while (n--)
@@ -647,10 +646,10 @@ void AES_ECB_encrypt( const uint8_t* key,
* @return whether size of ciphertext is a multiple of BLOCKSIZE
*/
char AES_ECB_decrypt( const uint8_t* key,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
uint8_t *c = (uint8_t*) cText, *p = pText;
count_T n = cTextLen / BLOCKSIZE;
count_t n = cTextLen / BLOCKSIZE;
AES_SetKey( key );
while (n--)
@@ -680,11 +679,11 @@ char AES_ECB_decrypt( const uint8_t* key,
* @param cText cipher-text buffer
*/
void AES_CBC_encrypt( const uint8_t* key, const block_t iVec,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
const uint8_t *p = pText, *iv = iVec;
uint8_t *c = cText;
count_T n = pTextLen / BLOCKSIZE; /* number of full blocks */
count_t n = pTextLen / BLOCKSIZE; /* number of full blocks */
#if CTS
n -= (n > 1 && pTextLen % BLOCKSIZE == 0); /* hold the last block */
@@ -726,11 +725,11 @@ void AES_CBC_encrypt( const uint8_t* key, const block_t iVec,
* @return whether size of ciphertext is a multiple of BLOCKSIZE
*/
char AES_CBC_decrypt( const uint8_t* key, const block_t iVec,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
const uint8_t *c = cText, *iv = iVec;
uint8_t *p = pText;
count_T n = cTextLen / BLOCKSIZE;
count_t n = cTextLen / BLOCKSIZE;
#if CTS
if (!n) return DECRYPTION_FAILURE;
@@ -777,11 +776,11 @@ char AES_CBC_decrypt( const uint8_t* key, const block_t iVec,
* @param cText cipher-text buffer
*/
void AES_CFB_encrypt( const uint8_t* key, const block_t iVec,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
const uint8_t *p = pText, *iv = iVec;
uint8_t *c = cText, tmp[BLOCKSIZE];
count_T n = pTextLen / BLOCKSIZE;
count_t n = pTextLen / BLOCKSIZE;
AES_SetKey( key );
while (n--)
@@ -791,7 +790,6 @@ void AES_CFB_encrypt( const uint8_t* key, const block_t iVec,
iv = c;
GOTO_NEXT_BLOCK
}
mixThenXor( iv, &RijndaelEncrypt, tmp, p, pTextLen % BLOCKSIZE, c );
BURN_AFTER_READ
}
@@ -805,11 +803,11 @@ void AES_CFB_encrypt( const uint8_t* key, const block_t iVec,
* @param pText plain-text output buffer
*/
void AES_CFB_decrypt( const uint8_t* key, const block_t iVec,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
const uint8_t *c = cText, *iv = iVec;
uint8_t *p = pText, tmp[BLOCKSIZE];
count_T n = cTextLen / BLOCKSIZE; /* number of full blocks */
count_t n = cTextLen / BLOCKSIZE; /* number of full blocks */
AES_SetKey( key );
while (n--)
@@ -819,7 +817,6 @@ void AES_CFB_decrypt( const uint8_t* key, const block_t iVec,
iv = c;
GOTO_NEXT_BLOCK
}
mixThenXor( iv, &RijndaelEncrypt, tmp, c, cTextLen % BLOCKSIZE, p );
BURN_AFTER_READ
}
@@ -839,11 +836,11 @@ void AES_CFB_decrypt( const uint8_t* key, const block_t iVec,
* @param cText cipher-text buffer
*/
void AES_OFB_encrypt( const uint8_t* key, const block_t iVec,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
uint8_t *y = cText;
block_t iv;
count_T n = pTextLen / BLOCKSIZE;
count_t n = pTextLen / BLOCKSIZE;
memcpy( iv, iVec, sizeof iv );
memcpy( cText, pText, pTextLen ); /* copy plain text to output */
@@ -855,7 +852,6 @@ void AES_OFB_encrypt( const uint8_t* key, const block_t iVec,
xorBlock( iv, y ); /* IV_next = Enc(IV) */
y += BLOCKSIZE;
}
mixThenXor( iv, &RijndaelEncrypt, iv, y, pTextLen % BLOCKSIZE, y );
BURN_AFTER_READ
}
@@ -869,7 +865,7 @@ void AES_OFB_encrypt( const uint8_t* key, const block_t iVec,
* @param pText plain-text output buffer
*/
void AES_OFB_decrypt( const uint8_t* key, const block_t iVec,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
AES_OFB_encrypt( key, iVec, cText, cTextLen, pText );
}
@@ -883,35 +879,30 @@ void AES_OFB_decrypt( const uint8_t* key, const block_t iVec,
/**
* @brief the overall scheme of operation in block-counter mode
* @param iVec initialization vector a.k.a. nonce
* @param ctrStart starting value for block-counter
* @param preInc pre-increment the counter block (for GCM)
* @param input plain/cipher-text input buffer
* @param dataSize size of input buffer
* @param output cipher/plain-text buffer
*/
static void CTR_Cipher( const uint8_t* iVec, const size_T ctrStart,
const void* input, const size_T dataSize, void* output )
static void CTR_Cipher( const uint8_t* iVec, const int preInc,
const void* input, const size_t dataSize, void* output )
{
uint8_t *p = (uint8_t*) input, *c = output;
block_t ctr = { 0 };
count_T n = dataSize / BLOCKSIZE;
const uint8_t *p = input;
uint8_t *c = output, ctr[BLOCKSIZE];
count_t n = dataSize / BLOCKSIZE;
if (ctrStart == (size_T) ~0) /* specifying this value for */
{ /* ..counter start means the */
memcpy( ctr, iVec, sizeof ctr ); /* ..count was initiated */
} /* ..inside the iv block */
else
memcpy( ctr, iVec, sizeof ctr );
if (preInc)
{
memcpy( ctr, iVec, CTR_IV_LENGTH );
putValueB( ctr, BLOCKSIZE - 1, ctrStart );
incBlockB( ctr, sizeof ctr );
}
while (n--)
{
RijndaelEncrypt( ctr, c ); /* both in (en/de)cryption: */
xorBlock( p, c ); /* Y = Enc(Ctr) ^ X */
incBlockB( ctr, BLOCKSIZE ); /* Ctr_next = Ctr + 1 */
incBlockB( ctr, sizeof ctr ); /* Ctr_next = Ctr + 1 */
GOTO_NEXT_BLOCK
}
mixThenXor( ctr, &RijndaelEncrypt, ctr, p, dataSize % BLOCKSIZE, c );
}
#endif
@@ -930,10 +921,15 @@ static void CTR_Cipher( const uint8_t* iVec, const size_T ctrStart,
* @param cText cipher-text buffer
*/
void AES_CTR_encrypt( const uint8_t* key, const uint8_t* iv,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
block_t ctr = { 0 };
AES_SetKey( key );
CTR_Cipher( iv, INIT_CTR_VALUE, pText, pTextLen, cText );
memcpy( ctr, iv, CTR_IV_LENGTH < sizeof ctr ? CTR_IV_LENGTH : sizeof ctr );
#if CTR_IV_LENGTH < BLOCKSIZE
putValueB( ctr, BLOCKSIZE - 1, CTR_STARTVALUE );
#endif
CTR_Cipher( ctr, 0, pText, pTextLen, cText );
BURN_AFTER_READ
}
@@ -946,7 +942,7 @@ void AES_CTR_encrypt( const uint8_t* key, const uint8_t* iv,
* @param pText plain-text output buffer
*/
void AES_CTR_decrypt( const uint8_t* key, const uint8_t* iv,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
AES_CTR_encrypt( key, iv, cText, cTextLen, pText ); /* similar to OFB */
}
@@ -968,13 +964,13 @@ void AES_CTR_decrypt( const uint8_t* key, const uint8_t* iv,
* @param output working memory; result of encryption/decryption process
*/
static void XEX_Cipher( const uint8_t* keypair, fmix_t cipher,
const size_T dataSize, const size_T scid,
const size_t dataSize, const size_t scid,
const block_t tweakid, block_t pad, void* output )
{
uint8_t *y = output;
count_T n = dataSize / BLOCKSIZE;
count_t n = dataSize / BLOCKSIZE;
if (scid == (size_T) ~0)
if (scid == (size_t) ~0)
{ /* the `i` block is either */
memcpy( pad, tweakid, BLOCKSIZE ); /* ..a little-endian number */
} /* ..or a byte array. */
@@ -1008,11 +1004,11 @@ static void XEX_Cipher( const uint8_t* keypair, fmix_t cipher,
* @param cText cipher-text buffer
*/
char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* twkId,
const uint8_t* pText, const size_T pTextLen, uint8_t* cText )
const uint8_t* pText, const size_t pTextLen, uint8_t* cText )
{
block_t T = { 0 };
uint8_t r = pTextLen % BLOCKSIZE, *c;
size_T len = pTextLen - r;
size_t len = pTextLen - r;
if (len == 0) return ENCRYPTION_FAILURE;
memcpy( cText, pText, len ); /* copy input data to output */
@@ -1041,11 +1037,11 @@ char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* twkId,
* @param pText plain-text output buffer
*/
char AES_XTS_decrypt( const uint8_t* keys, const uint8_t* twkId,
const uint8_t* cText, const size_T cTextLen, uint8_t* pText )
const uint8_t* cText, const size_t cTextLen, uint8_t* pText )
{
block_t TT, T = { 0 };
uint8_t r = cTextLen % BLOCKSIZE, *p;
size_T len = cTextLen - r;
size_t len = cTextLen - r;
if (len == 0) return DECRYPTION_FAILURE;
memcpy( pText, cText, len ); /* copy input data to output */
@@ -1100,31 +1096,32 @@ static void GetSubkeys( const uint8_t* key, const int LE, block_t D, block_t Q )
/** calculate the CMAC hash of input data using pre-calculated keys: D and Q. */
static void Cmac( const block_t D, const block_t Q,
const void* data, const size_T dataSize, block_t mac )
const void* data, const size_t dataSize, block_t mac )
{
block_t M = { 0 };
uint8_t r = dataSize ? (dataSize - 1) % BLOCKSIZE + 1 : 0;
const void *last = (const char*) data + dataSize - r;
const void *last_ptr = (const char*) data + dataSize - r;
if (r < BLOCKSIZE) M[r] = 0x80;
memcpy( M, last, r ); /* copy last block into M */
xorBlock( r < BLOCKSIZE ? Q : D, M ); /* ..and pad( M; D, Q ) */
if (r < sizeof M) M[r] = 0x80;
memcpy( M, last_ptr, r ); /* copy last block into M */
xorBlock( r < sizeof M ? Q : D, M ); /* ..and pad( M; D, Q ) */
MAC( data, dataSize - r, mac, &RijndaelEncrypt, mac );
xorThenMix( M, sizeof M, mac, &RijndaelEncrypt, mac );
}
/**
* @brief derive the CMAC hash of input data with a given encryption key
* @param key AES-128 encryption key
* @brief derive the AES-CMAC hash of input data using an encryption key
* @param key AES encryption key
* @param data buffer of input data
* @param dataSize size of data in bytes
* @param mac calculated CMAC hash; must be pre-initialized
* @param mac calculated CMAC hash
*/
void AES_CMAC( const uint8_t* key,
const void* data, const size_T dataSize, block_t mac )
const void* data, const size_t dataSize, block_t mac )
{
block_t D = { 0 }, Q;
memset( mac, 0, BLOCKSIZE );
GetSubkeys( key, 0, D, Q );
Cmac( D, Q, data, dataSize, mac );
}
@@ -1137,25 +1134,38 @@ void AES_CMAC( const uint8_t* key,
#if IMPLEMENT(GCM)
/** calculates GMAC hash of ciphertext and AAD using authentication subkey AK */
static void GHash( const block_t AK, const uint8_t* ctext, const uint8_t* adata,
const size_T ctextLen, const size_T adataLen, block_t hash )
static void GHash( const block_t AK, const uint8_t* cText, const uint8_t* aData,
const size_t ctextLen, const size_t adataLen, block_t GH )
{
block_t bitLen = { 0 };
block_t sizeBuf = { 0 };
/* digest and process additional data and ciphertext into GHash function: */
MAC( adata, adataLen, AK, &MulGf128, hash );
MAC( ctext, ctextLen, AK, &MulGf128, hash );
MAC( aData, adataLen, AK, &MulGf128, GH ); /* first digest AAD and then */
MAC( cText, ctextLen, AK, &MulGf128, GH ); /* ..ciphertext into GHash */
/* copy length info (bit-length) of hashed data into bitLen, then GMAC .. */
putValueB( bitLen, BLOCKSIZE - 9, adataLen * 8 );
putValueB( bitLen, BLOCKSIZE - 1, ctextLen * 8 );
MAC( bitLen, sizeof bitLen, AK, &MulGf128, hash );
/* copy length info (bit-length) of hashed data into sizeBuf, then GMAC.. */
putValueB( sizeBuf, BLOCKSIZE - 9, adataLen * 8 );
putValueB( sizeBuf, BLOCKSIZE - 1, ctextLen * 8 );
MAC( sizeBuf, sizeof sizeBuf, AK, &MulGf128, GH );
}
/** encrypt zeros to get authentication subkey H, and prepare the IV for GCM. */
static void GCM_GetIVH( const uint8_t* key, const uint8_t* nonce,
block_t authKey, block_t iv )
{
AES_SetKey( key );
RijndaelEncrypt( authKey, authKey ); /* authKey = Enc(zero block) */
#if GCM_NONCE_LEN != 12
GHash( authKey, nonce, NULL, GCM_NONCE_LEN, 0, iv );
#else
memcpy( iv, nonce, GCM_NONCE_LEN );
iv[BLOCKSIZE - 1] = 1;
#endif
}
/**
* @brief encrypt the input plaintext using GCM-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
* @param iv initialization vector a.k.a nonce. has GCM_NONCE_LEN bytes
* @param nonce a.k.a initialization vector with fixed size GCM_NONCE_LEN
* @param pText input plain-text buffer
* @param pTextLen size of input buffer
* @param aData additional authentication data
@@ -1163,25 +1173,24 @@ static void GHash( const block_t AK, const uint8_t* ctext, const uint8_t* adata,
* @param cText encrypted cipher-text buffer
* @param auTag message authentication tag. buffer must be 16-bytes long
*/
void AES_GCM_encrypt( const uint8_t* key, const uint8_t* iv,
const uint8_t* pText, const size_T pTextLen,
const uint8_t* aData, const size_T aDataLen,
void AES_GCM_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 )
{
block_t GH = { 0 }, authKey = { 0 };
AES_SetKey( key ); /* encrypt zero block to get */
RijndaelEncrypt( authKey, authKey ); /* authentication sub-key H */
block_t H = { 0 }, iv = { 0 }, g = { 0 };
GCM_GetIVH( key, nonce, H, iv ); /* get IV & auth. subkey H */
CTR_Cipher( iv, 2, pText, pTextLen, cText );
GHash( authKey, cText, aData, pTextLen, aDataLen, GH );
CTR_Cipher( iv, 1, GH, sizeof GH, auTag ); /* encrypt and calculate tag */
CTR_Cipher( iv, 1, pText, pTextLen, cText );
GHash( H, cText, aData, pTextLen, aDataLen, g );
CTR_Cipher( iv, 0, g, sizeof g, auTag ); /* auth. tag = Enc( GHASH ) */
BURN_AFTER_READ
}
/**
* @brief decrypt the input ciphertext using GCM-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
* @param iv initialization vector a.k.a nonce. has GCM_NONCE_LEN bytes
* @param nonce a.k.a initialization vector with fixed size GCM_NONCE_LEN
* @param cText input cipher-text buffer
* @param cTextLen size of input buffer
* @param aData additional authentication data
@@ -1191,25 +1200,23 @@ void AES_GCM_encrypt( const uint8_t* key, const uint8_t* iv,
* @param pText plain-text output buffer
* @return whether message authentication was successful
*/
char AES_GCM_decrypt( const uint8_t* key, const uint8_t* iv,
const uint8_t* cText, const size_T cTextLen,
const uint8_t* aData, const size_T aDataLen,
char AES_GCM_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 )
{
block_t GH = { 0 }, AK = { 0 };
AES_SetKey( key ); /* encrypt zero block to get */
RijndaelEncrypt( AK, AK ); /* authentication sub-key H */
block_t H = { 0 }, iv = { 0 }, g = { 0 };
GCM_GetIVH( key, nonce, H, iv );
GHash( AK, cText, aData, cTextLen, aDataLen, GH );
CTR_Cipher( iv, 1, GH, sizeof GH, AK ); /* save the tag into AK! */
if (memcmp( AK, auTag, tagSize ) != 0) /* compare tags and proceed */
GHash( H, cText, aData, cTextLen, aDataLen, g );
CTR_Cipher( iv, 0, g, sizeof g, H ); /* save the tag into H! */
if (memcmp( H, auTag, tagSize ) != 0) /* compare tags and proceed */
{ /* ..if they match. */
BURN_AFTER_READ
return AUTHENTICATION_FAILURE;
}
CTR_Cipher( iv, 2, cText, cTextLen, pText );
CTR_Cipher( iv, 1, cText, cTextLen, pText );
BURN_AFTER_READ
return ENDED_IN_SUCCESS;
}
@@ -1225,7 +1232,7 @@ char AES_GCM_decrypt( const uint8_t* key, const uint8_t* iv,
* method. calculated tag's size is 16 bytes which can be truncated afterward */
static void CCM_GetTag( const block_t iv,
const uint8_t* pText, const uint8_t* aData,
const size_T pTextLen, const size_T aDataLen,
const size_t pTextLen, const size_t aDataLen,
block_t tag )
{
block_t S = { 0 }, A = { 0 };
@@ -1246,7 +1253,7 @@ static void CCM_GetTag( const block_t iv,
m -= 4;
putValueB( A, 1, 0xFFFE ); /* prepend FFFE to len_id */
}
memcpy( A + p + 1, aData, m ); /* A = len_id || ADATA */
memcpy( A + p + 1, aData, m ); /* A = len_id ~~ ADATA */
S[0] |= 0x40;
RijndaelEncrypt( S, S ); /* S_1 = Enc(S_0) ^ A */
xorBlock( A, S );
@@ -1264,7 +1271,7 @@ static void CCM_GetTag( const block_t iv,
/**
* @brief encrypt the input plaintext using CCM-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
* @param iVec init-vector a.k.a nonce, containing CCM_NONCE_LEN bytes
* @param nonce a.k.a initialization vector with fixed size CCM_NONCE_LEN
* @param pText input plain-text buffer
* @param pTextLen size of input buffer
* @param aData additional authentication data
@@ -1272,25 +1279,25 @@ static void CCM_GetTag( const block_t iv,
* @param cText encrypted cipher-text buffer
* @param auTag message authentication tag. buffer must be 16-bytes long
*/
void AES_CCM_encrypt( const uint8_t* key, const uint8_t* iVec,
const uint8_t* pText, const size_T pTextLen,
const uint8_t* aData, const size_T aDataLen,
void AES_CCM_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 )
{
block_t iv = { 14 - CCM_NONCE_LEN, 0 };
memcpy( iv + 1, iVec, CCM_NONCE_LEN );
memcpy( iv + 1, nonce, CCM_NONCE_LEN );
iv[sizeof iv - 1] = 1;
AES_SetKey( key );
CCM_GetTag( iv, pText, aData, pTextLen, aDataLen, auTag );
CTR_Cipher( iv, ~0, pText, pTextLen, cText );
CTR_Cipher( iv, 0, pText, pTextLen, cText );
BURN_AFTER_READ
}
/**
* @brief decrypt the input ciphertext using CCM-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
* @param iVec init-vector a.k.a nonce, containing CCM_NONCE_LEN bytes
* @param nonce a.k.a initialization vector with fixed size CCM_NONCE_LEN
* @param cText input cipher-text buffer
* @param cTextLen size of input buffer
* @param aData additional authentication data
@@ -1300,22 +1307,22 @@ void AES_CCM_encrypt( const uint8_t* key, const uint8_t* iVec,
* @param pText plain-text output buffer
* @return whether message authentication was successful
*/
char AES_CCM_decrypt( const uint8_t* key, const uint8_t* iVec,
const uint8_t* cText, const size_T cTextLen,
const uint8_t* aData, const size_T aDataLen,
char AES_CCM_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 )
{
block_t tag, iv = { 14 - CCM_NONCE_LEN, 0 };
memcpy( iv + 1, iVec, CCM_NONCE_LEN );
block_t iv = { 14 - CCM_NONCE_LEN, 0 };
memcpy( iv + 1, nonce, CCM_NONCE_LEN );
iv[sizeof iv - 1] = 1;
AES_SetKey( key );
CTR_Cipher( iv, ~0, cText, cTextLen, pText );
CCM_GetTag( iv, pText, aData, cTextLen, aDataLen, tag );
BURN_AFTER_READ
CTR_Cipher( iv, 0, cText, cTextLen, pText );
CCM_GetTag( iv, pText, aData, cTextLen, aDataLen, iv );
BURN_AFTER_READ /* tag is saved into iv! */
if (memcmp( tag, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
if (memcmp( iv, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
{ /* memset(pText, 0, Length); */
return AUTHENTICATION_FAILURE;
}
@@ -1332,7 +1339,7 @@ char AES_CCM_decrypt( const uint8_t* key, const uint8_t* iVec,
/** calculate the CMAC* of AAD unit(s), then plaintext, and synthesize the IV */
static void S2V( const uint8_t* key,
const uint8_t* aData, const uint8_t* pText,
const size_T aDataLen, const size_T pTextLen, block_t V )
const size_t aDataLen, const size_t pTextLen, block_t V )
{
block_t T = { 0 }, D = { 0 }, Q;
uint8_t r = pTextLen >= BLOCKSIZE ? BLOCKSIZE : pTextLen % BLOCKSIZE;
@@ -1341,7 +1348,7 @@ static void S2V( const uint8_t* key,
GetSubkeys( key, 0, D, Q );
Cmac( D, Q, T, sizeof T, T ); /* T_0 = CMAC(zero block) */
if (aDataLen) /* process each ADATA unit */
{ /* ..the same was as this: */
{ /* ..the same way as this: */
doubleGf128B( T );
Cmac( D, Q, aData, aDataLen, V ); /* C_A = CMAC(ADATA) */
xorBlock( V, T ); /* T_1 = double(T_0) ^ C_A */
@@ -1369,8 +1376,8 @@ static void S2V( const uint8_t* key,
* @param cText encrypted cipher-text buffer
*/
void AES_SIV_encrypt( const uint8_t* keys,
const uint8_t* pText, const size_T pTextLen,
const uint8_t* aData, const size_T aDataLen,
const uint8_t* pText, const size_t pTextLen,
const uint8_t* aData, const size_t aDataLen,
block_t iv, uint8_t* cText )
{
block_t IV = { 0 };
@@ -1379,7 +1386,7 @@ void AES_SIV_encrypt( const uint8_t* keys,
IV[8] &= 0x7F; IV[12] &= 0x7F;
AES_SetKey( keys + KEYSIZE );
CTR_Cipher( IV, ~0, pText, pTextLen, cText );
CTR_Cipher( IV, 0, pText, pTextLen, cText );
BURN_AFTER_READ
}
@@ -1395,8 +1402,8 @@ void AES_SIV_encrypt( const uint8_t* keys,
* @return whether synthesized I.V. matched the provided one
*/
char AES_SIV_decrypt( const uint8_t* keys,
const uint8_t* cText, const size_T cTextLen,
const uint8_t* aData, const size_T aDataLen,
const uint8_t* cText, const size_t cTextLen,
const uint8_t* aData, const size_t aDataLen,
const block_t iv, uint8_t* pText )
{
block_t IV;
@@ -1404,7 +1411,7 @@ char AES_SIV_decrypt( const uint8_t* keys,
memcpy( IV, iv, sizeof IV );
IV[8] &= 0x7F; IV[12] &= 0x7F;
CTR_Cipher( IV, ~0, cText, cTextLen, pText );
CTR_Cipher( IV, 0, cText, cTextLen, pText );
memset( IV, 0, sizeof IV );
S2V( keys, aData, pText, aDataLen, cTextLen, IV );
BURN_AFTER_READ
@@ -1423,12 +1430,12 @@ char AES_SIV_decrypt( const uint8_t* keys,
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(EAX)
/** this function calculates the OMAC hash of a data array using D (Ld) and Q */
/** this function calculates the OMAC hash of a data array using D (K1) and Q */
static void Omac( const uint8_t t, const block_t D, const block_t Q,
const void* data, const size_T dataSize, block_t mac )
const void* data, const size_t dataSize, block_t mac )
{
#if EAXP
if (dataSize == 0) return;
if (dataSize == 0 && t) return; /* ignore null ciphertext */
memcpy( mac, t ? Q : D, BLOCKSIZE );
#else
block_t M = { 0 };
@@ -1448,44 +1455,44 @@ static void Omac( const uint8_t t, const block_t D, const block_t Q,
* @param nonce a.k.a init-vector with EAX_NONCE_LEN bytes if not EAX'
* @param pText input plain-text buffer
* @param pTextLen size of input buffer
* @param nonceLen size of the nonce byte array; MUST be non-zero in EAX'
* @param nonceLen size of the nonce byte array; should be non-zero in EAX'
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
* @param cText encrypted cipher-text buffer
* @param auTag authentication tag; 16 bytes in EAX or 4 bytes in EAX'
*/
void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t* pText, const size_T pTextLen,
const uint8_t* pText, const size_t pTextLen,
#if EAXP
const size_T nonceLen,
const size_t nonceLen,
#else
const uint8_t* aData, const size_T aDataLen,
const uint8_t* aData, const size_t aDataLen,
#endif
uint8_t* cText, uint8_t* auTag )
{
block_t mac, tag = { 0 }, Ld = { 0 }, Lq;
GetSubkeys( key, EAXP, Ld, Lq );
block_t mac, tag = { 0 }, D = { 0 }, K2;
GetSubkeys( key, EAXP, D, K2 );
#if EAXP
Omac( 0, Ld, Lq, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
Omac( 0, D, K2, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
memcpy( auTag, mac + 12, 4 );
mac[12] &= 0x7F; /* clear 2 bits to get N' */
mac[14] &= 0x7F;
CTR_Cipher( mac, ~0, pText, pTextLen, cText );
CTR_Cipher( mac, 0, pText, pTextLen, cText );
Omac( 2, Ld, Lq, cText, pTextLen, tag ); /* C' = CMAC'( ciphertext ) */
for (*Ld = 0; *Ld < 4; ++*Ld) /* using Ld[0] as counter! */
Omac( 2, D, K2, cText, pTextLen, tag ); /* C' = CMAC'( ciphertext ) */
for (*D = 0; *D < 4; ++*D) /* using D[0] as counter! */
{
auTag[*Ld] ^= tag[12 + *Ld]; /* last 4 bytes of C' ^ N' */
auTag[*D] ^= tag[12 + *D]; /* last 4 bytes of C' ^ N' */
}
#else
Omac( 0, Ld, Lq, nonce, EAX_NONCE_LEN, mac );
Omac( 1, Ld, Lq, aData, aDataLen, tag ); /* H = OMAC(1; adata) */
xorBlock( mac, tag ); /* N = OMAC(0; nonce) */
Omac( 0, D, K2, nonce, EAX_NONCE_LEN, mac ); /* N = OMAC(0; nonce) */
Omac( 1, D, K2, aData, aDataLen, tag ); /* H = OMAC(1; adata) */
xorBlock( mac, tag );
memcpy( auTag, tag, sizeof tag );
CTR_Cipher( mac, ~0, pText, pTextLen, cText );
CTR_Cipher( mac, 0, pText, pTextLen, cText );
Omac( 2, Ld, Lq, cText, pTextLen, mac ); /* C = OMAC(2; ciphertext) */
Omac( 2, D, K2, cText, pTextLen, mac ); /* C = OMAC(2; ciphertext) */
xorBlock( mac, auTag ); /* tag = N ^ H ^ C */
#endif
BURN_AFTER_READ
@@ -1497,7 +1504,7 @@ void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
* @param nonce a.k.a init-vector with EAX_NONCE_LEN bytes if not EAX'
* @param cText input cipher-text buffer; +4 bytes tag at the end in EAX'
* @param cTextLen size of input buffer; excluding added 4 bytes in EAX'
* @param nonceLen size of the nonce byte array; MUST be non-zero in EAX'
* @param nonceLen size of the nonce byte array; should be non-zero in EAX'
* @param aData additional authentication data; ignored in EAX'
* @param aDataLen size of additional authentication data
* @param auTag message authentication tag; ignored in EAX'
@@ -1506,32 +1513,32 @@ void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
* @return whether message authentication was successful
*/
char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t* cText, const size_T cTextLen,
const uint8_t* cText, const size_t cTextLen,
#if EAXP
const size_T nonceLen,
const size_t nonceLen,
#else
const uint8_t* aData, const size_T aDataLen,
const uint8_t* aData, const size_t aDataLen,
const uint8_t* auTag, const uint8_t tagSize,
#endif
uint8_t* pText )
{
block_t mac, tag = { 0 }, Ld = { 0 }, Lq;
GetSubkeys( key, EAXP, Ld, Lq );
Omac( 2, Ld, Lq, cText, cTextLen, tag ); /* C = OMAC(2; ciphertext) */
block_t mac, tag = { 0 }, D = { 0 }, K2;
GetSubkeys( key, EAXP, D, K2 );
Omac( 2, D, K2, cText, cTextLen, tag ); /* C = OMAC(2; ciphertext) */
#if EAXP
Omac( 0, Ld, Lq, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
for (*Lq = *Ld = 0; *Ld < 4; ++*Ld) /* authenticate/compare tags */
Omac( 0, D, K2, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
for (*K2 = *D = 0; *D < 4; ++*D) /* authenticate/compare tags */
{
*Lq |= tag[12 + *Ld] ^ mac[12 + *Ld] ^ cText[cTextLen + *Ld];
*K2 |= cText[cTextLen + *D] ^ tag[12 + *D] ^ mac[12 + *D];
}
mac[12] &= 0x7F;
mac[14] &= 0x7F; /* clear 2 bits to get N' */
if (*Lq != 0)
mac[12] &= 0x7F; /* clear 2 bits to get N' */
mac[14] &= 0x7F;
if (*K2 != 0) /* result of tag comparison */
#else
Omac( 1, Ld, Lq, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
Omac( 1, D, K2, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
xorBlock( mac, tag ); /* N = OMAC(0; nonce) */
Omac( 0, Ld, Lq, nonce, EAX_NONCE_LEN, mac );
Omac( 0, D, K2, nonce, EAX_NONCE_LEN, mac );
xorBlock( mac, tag ); /* tag = N ^ H ^ C */
if (memcmp( tag, auTag, tagSize ) != 0) /* authenticate then decrypt */
@@ -1540,7 +1547,7 @@ char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
BURN_AFTER_READ
return AUTHENTICATION_FAILURE;
}
CTR_Cipher( mac, ~0, cText, cTextLen, pText );
CTR_Cipher( mac, 0, cText, cTextLen, pText );
BURN_AFTER_READ
return ENDED_IN_SUCCESS;
@@ -1564,12 +1571,12 @@ char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
* @param output encrypted/decrypted data
*/
static void OCB_Cipher( const uint8_t* nonce, fmix_t cipher,
const uint8_t* input, const size_T dataSize,
const uint8_t* input, const size_t dataSize,
block_t Ls, block_t Ld, block_t Del, uint8_t* output )
{
uint8_t Kt[2 * BLOCKSIZE] = { OCB_TAG_LEN << 4 & 0xFE, 0, 0, 1 };
uint8_t r, *y = output;
count_T i, n;
count_t i, n;
memcpy( output, input, dataSize ); /* copy input data to output */
n = nonce[11] % 64 >> 3;
@@ -1588,11 +1595,10 @@ static void OCB_Cipher( const uint8_t* nonce, fmix_t cipher,
r = dataSize % BLOCKSIZE;
i = 0;
memset( Kt + BLOCKSIZE, 0 , BLOCKSIZE ); /* processed nonce is Δ_0 */
RijndaelEncrypt( Kt + BLOCKSIZE, Ls ); /* L_* = Enc(zero block) */
RijndaelEncrypt( Ls, Ls ); /* L_* = Enc(zero block) */
memcpy( Ld, Ls, BLOCKSIZE );
doubleGf128B( Ld ); /* L_$ = double(L_*) */
if (n == 0)
if (n == 0) /* processed nonce is Δ_0 */
{
memcpy( Del, Kt, BLOCKSIZE ); /* initialize Δ_0 */
}
@@ -1618,15 +1624,15 @@ static void OCB_Cipher( const uint8_t* nonce, fmix_t cipher,
static void OCB_GetTag( const block_t Ds,
const block_t Ls, const block_t Ld,
const uint8_t* pText, const uint8_t* aData,
const size_T pTextLen, const size_T aDataLen,
const size_t pTextLen, const size_t aDataLen,
block_t tag )
{
block_t S = { 0 }; /* checksum, i.e. ... */
count_T i = pTextLen % BLOCKSIZE, n;
const uint8_t *x = aData;
count_t i = pTextLen % BLOCKSIZE, n;
block_t S = { 0 }; /* checksum, i.e. ... */
MAC( pText, pTextLen, NULL, &nop, S ); /* ..xor of all plaintext */
xorThenMix( Ds, BLOCKSIZE, Ld, &xorBlock, S );
xorThenMix( Ds, sizeof S, Ld, &xorBlock, S );
if (i) S[i] ^= 0x80; /* pad if partial block */
RijndaelEncrypt( S, tag ); /* Tag0 = Enc(L_$ ^ Δ_* ^ S) */
@@ -1670,11 +1676,11 @@ static void OCB_GetTag( const block_t Ds,
* @param auTag message authentication tag. buffer must be 16-bytes long
*/
void AES_OCB_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,
const uint8_t* pText, const size_t pTextLen,
const uint8_t* aData, const size_t aDataLen,
uint8_t* cText, block_t auTag )
{
block_t Ls, Ld, delta;
block_t Ls = { 0 }, Ld, delta;
AES_SetKey( key );
OCB_Cipher( nonce, &RijndaelEncrypt, pText, pTextLen, Ls, Ld, delta, cText );
OCB_GetTag( delta, Ls, Ld, pText, aData, pTextLen, aDataLen, auTag );
@@ -1695,18 +1701,18 @@ void AES_OCB_encrypt( const uint8_t* key, const uint8_t* nonce,
* @return whether message authentication was successful
*/
char AES_OCB_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* cText, const size_t cTextLen,
const uint8_t* aData, const size_t aDataLen,
const uint8_t* auTag, const uint8_t tagSize,
uint8_t* pText )
{
block_t Ls, Ld, delta, tag;
block_t Ls = { 0 }, Ld, delta;
AES_SetKey( key );
OCB_Cipher( nonce, &RijndaelDecrypt, cText, cTextLen, Ls, Ld, delta, pText );
OCB_GetTag( delta, Ls, Ld, pText, aData, cTextLen, aDataLen, tag );
BURN_AFTER_READ
OCB_GetTag( delta, Ls, Ld, pText, aData, cTextLen, aDataLen, delta );
BURN_AFTER_READ /* saved the tag into delta! */
if (memcmp( tag, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
if (memcmp( delta, auTag, tagSize ) != 0) /* sabotage results ↓ maybe? */
{ /* memset(pText, 0, Length); */
return AUTHENTICATION_FAILURE;
}
@@ -1716,10 +1722,50 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
/**--------------------------------------------------------------------------**\
AES-GCM-SIV (Galois counter mode with synthetic i.v): main functions
SIV-GCM-AES (Galois counter mode with synthetic i.v): main functions
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(GCM_SIV)
/**
* @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 pText input plain-text buffer
* @param pTextLen size of input buffer
* @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
*/
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 )
{
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 input buffer
* @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
*/
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
return ENDED_IN_SUCCESS;
}
#endif /* GCM-SIV */
@@ -1747,10 +1793,10 @@ static void xorWith( uint8_t* block, uint8_t p, size_t t )
* @param wrapped wrapped secret. note: size of output = secretLen + 8
*/
void AES_KEY_wrap( const uint8_t* kek,
const uint8_t* secret, const size_T secretLen, uint8_t* wrapped )
const uint8_t* secret, const size_t secretLen, uint8_t* wrapped )
{
uint8_t A[16], *r, i;
count_T j, nb = secretLen / 8; /* number of blocks */
count_t j, nb = secretLen / 8; /* number of blocks */
memset( A, 0xA6, 8 ); /* initialization vector */
memcpy( wrapped + 8, secret, secretLen );
@@ -1782,10 +1828,10 @@ void AES_KEY_wrap( const uint8_t* kek,
* @return a value indicating whether decryption was successful
*/
char AES_KEY_unwrap( const uint8_t* kek,
const uint8_t* wrapped, const size_T wrapLen, uint8_t* secret )
const uint8_t* wrapped, const size_t wrapLen, uint8_t* secret )
{
uint8_t A[16], *r, i;
count_T j, nb = wrapLen / 8 - 1; /* number of secret blocks */
count_t j, nb = wrapLen / 8 - 1; /* number of secret blocks */
memcpy( A, wrapped, 8 ); /* authentication vector */
memcpy( secret, wrapped + 8, wrapLen - 8 );

View File

@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.h
Author : polfosol
Version : 8.7.0.0
Version : 8.9.0.0
Copyright : copyright © 2022 - polfosol
Description : μAES ™ is a minimalist all-in-one library for AES encryption
==============================================================================
@@ -38,7 +38,7 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
#define GCM 1 /* Galois/counter mode with GMAC (NIST SP 800-38D) */
#define EAX 1 /* encrypt-authenticate-translate (ANSI C12.22) */
#define SIV 1 /* synthetic initialization vector (RFC-5297) */
#define GCM_SIV 0 /* nonce misuse-resistant AES-GCM (RFC-8452) */
#define GCM_SIV 1 /* nonce misuse-resistant AES-GCM (RFC-8452) */
#endif
#if CBC
@@ -54,7 +54,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
#if SIV || EAX
#if EAX || SIV
#define CMAC 1 /* message authentication code (NIST SP 800-38B) */
#endif
@@ -78,26 +78,26 @@ REFER TO THE BOTTOM OF THIS DOCUMENT FOR SOME EXPLANATIONS ABOUT THESE MACROS:
#define AES_PADDING 0 /* other valid values: (1) PKCS#7 (2) IEC7816-4 */
#endif
#if CTR
#define INIT_CTR_VALUE 1 /* if set to ~0 a full block I.V is used in CTR_NA */
#define CTR_IV_LENGTH 12 /* changing this value may break GCM mode as well. */
#if CTR_NA
#define CTR_STARTVALUE 1 /* recommended value according to the RFC-3686. */
#define CTR_IV_LENGTH 12 /* for using the last 32 bits as counter */
#endif
#if CCM
#define CCM_NONCE_LEN 11 /* for 32-bit count (since one byte is reserved). */
#define CCM_TAG_LEN 16
#endif
#if GCM
#define GCM_NONCE_LEN 12 /* RECOMMENDED. please don't change, or see below */
#endif
#if OCB
#define OCB_TAG_LEN 16 /* again, please see the bottom of this document! */
#define GCM_NONCE_LEN 12 /* RECOMMENDED. but other values are supported. */
#endif
#if EAX && !EAXP
#define EAX_NONCE_LEN 16 /* practically no limit; can be arbitrarily large */
#endif
#if CCM
#define CCM_NONCE_LEN 11 /* for 32-bit count (since one byte is reserved). */
#define CCM_TAG_LEN 16
#if OCB
#define OCB_TAG_LEN 16 /* again, please see the bottom of this document! */
#endif
/**----------------------------------------------------------------------------
@@ -109,16 +109,16 @@ If the length of the input cipher/plain text is 'always' less than 4KB, you can
#define SMALL_CIPHER 0
#include <stddef.h>
typedef unsigned char uint8_t; /* C89 doesn't have <stdint.h> */
#if SMALL_CIPHER
typedef unsigned short size_T;
typedef unsigned char count_T;
typedef unsigned char count_t;
#else
typedef size_t size_T;
typedef size_t count_T;
typedef size_t count_t;
#endif
typedef unsigned char uint8_T;
#define uint8_t uint8_T /* C89 doesn't have <stdint.h> */
#ifdef __cplusplus
extern "C" {
#endif
@@ -139,12 +139,12 @@ Main functions for ECB-AES block ciphering
#if ECB
void AES_ECB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
char AES_ECB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* ECB */
@@ -155,13 +155,13 @@ Main functions for CBC-AES block ciphering
void AES_CBC_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
char AES_CBC_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* CBC */
@@ -172,13 +172,13 @@ Main functions for CFB-AES block ciphering
void AES_CFB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
void AES_CFB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* CFB */
@@ -189,13 +189,13 @@ Main functions for OFB-AES block ciphering
void AES_OFB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
void AES_OFB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iVec, /* initialization vector */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* OFB */
@@ -206,13 +206,13 @@ Main functions for XTS-AES block ciphering
char AES_XTS_encrypt( const uint8_t* keys, /* encryption key pair */
const uint8_t* unitId, /* tweak value (sector ID) */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
char AES_XTS_decrypt( const uint8_t* keys, /* decryption key pair */
const uint8_t* unitId, /* tweak value (sector ID) */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* XTS */
@@ -223,43 +223,33 @@ Main functions for CTR-AES block ciphering
void AES_CTR_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iv, /* initialization vector/ nonce */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
uint8_t* cText ); /* cipher-text buffer */
void AES_CTR_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iv, /* initialization vector/ nonce */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
uint8_t* pText ); /* decrypted plain-text */
#endif /* CTR */
/**----------------------------------------------------------------------------
Main function for AES-128 cipher-based message authentication code
-----------------------------------------------------------------------------*/
#if CMAC
void AES_CMAC( const uint8_t* key, /* 128-bit encryption key */
const void* data, /* input data buffer */
const size_T dataSize, /* size of data in bytes */
uint8_t* mac ); /* calculated CMAC hash */
#endif
/**----------------------------------------------------------------------------
Main functions for SIV-AES block ciphering
-----------------------------------------------------------------------------*/
#if SIV
void AES_SIV_encrypt( const uint8_t* keys, /* encryption key pair */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input 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 */
const size_t aDataLen, /* size of authentication data */
uint8_t* iv, /* synthesized init-vector */
uint8_t* cText ); /* cipher-text buffer */
char AES_SIV_decrypt( const uint8_t* keys, /* decryption key pair */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input 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 size_t aDataLen, /* size of authentication data */
const uint8_t* iv, /* provided init-vector */
uint8_t* pText ); /* decrypted plain-text */
#endif /* SIV */
@@ -269,20 +259,20 @@ Main functions for GCM-AES block ciphering
-----------------------------------------------------------------------------*/
#if GCM
void AES_GCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iv, /* initialization vector/ nonce */
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 size_t pTextLen, /* length of input plain text */
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* cText, /* cipher-text buffer */
uint8_t* auTag ); /* message authentication tag */
char AES_GCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iv, /* initialization vector/ nonce */
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 size_t cTextLen, /* length of input cipher-text */
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of 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 */
@@ -292,10 +282,23 @@ char AES_GCM_decrypt( const uint8_t* key, /* decryption key */
Main functions for GCM-SIV-AES block ciphering
-----------------------------------------------------------------------------*/
#if GCM_SIV
void GCM_SIV_encrypt( const uint8_t* keys, /* encryption key pair */
);
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* keys, /* decryption key pair */
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 */
@@ -304,20 +307,20 @@ Main functions for CCM-AES block ciphering
-----------------------------------------------------------------------------*/
#if CCM
void AES_CCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* iVec, /* initialization vector/ nonce */
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 size_t pTextLen, /* length of input plain text */
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* cText, /* cipher-text buffer */
uint8_t* auTag ); /* message authentication tag */
char AES_CCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* iVec, /* initialization vector/ nonce */
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 size_t cTextLen, /* length of input cipher-text */
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of 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 */
@@ -330,18 +333,18 @@ Main functions for OCB-AES block ciphering
void AES_OCB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* 96-bit initialization vector */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input 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 */
const size_t aDataLen, /* size of authentication data */
uint8_t* cText, /* cipher-text buffer */
uint8_t* auTag ); /* message authentication tag */
char AES_OCB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* 96-bit initialization vector */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input 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 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 */
@@ -354,12 +357,12 @@ Main functions for EAX-AES mode; more info at the bottom of this document.
void AES_EAX_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* initialization vector */
const uint8_t* pText, /* plain text */
const size_T pTextLen, /* length of input plain text */
const size_t pTextLen, /* length of input plain text */
#if EAXP
const size_T nonceLen, /* size of provided nonce */
#else
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of authentication data */
const size_t aDataLen, /* size of authentication data */
#endif
uint8_t* cText, /* cipher-text buffer */
uint8_t* auTag ); /* message authentication tag */
@@ -367,12 +370,12 @@ void AES_EAX_encrypt( const uint8_t* key, /* encryption key */
char AES_EAX_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* initialization vector */
const uint8_t* cText, /* cipher text */
const size_T cTextLen, /* length of input cipher-text */
const size_t cTextLen, /* length of input cipher-text */
#if EAXP
const size_T nonceLen, /* size of provided nonce */
#else
const uint8_t* aData, /* added authentication data */
const size_T aDataLen, /* size of 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) */
#endif
@@ -385,15 +388,24 @@ Main functions for AES key-wrapping; more info at the bottom of this page.
#if KWA
void AES_KEY_wrap( const uint8_t* kek, /* key encryption key */
const uint8_t* secret, /* input secret to be wrapped */
const size_T secretLen, /* size of input */
const size_t secretLen, /* size of input */
uint8_t* wrapped ); /* key-wrapped output */
char AES_KEY_unwrap( const uint8_t* kek, /* key encryption key */
const uint8_t* wrapped, /* key-wrapped secret */
const size_T wrapLen, /* size of input (secretLen +8) */
const size_t wrapLen, /* size of input (secretLen +8) */
uint8_t* secret ); /* buffer for unwrapped key */
#endif /* KWA */
/**----------------------------------------------------------------------------
Main function for AES cipher-based message authentication code
-----------------------------------------------------------------------------*/
#if CMAC
void AES_CMAC( const uint8_t* key, /* encryption/cipher key */
const void* data, /* input data buffer */
const size_t dataSize, /* size of data in bytes */
uint8_t* mac ); /* calculated CMAC hash */
#endif
#ifdef __cplusplus
}
@@ -433,22 +445,15 @@ These constants should be defined here for external references:
is a part of the I.V, which itself can either be a full block or a partial
one. In CBC/CFB/OFB modes, the provided I.V must be a full block. In pure
CTR mode (CTR_NA) you can either provide a 96-bit I.V and let the count
start at INIT_CTR_VALUE, or use a full block IV. Anyhow, according to the
RFC-3686, the counter value must start at 1.
start at CTR_STARTVALUE, or use a full block IV.
* In AEAD modes, the size of nonce and tag might be a parameter of the algorithm
such that changing them affect the results. In CCM, the nonce/I.V size may
vary from 8 to 13 bytes. Also the tag size is an EVEN number between 4..16.
In OCB, only the tag size is a parameter between 0..16 bytes. The GCM/EAX
modes support arbitrary sizes for nonce. Note that the 'calculated' tag size
is always 16 bytes which can later be truncated to the desired value. So in
encryption functions, the provided authTag buffer must be 16 bytes long.
* As stated above, GCM mode supports arbitrary nonce length. But if you want to
use the functions of this library for such nonces, first you will need to
pre-process the nonce and calculate J_0. Then use J_0 as the provided IV
parameter for those functions. The process of calculating J_0 is the same as
digesting aData or cText, i.e. J_0 = GHash(nonce; GCM_NONCE_LEN)
such that changing them affect the results. The GCM/EAX modes support
arbitrary sizes for nonce. In CCM, the nonce length may vary from 8 to 13
bytes. Also the tag size is an EVEN number between 4..16. In OCB, only the
tag size is a parameter between 0..16 bytes. Note that the 'calculated' tag
size is always 16 bytes which can later be truncated to desired values. So
in encryption functions, the provided authTag buffer must be 16 bytes long.
* For the EAX mode of operation, the IEEE-1703 standard defines EAX' which is a
modified version that combines AAD and nonce. Also the tag size is fixed to

View File

@@ -1,3 +1,13 @@
/*
==============================================================================
Name : CCMtest.c
Author : polfosol
Version : 1.5.0.0
Copyright : copyright © 2022 - polfosol
Description : illustrating how the NIST's vectors for AES-CCM mode are used
==============================================================================
*/
#include <stdio.h>
#include <string.h>
#include "../micro_aes.h"
@@ -59,9 +69,9 @@ int main()
{
const char *linehdr[] = { "Key = ", "Nonce = ", "Adata = ", "Payload = ", "CT = " };
char buffer[0x800], *value = "";
size_t i, n = 0, pass = 0, df = 0, ef = 0, skip = 0, sp = 0, sc = 0, sa = 0;
uint8_t key[16], iv[16], p[64], c[80], a[64];
FILE *fp, *fs, *ferr;
int i, n = 0, pass = 0, df = 0, ef = 0, skip = 0;
uint8_t key[16], iv[16], p[64], c[80], a[64], sp = 0, sc = 0, sa = 0;
fp = fopen(TESTFILEPATH, "r");
fs = fopen("passed.log", "w");

File diff suppressed because one or more lines are too long

128
testvectors/CMACtest.c Normal file
View File

@@ -0,0 +1,128 @@
/*
==============================================================================
Name : CMACtest.c
Author : polfosol
Version : 1.1.0.0
Copyright : copyright © 2022 - polfosol
Description : illustrating how the NIST's vectors for AES-CMAC are used
==============================================================================
*/
#include <stdio.h>
#include <string.h>
#include "../micro_aes.h"
#define TESTFILEPATH "CMACGenAES128.rsp"
static void str2bytes(const char* str, uint8_t* bytes)
#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
{
size_t i, j;
for (i = 0, j = ~0; str[i]; ++i)
{
if (str[i] < '0' || str[i] > 'f') continue;
if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
else bytes[j / 2] |= char2num(str[i]);
}
}
static void bytes2str(const uint8_t* bytes, char* str, size_t len)
#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
{
size_t i, j;
for (i = 0, j = 0; i < len; ++i)
{
str[j++] = num2char(bytes[i] >> 4);
str[j++] = num2char(bytes[i] & 15);
}
str[j] = 0;
}
static int ciphertest(uint8_t* key, uint8_t* d, uint8_t* m, size_t ds, size_t ms, char* r)
{
char sk[40], smac[40], msg[30];
uint8_t tmp[32], t = 0;
sprintf(msg, "%s", "success");
AES_CMAC(key, d, ds, tmp);
t = memcmp(m, tmp, ms);
if (t) sprintf(msg, "%s", "failed");
bytes2str(key, sk, 16);
bytes2str(m, smac, ms);
sprintf(r, "%s\nK: %s\nmac: %s\n", msg, sk, smac);
return t;
}
int main()
{
const char *linehdr[] = { "Key = ", "Msg = ", "Mac = " };
char buffer[0x20100], *value = "";
size_t i, n = 0, pass = 0, nf = 0, sd = 0, sm = 0;
uint8_t key[32], d[0x10100], m[32];
FILE *fp, *fs, *ferr;
fp = fopen(TESTFILEPATH, "r");
fs = fopen("passed.log", "w");
ferr = fopen("failed.log", "w");
if (fp == NULL)
{
printf("File not found: %s\n", TESTFILEPATH);
return 1;
}
if (!fs || !ferr) return 1;
while (fgets(buffer, sizeof buffer, fp) != NULL)
{
buffer[strcspn(buffer, "\n")] = 0;
if (strlen(buffer) < 4 || !strcspn(buffer, "=")) continue;
for (i = 0; i < 3; i++)
{
if (strncmp(buffer, linehdr[i], strlen(linehdr[i])) == 0)
{
value = strrchr(buffer, ' ');
break;
}
}
switch (i)
{
case 0:
str2bytes(value + 1, key);
break;
case 1:
sd = strlen(value + 1) / 2;
str2bytes(value + 1, d);
if (sd == 1 && d[0] == 0) --sd;
++n;
break;
case 2:
sm = strlen(value + 1) / 2;
str2bytes(value + 1, m);
++n;
break;
default:
continue;
}
if (n == 2)
{
n = ciphertest(key, d, m, sd, sm, buffer);
fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
if (n == 0) ++pass;
else
{
++nf;
n = 0;
}
}
}
printf ("test cases: %d\nsuccessful: %d\nfailed: %d\n", pass + nf, pass, nf);
fclose(fp); fclose(fs); fclose(ferr);
if (nf == 0)
{
remove("passed.log"); remove("failed.log");
}
return 0;
}

46
testvectors/CMACtest.cbp Normal file
View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="CMACtest" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin/Debug/testvecs" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-pedantic" />
<Add option="-g" />
<Add option="-ansi" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin/Release/testvecs" prefix_auto="1" extension_auto="1" />
<Option object_output="obj/Release/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-pedantic" />
<Add option="-ansi" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Unit filename="../micro_aes.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../micro_aes.h" />
<Unit filename="CMACtest.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

View File

@@ -1,3 +1,13 @@
/*
==============================================================================
Name : GCMtest.c
Author : polfosol
Version : 1.5.0.0
Copyright : copyright © 2022 - polfosol
Description : illustrating how the NIST's vectors for AES-GCM mode are used
==============================================================================
*/
#include <stdio.h>
#include <string.h>
#include "../micro_aes.h"
@@ -31,7 +41,7 @@ static void bytes2str(const uint8_t* bytes, char* str, size_t len)
static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t* c,
uint8_t np, uint8_t na, uint8_t nt, char* r)
{
char sk[40], si[40], sp[0x100], sc[0x100], sa[0x100], msg[30];
char sk[40], si[GCM_NONCE_LEN*2+6], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[128], t = 0;
sprintf(msg, "%s", "success");
@@ -60,9 +70,9 @@ int main()
{
const char *linehdr[] = { "Key = ", "IV = ", "AAD = ", "PT = ", "CT = ", "Tag = " };
char buffer[0x800], *value = "";
size_t i, n = 0, pass = 0, df = 0, ef = 0, skip = 0, sp = 0, st = 0, sa = 0;
uint8_t key[16], iv[GCM_NONCE_LEN], p[96], c[112], a[96], t[16];
FILE *fp, *fs, *ferr;
int i, n = 0, pass = 0, df = 0, ef = 0, skip = 0;
uint8_t key[16], iv[16], p[96], c[112], a[96], t[16], sp = 0, st = 0, sa = 0;
fp = fopen(TESTFILEPATH, "r");
fs = fopen("passed.log", "w");

7
testvectors/README.md Normal file
View File

@@ -0,0 +1,7 @@
### Testing µAES
---
This folder contains some of the NIST's official [CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes) test vectors. The `*.rsp` files are courtesy of the NIST. Some sample codes are provided alongside them to illustrate how they are used.
Also in the `main.c` file of parent directory, you will find some other test vectors that are either generated by the [Crypto++®](https://www.cryptopp.com) library or taken from various online documents. Please let me know if you faced any issues in verifying them.
Needless to say, the µAES library has been successfully tested against all [CAVP's vectors](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes).

View File

@@ -1,3 +1,13 @@
/*
==============================================================================
Name : XTStest.c
Author : polfosol
Version : 2.0.0.0
Copyright : copyright © 2022 - polfosol
Description : illustrating how the NIST's vectors for AES-XTS mode are used
==============================================================================
*/
#include <stdio.h>
#include <string.h>
#include "../micro_aes.h"
@@ -60,8 +70,8 @@ int main()
{
const char *linehdr[] = { "Key = ", "i = ", "PT = ", "CT = " };
char buffer[0x800], *value = "";
int i, n = 0, pass = 0, df = 0, ef = 0;
uint8_t key[32], iv[16], p[32], c[32], s = 0;
size_t i, n = 0, pass = 0, df = 0, ef = 0, s = 0;
uint8_t key[32], iv[16], p[32], c[32];
FILE *fp, *fs, *ferr;
fp = fopen(TESTFILEPATH, "r");