diff --git a/README.md b/README.md
index 036c8c2..35e1215 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,10 @@
**A minimalist ANSI-C compatible API for the AES encryption and block cipher modes**.
-[](../../ "µAES")  [](../../../../user-attachments/files/18098067/micro_aes-v1.9.3.zip "µAES-v1.9.3.zip") [](https://opensource.org/licenses/Apache-2.0)
+[](../../ "µAES")
+
+[](../../../../user-attachments/files/22698833/micro_aes-v1.11.0.zip "µAES-v1.11.0.zip")
+[](https://opensource.org/licenses/Apache-2.0)
This is a highly flexible, small and portable implementation of most of the AES related algorithms.
@@ -31,7 +34,7 @@ and furthermore, authentication APIs for
* Clear and readable code — written in a layman-friendly way with lots of comments to clarify its purpose. Also the code styling is a bit different, and IMHO more eye-catching, than what you might see in other implementations.
-* Flexible — most features are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These [macros](micro_aes.h#L546) are defined in the header file and comments are added for each of them to explain what they represent. *Please read [those comments](micro_aes.h#L483) carefully before using the code*.
+* Flexible — most features are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These [macros](micro_aes.h#L544) are defined in the header file and comments are added for each of them to explain what they represent. *Please read [those comments](micro_aes.h#L481) carefully before using the code*.
* Lightweight — the API has very little memory footprint and compiled code size. The amount of RAM used by the functions doesn't exceed a few hundred bytes in most extreme cases. Moreover, the ROM space of µAES is optimized as much as possible.
@@ -53,7 +56,7 @@ and furthermore, authentication APIs for
* Portable — µAES is fully compliant with the ANSI-C or C89 standard which, combined with its small size and independence from external libraries, makes it a competent candidate for embedded systems and mini applications.
- You can even compile it with [Tiny C Compiler](https://bellard.org/tcc/):
+ You can even [compile it](../../../../user-attachments/files/21704976/TCPROJ.zip "instructions and prerequisites") with a vintage [Borland Turbo C](https://hackaday.com/2023/04/08/revisiting-borland-turbo-c-and-c/) or a teeny [tiny C compiler](https://bellard.org/tcc/):
```
path/to/tcc.exe -c micro_aes.c
path/to/tcc.exe micro_aes.c -run main.c
diff --git a/main.c b/main.c
index 7e60830..3266c66 100644
--- a/main.c
+++ b/main.c
@@ -2,7 +2,7 @@
==============================================================================
Name : main.c
Author : polfosol
- Version : 10
+ Version : 11
Copyright : copyright © 2022 - polfosol
Description : test vectors for µAES ™ library, mostly generated by Crypto++ ®
==============================================================================
@@ -42,7 +42,7 @@ static const char
"3f9c56525efbe64a 876ad1d761d3fc93 59fb4f5b2354acd4 90",
*ofbcipher = "edab3105e673bc9e b9102539a9f457bc d28c8e4c92995f5c d9426926be1e775d"
"e22b8ce4d0278b18 181b8bec93b9726f 959aa5d701d46102 f0",
-#if CTR_IV_LENGTH == 16
+#if PRESET_COUNTER
*ctrcipher = "edab3105e673bc9e b9102539a9f457bc f2e2606dfa3f93c5 c51b910a89cddb67"
"191a118531ea0427 97626c9bfd370426 fdf3f59158bf7d4d 43",
#else
@@ -108,7 +108,7 @@ static void hex2bytes(const char* hex, uint8_t* bytes)
static void check(const char* method, void* result, const void* expected, size_t size)
{
int c = memcmp(expected, result, size);
- printf("AES-%d %s: %s\n", AES_KEY_SIZE * 8, method, c ? "FAILED :`(" : "PASSED!");
+ printf("AES-%d %s: %s\n", AES_KEYLENGTH * 8, method, c ? "FAILED :`(" : "PASSED!");
memset(result, 0xcc, TAGGED);
}
@@ -124,7 +124,7 @@ int main(void)
#if MICRO_RJNDL
hex2bytes(iVec, input + 48);
hex2bytes(secondKey, test);
- a = AES_KEY_SIZE == 16 ? key : input + (AES___ - 192) / 2;
+ a = AES_KEYLENGTH == 16 ? key : input + (AES_KEYLENGTH - 24) * 4;
AES_Cipher(test, 'E', authKey, output);
AES_Cipher(authKey, 'E', test, output + 16);
@@ -136,108 +136,108 @@ int main(void)
#endif
printf("%s %s Test results\n", __DATE__, __TIME__);
-#if ECB && AES_KEY_SIZE - 8 * AES_PADDING == 16
+#if ECB && AES___ == 64 * (AES_PADDING ^ 2)
hex2bytes(ecbcipher, test);
AES_ECB_encrypt(key, input, sp, output);
check("ECB encryption", output, test, sizeof input);
AES_ECB_decrypt(key, test, sizeof input, output);
check("ECB decryption", output, input, sp);
#endif
-#if CBC && AES_KEY_SIZE == 16
+#if CBC && AES___ == 128
hex2bytes(cbccipher, test);
AES_CBC_encrypt(key, iv, input, sp, output);
check("CBC encryption", output, test, CTS ? sp : sizeof input);
AES_CBC_decrypt(key, iv, test, CTS ? sp : sizeof input, output);
check("CBC decryption", output, input, sp);
#endif
-#if CFB && AES_KEY_SIZE == 16
+#if CFB && AES___ == 128
hex2bytes(cfbcipher, test);
AES_CFB_encrypt(key, iv, input, sp, output);
check("CFB encryption", output, test, sp);
AES_CFB_decrypt(key, iv, test, sp, output);
check("CFB decryption", output, input, sp);
#endif
-#if OFB && AES_KEY_SIZE == 16
+#if OFB && AES___ == 128
hex2bytes(ofbcipher, test);
AES_OFB_encrypt(key, iv, input, sp, output);
check("OFB encryption", output, test, sp);
AES_OFB_decrypt(key, iv, test, sp, output);
check("OFB decryption", output, input, sp);
#endif
-#if CTR_NA && AES_KEY_SIZE == 16
+#if CTR_NA && AES___ == 128
hex2bytes(ctrcipher, test);
AES_CTR_encrypt(key, iv, input, sp, output);
check("CTR encryption", output, test, sp);
AES_CTR_decrypt(key, iv, test, sp, output);
check("CTR decryption", output, input, sp);
#endif
-#if XTS && AES_KEY_SIZE != 24
+#if XTS && AES___ != 192
hex2bytes(xtscipher, test);
AES_XTS_encrypt(key, iv, input, sp, output);
check("XTS encryption", output, test, sp);
AES_XTS_decrypt(key, iv, test, sp, output);
check("XTS decryption", output, input, sp);
#endif
-#if CMAC && AES_KEY_SIZE == 16
+#if CMAC && AES___ == 128
hex2bytes(ptxt_cmac, test);
AES_CMAC(key, input, sp, output);
check("plaintext CMAC", output, test, 16);
#endif
-#if POLY1305 && AES_KEY_SIZE == 16
+#if POLY1305 && AES___ == 128
hex2bytes(poly_1305, test);
AES_Poly1305(key, iv, input, sp, output);
- check("Poly-1305 *mac", output, test, 16);
+ check("Poly1305 of PT", output, test, 16);
#endif
-#if GCM && AES_KEY_SIZE != 24
+#if GCM && AES___ != 192
hex2bytes(gcmcipher, test);
- AES_GCM_encrypt(key, iv, input, sp, a, sa, output, output + sp);
- check("GCM encryption", output, test, sp + 16);
- AES_GCM_decrypt(key, iv, test, sp, a, sa, 16, output);
+ AES_GCM_encrypt(key, iv, a, sa, input, sp, output);
+ check("GCM encryption", output, test, sp + GCM_TAG_LEN);
+ AES_GCM_decrypt(key, iv, a, sa, test, sp, output);
check("GCM decryption", output, input, sp);
#endif
-#if CCM && AES_KEY_SIZE == 16
+#if CCM && AES___ == 128
hex2bytes(ccmcipher, test);
- AES_CCM_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ AES_CCM_encrypt(key, iv, a, sa, input, sp, output);
check("CCM encryption", output, test, sp + CCM_TAG_LEN);
- *output ^= AES_CCM_decrypt(key, iv, test, sp, a, sa, CCM_TAG_LEN, output);
+ *output ^= AES_CCM_decrypt(key, iv, a, sa, test, sp, output);
check("CCM decryption", output, input, sp);
#endif
-#if OCB && AES_KEY_SIZE == 16
+#if OCB && AES___ == 128
hex2bytes(ocbcipher, test);
- AES_OCB_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ AES_OCB_encrypt(key, iv, a, sa, input, sp, output);
check("OCB encryption", output, test, sp + OCB_TAG_LEN);
- *output ^= AES_OCB_decrypt(key, iv, test, sp, a, sa, OCB_TAG_LEN, output);
+ *output ^= AES_OCB_decrypt(key, iv, a, sa, test, sp, output);
check("OCB decryption", output, input, sp);
#endif
-#if SIV && AES_KEY_SIZE == 16
+#if SIV && AES___ == 128
hex2bytes(sivcipher, test);
- AES_SIV_encrypt(key, input, sp, a, sa, output, output + 16);
+ AES_SIV_encrypt(key, a, sa, input, sp, output, output + 16);
check("SIV encryption", output, test, sp + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, output);
+ *output ^= AES_SIV_decrypt(key, test, a, sa, test + 16, sp, output);
check("SIV decryption", output, input, sp);
#endif
-#if GCM_SIV && AES_KEY_SIZE == 16
+#if GCM_SIV && AES___ == 128
hex2bytes(gsvcipher, test);
- GCM_SIV_encrypt(key, iv, input, sp, a, sa, output, output + sp);
- check("GCMSIV encrypt", output, test, sp + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, sp, a, sa, 16, output);
+ GCM_SIV_encrypt(key, iv, a, sa, input, sp, output);
+ check("GCMSIV encrypt", output, test, sp + SIVGCM_TAG_LEN);
+ *output ^= GCM_SIV_decrypt(key, iv, a, sa, test, sp, output);
check("GCMSIV decrypt", output, input, sp);
#endif
-#if EAX && AES_KEY_SIZE == 16
+#if EAX && AES___ == 128
hex2bytes(eaxcipher, test);
#if EAXP
- AES_EAX_encrypt(key, a, input, sp, sa, output);
+ AES_EAX_encrypt(key, a, sa, input, sp, output);
check("EAX encryption", output, test, sp + 4);
- AES_EAX_decrypt(key, a, test, sp, sa, output);
+ AES_EAX_decrypt(key, a, sa, test, sp, output);
#else
- AES_EAX_encrypt(key, iv, input, sp, a, sa, output, output + sp);
- check("EAX encryption", output, test, sp + 16);
- AES_EAX_decrypt(key, iv, test, sp, a, sa, 16, output);
+ AES_EAX_encrypt(key, iv, a, sa, input, sp, output);
+ check("EAX encryption", output, test, sp + EAX_TAG_LEN);
+ AES_EAX_decrypt(key, iv, a, sa, test, sp, output);
#endif
check("EAX decryption", output, input, sp);
#endif
-#if AES_KEY_SIZE + !FPE + CUSTOM_ALPHABET == 16
- memcpy(test, fpecipher, FF_X == 3 ? (sp = 55) : sp);
+#if FPE && AES___ == 128 && !CUSTOM_ALPHABET
+ memcpy(test, fpecipher, sp = FF_X == 3 ? 55 : PTSIZE);
#if FF_X == 3
AES_FPE_encrypt(key, a, fpe_plain, sp, output);
check("FF3 encryption", output, test, sp);
@@ -251,15 +251,15 @@ int main(void)
#endif
#if KWA
hex2bytes(k_wrapped, test);
- AES_KEY_wrap(authKey, key + 32, AES_KEY_SIZE, output);
- check("key wrapping ", output, test, AES_KEY_SIZE + 8);
- AES_KEY_unwrap(authKey, test, AES_KEY_SIZE + 8, output);
- check("key unwrapping", output, key + 32, AES_KEY_SIZE);
+ AES_KEY_wrap(authKey, key + 32, AES_KEYLENGTH, output);
+ check("KW- (key wrap)", output, test, AES_KEYLENGTH + 8);
+ AES_KEY_unwrap(authKey, test, AES_KEYLENGTH + 8, output);
+ check("key unwrapping", output, key + 32, AES_KEYLENGTH);
#endif
- /** a template for "OFFICIAL TEST VECTORS": */
-#if OCB * EAX * SIV * GCM_SIV * POLY1305 * FPE * (16 / AES_KEY_SIZE)
- printf("+-> Let's do some extra tests\n");
+ if (AES_KEYLENGTH > 16) return 0;
+ printf("+-> Let's do some extra tests\n");
+#if OCB
sp = sa = 24; /* taken from RFC-7253: */
hex2bytes("000102030405060708090A0B0C0D0E0F", key);
hex2bytes("BBAA99887766554433221107", iv);
@@ -267,33 +267,37 @@ int main(void)
hex2bytes("000102030405060708090A0B0C0D0E0F1011121314151617", input);
hex2bytes("1CA2207308C87C010756104D8840CE1952F09673A448A122\
C92C62241051F57356D7F3C90BB0E07F", test);
- AES_OCB_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ AES_OCB_encrypt(key, iv, a, sa, input, sp, output);
check("OCB encryption", output, test, sp + OCB_TAG_LEN);
- *output ^= AES_OCB_decrypt(key, iv, test, sp, a, sa, OCB_TAG_LEN, output);
+ *output += AES_OCB_decrypt(key, iv, a, sa, test, sp, output);
check("OCB decryption", output, input, sp);
-
+#endif
+#if GCM_SIV
sp = 11, sa = 7; /* taken from RFC-8452: */
hex2bytes("ee8e1ed9ff2540ae8f2ba9f50bc2f27c", key);
hex2bytes("752abad3e0afb5f434dc4310", iv);
hex2bytes("6578616d706c65", a);
hex2bytes("48656c6c6f20776f726c64", input);
hex2bytes("5d349ead175ef6b1def6fd4fbcdeb7e4793f4a1d7e4faa70100af1", test);
- GCM_SIV_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ GCM_SIV_encrypt(key, iv, a, sa, input, sp, output);
check("GCMSIV encrypt", output, test, sp + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, sp, a, sa, 16, output);
+ *output += GCM_SIV_decrypt(key, iv, a, sa, test, sp, output);
check("GCMSIV decrypt", output, input, sp);
- sp = 12, sa = 1; /* taken from RFC-8452: */
+ sp = 32, sa = 1; /* taken from RFC-8452: */
hex2bytes("01000000000000000000000000000000", key);
hex2bytes("030000000000000000000000", iv);
hex2bytes("01", a);
- hex2bytes("020000000000000000000000", input);
- hex2bytes("296c7889fd99f41917f4462008299c51\
- 02745aaa3a0c469fad9e075a", test);
- GCM_SIV_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ hex2bytes("02000000000000000000000000000000\
+ 03000000000000000000000000000000", input);
+ hex2bytes("620048ef3c1e73e57e02bb8562c416a3\
+ 19e73e4caac8e96a1ecb2933145a1d71\
+ e6af6a7f87287da059a71684ed3498e1", test);
+ GCM_SIV_encrypt(key, iv, a, sa, input, sp, output);
check("GCMSIV encrypt", output, test, sp + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, sp, a, sa, 16, output);
+ *output += GCM_SIV_decrypt(key, iv, a, sa, test, sp, output);
check("GCMSIV decrypt", output, input, sp);
-
+#endif
+#if SIV
sp = 14, sa = 24; /* taken from RFC-5297: */
hex2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff", key);
@@ -302,18 +306,19 @@ int main(void)
hex2bytes("11223344 55667788 99aabbcc ddee", input);
hex2bytes("85632d07 c6e8f37f 950acd32 0a2ecc93\
40c02b96 90c4dc04 daef7f6a fe5c", test);
- AES_SIV_encrypt(key, input, sp, a, sa, output, output + 16);
+ AES_SIV_encrypt(key, a, sa, input, sp, output, output + 16);
check("SIV encryption", output, test, sp + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, output);
+ *output += AES_SIV_decrypt(key, test, a, sa, test + 16, sp, output);
check("SIV decryption", output, input, sp);
sp = 16, sa = 0; /* from miscreant on github: bit.ly/3ycgGB */
hex2bytes("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", key);
hex2bytes("00112233445566778899aabbccddeeff", input);
hex2bytes("f304f912863e303d5b540e5057c7010c942ffaf45b0e5ca5fb9a56a5263bb065", test);
- AES_SIV_encrypt(key, input, sp, a, sa, output, output + 16);
+ AES_SIV_encrypt(key, a, sa, input, sp, output, output + 16);
check("SIV encryption", output, test, sp + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, output);
+ *output += AES_SIV_decrypt(key, test, a, sa, test + 16, sp, output);
check("SIV decryption", output, input, sp);
+#endif
#if EAXP
sp = 0, sa = 50; /* from Annex G of the IEEE Std. 1703-2012 */
hex2bytes("01020304050607080102030405060708", key);
@@ -322,10 +327,10 @@ int main(void)
7C86F7540116007B040248F3C2040330\
0005", input);
hex2bytes("515AE775", test);
- AES_EAX_encrypt(key, input, NULL, sp, sa, output);
- check("EAX encryption", output, test, sp + 4);
- sp += AES_EAX_decrypt(key, input, test, sp, sa, output);
- check("EAX decryption", output, input, sp);
+ AES_EAX_encrypt(key, input, sa, NULL, sp, output);
+ check("EAX\'encryption", output, test, sp + 4);
+ sp += AES_EAX_decrypt(key, input, sa, test, sp, output);
+ check("EAX\'decryption", output, input, sp);
sp = 28, sa = 65; /* from Moise-Beroset-Phinney-Burns paper: */
hex2bytes("10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 00", authKey);
hex2bytes("a2 0e 06 0c 60 86 48 01 86 fc 2f 81 1c aa 4e 01\
@@ -337,44 +342,13 @@ int main(void)
30 30 30 30 30 30 00 00 03 30 00 01", input);
hex2bytes("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(authKey, test, input, sp, sa, output);
- check("EAX encryption", output, key, sp + 4);
- AES_EAX_decrypt(authKey, test, key, sp, sa, output);
-#else
- sp = 12, sa = 8; /* from Bellare-Rogaway-Wagner 2004 paper: */
- hex2bytes("BD8E6E11475E60B268784C38C62FEB22", key);
- hex2bytes("6EAC5C93072D8E8513F750935E46DA1B", iv);
- hex2bytes("D4482D1CA78DCE0F", a);
- hex2bytes("4DE3B35C3FC039245BD1FB7D", input);
- hex2bytes("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F", test);
- AES_EAX_encrypt(key, iv, input, sp, a, sa, output, output + sp);
- check("EAX encryption", output, test, sp + 16);
- AES_EAX_decrypt(key, iv, test, sp, a, sa, 16, output);
+ AES_EAX_encrypt(authKey, test, sa, input, sp, output);
+ check("EAX\'encryption", output, key, sp + 4);
+ AES_EAX_decrypt(authKey, test, sa, key, sp, output);
+ check("EAX\'decryption", output, input, sp);
#endif
- check("EAX decryption", output, input, sp);
-
-#if (FF_X != 3) * CUSTOM_ALPHABET == 3
- sp = 19, sa = 11;
- hex2bytes("2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C", key);
- hex2bytes("37 37 37 37 70 71 72 73 37 37 37", a);
- memcpy(input, "0123456789abcdefghi", sp);
- memcpy(output, "a9tv40mll9kdu509eum", sp);
- AES_FPE_encrypt(key, a, sa, input, sp, test);
- check("FF1 encryption", test, output, sp);
- AES_FPE_decrypt(key, a, sa, output, sp, test);
- check("FF1 decryption", test, input, sp);
-#elif FF_X * !CUSTOM_ALPHABET == 3
- sp = 29; /* zero tweak works for both FF3 and FF3-1 */
- hex2bytes("EF 43 59 D8 D5 80 AA 4F 7F 03 6D 6F 04 FC 6A 94", key);
- hex2bytes("00 00 00 00 00 00 00 00", a);
- memcpy(input, "89012123456789000000789000000", sp);
- memcpy(output, "34695224821734535122613701434", sp);
- AES_FPE_encrypt(key, a, input, sp, test);
- check("FF3 encryption", test, output, sp);
- AES_FPE_decrypt(key, a, output, sp, test);
- check("FF3 decryption", test, input, sp);
-#endif
- sp = 32; /* ↓ from Daniel J. Bernstein's 2005 paper */
+#if POLY1305
+ sp = 32; /* taken from D.J. Bernstein (2005) paper: */
hex2bytes("66 3c ea 19 0f fb 83 d8 95 93 f3 f4 76 b6 bc 24\
d7 e6 79 10 7e a2 6a db 8c af 66 52 d0 65 61 36", input);
hex2bytes("6a cb 5f 61 a7 17 6d d3 20 c5 c1 eb 2e dc dc 74\
diff --git a/micro_aes.c b/micro_aes.c
index 9535588..de0077b 100644
--- a/micro_aes.c
+++ b/micro_aes.c
@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.c
Author : polfosol
- Version : 10
+ Version : 11
Copyright : copyright © 2022 - polfosol
Description : ANSI-C compatible implementation of µAES ™ library.
==============================================================================
@@ -15,20 +15,21 @@
\*----------------------------------------------------------------------------*/
enum basic_constants
{
- BLOCKSIZE = (128) / 8, /* Block length in AES is 'always' 128-bits */
- KEYSIZE = AES_KEY_SIZE,
- Nb = BLOCKSIZE / 4, /* number of columns comprising a AES state */
- Nk = KEYSIZE / 4, /* number of 32 bit words in a key. */
- ROUNDS = Nk + 6, /* number of rounds in AES Cipher. */
- LAST = BLOCKSIZE - 1, /* index of last element (LSB) in a block. */
- HB = BLOCKSIZE / 2, /* length of a half-block unit. */
- SP = 17 /* length of data blocks in poly-1305 mode. */
+ BLOCKSIZE = 128 / 8, /* Block length in AES is 'always' 128-bits. */
+ KEYSIZE = AES_KEYLENGTH,
+ Nb = BLOCKSIZE / 4, /* number of columns comprising a AES state. */
+ Nk = KEYSIZE / 4, /* number of 32 bit words in a key. */
+ ROUNDS = Nk + 6, /* number of rounds in AES Cipher. */
+ HB = BLOCKSIZE / 2, /* length of a half-block unit. */
+ LAST = BLOCKSIZE - 1, /* index of last element (LSB) in a block. */
+ MIDST = LAST / 2, /* index of half-block LSB. */
+ PL = BLOCKSIZE + 1 /* length of arithmetic blocks in poly-1305. */
};
#define IMPLEMENT(x) (x) > 0
-#define INCREASE_SECURITY 0 /* see the comments at the bottom of header */
-#define DISCARD_SUBROUTINES 0
+#define INCREASE_SECURITY 0 /* see the comments at the bottom of header. */
+#define INLINE_SUBROUTINES 0
#define SMALL_CIPHER 0
/** Lookup-tables are "static constant", so that they can be placed in read-only
@@ -85,7 +86,7 @@ typedef uint8_t state_t[Nb][4];
#define COPYDWORD(x, y) *(int32_t*) &y = *(int32_t*) &x
#define XOR32BITS(x, y) *(int32_t*) &y ^= *(int32_t*) &x
-#if DISCARD_SUBROUTINES
+#if INLINE_SUBROUTINES
/** note: 'long long' type is NOT supported in C89. so this may throw errors: */
#define xorBlock(x, y) \
@@ -100,7 +101,7 @@ typedef uint8_t state_t[Nb][4];
xtime(a ^ b ^ xtime(a ^ c ^ xtime(a ^ b ^ c ^ d )))
#else
-/** XOR two 128bit numbers (blocks) called src and dest, so that: dest ^= src */
+/** XOR two 128bit blocks, i.e. add two numbers in Galois bit field GF(2^128) */
static void xorBlock( const block_t src, block_t dest )
{
uint8_t i;
@@ -151,10 +152,10 @@ static void KeyExpansion( const uint8_t* key )
{
case 0:
memcpy( &RoundKey[i], &RoundKey[i - KEYSIZE], KEYSIZE );
-
- /* RCON reaches 0 only in AES-128, otherwise the line is ignored. */
- if (4 / Nk && rcon == 0) rcon = 0x1b;
-
+ if (4 / Nk && !rcon)
+ {
+ rcon = 0x1b; /* RCON reaches 0 only in AES-128, when Nk=4 */
+ }
RoundKey[i ] ^= SBoxValue( RoundKey[i - 3] ) ^ rcon;
RoundKey[i + 1] ^= SBoxValue( RoundKey[i - 2] );
RoundKey[i + 2] ^= SBoxValue( RoundKey[i - 1] );
@@ -176,7 +177,7 @@ static void KeyExpansion( const uint8_t* key )
}
}
-/** Add the round keys to the rijndael state matrix (adding in GF means XOR). */
+/** XOR the round keys with the rijndael state matrix; namely, add them in GF */
static void AddRoundKey( const uint8_t round, block_t state )
{
xorBlock( RoundKey + BLOCKSIZE * round, state );
@@ -227,11 +228,10 @@ static void MixColumns( state_t state )
C[1] ^= C[0];
C[0] ^= C[2];
C[2] = xtime( C[0] );
- C[0] ^= C[3]; /* C[0] = xor of all elements in i-th column */
C[0] ^= xtime( C[1] );
C[1] = xtime( C[3] );
- state[i][0] ^= C[0];
+ state[i][0] ^= C[0] ^= C[3];
state[i][1] ^= C[0] ^= C[2];
state[i][2] ^= C[0] ^= C[1];
state[i][3] ^= C[0] ^= C[2];
@@ -362,26 +362,26 @@ typedef void (*fdouble_t)( block_t );
#if INCREASE_SECURITY
#define BURN(key) memset( key, 0, sizeof key )
#define SABOTAGE(buf, len) memset( buf, 0, len )
-#define MISMATCH constmemcmp /* a.k.a secure memcmp */
-#else
-#define MISMATCH memcmp
-#define SABOTAGE(buf, len) (void) buf
-#define BURN(key) (void) key /* the line will be ignored */
-#endif
-
-#if INCREASE_SECURITY && AEAD_MODES
+#if AEAD_MODES
/** for constant-time comparison of memory blocks, to avoid "timing attacks". */
-static uint8_t constmemcmp( const uint8_t* src, const uint8_t* dst, uint8_t n )
+static uint8_t memcmp_s( const void* src, const void* dest, const uint8_t len )
{
- uint8_t cmp = 0;
- while (n--)
+ const volatile char *p1 = src, *p2 = (const volatile char*) dest;
+ volatile uint8_t result = 0;
+ char i;
+ for (i = 0; i != len; i++)
{
- cmp |= src[n] ^ dst[n];
+ result |= p1[i] ^ p2[i];
}
- return cmp;
+ return result;
}
#endif
+#else
+#define BURN(key) (void) key /* the line will be ignored */
+#define SABOTAGE(buf, len) (void) buf
+#define memcmp_s memcmp
+#endif
#if SMALL_CIPHER
typedef uint8_t count_t;
@@ -439,7 +439,7 @@ static void doubleBblock( block_t array )
c |= array[--i] << 1; /* append the previous MSBit */
array[i] = (uint8_t) c;
} /* if first MSBit is carried */
- array[LAST] ^= c * 0x87; /* .. B ^= 10000111b (B.E.) */
+ array[LAST] ^= c * 0x87; /* .. A ^= 10000111b (B.E.) */
}
#endif
@@ -454,7 +454,7 @@ static void doubleLblock( block_t array )
c |= array[i] << 1;
array[i++] = (uint8_t) c;
}
- array[0] ^= c * 0x87; /* B ^= 10000111b (L.E.) */
+ array[0] ^= c * 0x87; /* A ^= 10000111b (L.E.) */
}
#endif
@@ -469,7 +469,7 @@ static void divideBblock( block_t array )
c = c << 8 | array[i]; /* then shift it to right. */
array[i] = c >> 1;
} /* if block is odd (LSB = 1) */
- if (c & 1) array[0] ^= 0xe1; /* .. B ^= 11100001b << 120 */
+ if (c & 1) array[0] ^= 0xe1; /* .. A ^= 11100001b << 120 */
}
/** Multiply two 128-bit numbers (big-endian blocks) in the Galois bit field. */
@@ -504,7 +504,7 @@ static void divideLblock( block_t array )
c = c << 8 | array[i];
array[i] = c >> 1;
}
- if (c & 1) array[LAST] ^= 0xe1; /* B ^= LE. 11100001b << 120 */
+ if (c & 1) array[LAST] ^= 0xe1; /* (L.E) A ^= 11100001b<<120 */
}
/** The so-called "dot multiplying" in GF(2^128), used in POLYVAL calculation */
@@ -534,13 +534,12 @@ static void dotGF128( const block_t x, block_t y )
static void mixThenXor( fmix_t mix, const block_t B, block_t f,
const uint8_t* X, uint8_t n, uint8_t* Y )
{
- if (n != 0)
+ if (n == 0) return;
+
+ mix( B, f ); /* Y = f(B) ^ X */
+ while (n--)
{
- mix( B, f ); /* Y = f(B) ^ X */
- while (n--)
- {
- Y[n] = f[n] ^ X[n];
- }
+ Y[n] = f[n] ^ X[n];
}
}
#endif
@@ -560,7 +559,7 @@ static void xMac( const void* data, const size_t dataSize,
xorBlock( x, result ); /* M_next = mix(seed, M ^ X) */
mix( seed, result );
}
- if ((n = dataSize % BLOCKSIZE) != 0) /* if any partial block left */
+ if ((n = dataSize % BLOCKSIZE) > 0) /* if any partial block left */
{
while (n--)
{
@@ -705,7 +704,7 @@ char AES_CBC_encrypt( const uint8_t* key, const block_t iVec,
#if CTS
if (n > 1 && !r && --n) r = BLOCKSIZE; /* CS3 ciphertext stealing */
- if (n == 0) return M_ENCRYPTION_ERROR; /* data size >= BLOCKSIZE */
+ if (n == 0) return M_DATALENGTH_ERROR; /* data size >= BLOCKSIZE */
#endif
memcpy( crtxt, pntxt, ptextLen ); /* do in-place encryption */
@@ -754,9 +753,9 @@ char AES_CBC_decrypt( const uint8_t* key, const block_t iVec,
#if CTS
if (n > 1 && !r && --n) r = BLOCKSIZE;
- if (n == 0) return M_DECRYPTION_ERROR;
+ if (n == 0) return M_DATALENGTH_ERROR;
#else
- if (r != 0) return M_DECRYPTION_ERROR;
+ if (r != 0) return M_DATALENGTH_ERROR;
#endif
n -= r > 0; /* hold last 2 blocks in CTS */
@@ -900,6 +899,15 @@ void AES_OFB_decrypt( const uint8_t* key, const block_t iVec,
+ How to use it in a simple, non-authenticated API
\*----------------------------------------------------------------------------*/
#if CTR
+
+enum ctr_based_modes
+{
+ CTR_DEFAULT,
+ SIV_CTR = 5, /* RFC-5297 */
+ SIVGCM_CTR = 8, /* RFC-8452 (GCM-SIV) */
+ CCM_GCM = 2 /* either CCM or GCM */
+};
+
/**
* @brief the general scheme of operation in block-counter mode
* @param iCtr initialized counter block
@@ -920,17 +928,17 @@ static void CTR_cipher( const block_t iCtr, const char mode,
switch (mode)
{
- case 2:
- incBlock( c, index ); /* pre-increment in CCM/GCM */
- break;
- case 4:
- c[+8] &= 0x7F; /* SIV mode: clear two bits */
+ case SIV_CTR:
+ c[+8] &= 0x7F; /* clear 2 bits in SIV mode */
c[12] &= 0x7F;
break;
- case 8: /* GCM-SIV: set one bit */
- c[index] |= 0x80;
+ case SIVGCM_CTR:
+ c[LAST] |= 0x80; /* set 1 bit of L.E counter */
index = 0;
break;
+ case CCM_GCM:
+ incBlock( c, index ); /* pre-increment in CCM/GCM */
+ break;
}
for (y = output; n--; y += BLOCKSIZE)
{
@@ -954,16 +962,16 @@ static void CTR_cipher( const block_t iCtr, const char mode,
void AES_CTR_encrypt( const uint8_t* key, const uint8_t* iv,
const void* pntxt, const size_t ptextLen, void* crtxt )
{
-#if CTR_IV_LENGTH == 16
+#if PRESET_COUNTER
uint8_t const* ctr = iv; /* block is pre-initialized */
#else
block_t ctr = { 0 };
memcpy( ctr, iv, CTR_IV_LENGTH );
- xorBEint( ctr, CTR_STARTVALUE, LAST ); /* initialize the counter */
+ xorBEint( ctr, CTR_START_VALUE, LAST ); /* initialize the counter */
#endif
AES_setkey( key );
- CTR_cipher( ctr, 0, pntxt, ptextLen, crtxt );
+ CTR_cipher( ctr, CTR_DEFAULT, pntxt, ptextLen, crtxt );
BURN( RoundKey );
}
@@ -1058,7 +1066,7 @@ static void XTS_cipher( const uint8_t* keypair, const char mode,
char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* tweak,
const void* pntxt, const size_t ptextLen, void* crtxt )
{
- if (ptextLen < BLOCKSIZE) return M_ENCRYPTION_ERROR;
+ if (ptextLen < BLOCKSIZE) return M_DATALENGTH_ERROR;
memcpy( crtxt, pntxt, ptextLen ); /* do in-place encryption */
XTS_cipher( keys, 1, tweak, 0, ptextLen, crtxt );
@@ -1077,7 +1085,7 @@ char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* tweak,
char AES_XTS_decrypt( const uint8_t* keys, const uint8_t* tweak,
const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- if (crtxtLen < BLOCKSIZE) return M_DECRYPTION_ERROR;
+ if (crtxtLen < BLOCKSIZE) return M_DATALENGTH_ERROR;
memcpy( pntxt, crtxt, crtxtLen ); /* in-place decryption */
XTS_cipher( keys, 0, tweak, 0, crtxtLen, pntxt );
@@ -1116,11 +1124,11 @@ void AES_CMAC( const uint8_t* key,
#if IMPLEMENT(GCM)
/** calculate G-Hash of ciphertext and AAD using an authentication subkey `H` */
-static void Ghash( const block_t H, const void* aData, const void* crtxt,
+static void gHash( const block_t H, const void* aData, const void* crtxt,
const size_t aDataLen, const size_t crtxtLen, block_t gh )
{
block_t len = { 0 };
- xorBEint( len, aDataLen * 8, LAST / 2 );
+ xorBEint( len, aDataLen * 8, MIDST );
xorBEint( len, crtxtLen * 8, LAST ); /* save bit-sizes into len */
xMac( aData, aDataLen, H, &mulGF128, gh ); /* first digest AAD, then */
@@ -1129,77 +1137,76 @@ static void Ghash( const block_t H, const void* aData, const void* crtxt,
}
/** encrypt zeros to get authentication subkey H, and prepare the IV for GCM. */
-static void GCMinit( const uint8_t* key,
- const uint8_t* nonce, block_t auKey, block_t iv )
+static void GCMsetup( const uint8_t* key,
+ const uint8_t* nonce, block_t auKey, block_t iv )
{
AES_setkey( key );
rijndaelEncrypt( auKey, auKey ); /* auKey = Enc( zero block ) */
-#if GCM_NONCE_LEN != 12
- Ghash( auKey, NULL, nonce, 0, GCM_NONCE_LEN, iv );
-#else
+ if (GCM_NONCE_LEN != 12)
+ {
+ gHash( auKey, NULL, nonce, 0, GCM_NONCE_LEN, iv );
+ return;
+ }
memcpy( iv, nonce, 12 );
iv[LAST] = 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 nonce a.k.a initialization vector with fixed size: GCM_NONCE_LEN
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param crtxt resulting cipher-text buffer
- * @param auTag message authentication tag. buffer must be 16-bytes long
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
+ * @param crtxt resulting cipher-text buffer + message authentication tag
*/
void AES_GCM_encrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* pntxt, const size_t ptextLen,
- const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, block_t auTag )
+ const void* aData, const size_t aDataLen,
+ const void* pntxt, const size_t ptextLen, void* crtxt )
{
- block_t gh = { 0 }, H = { 0 }, iv = { 0 };
- GCMinit( key, nonce, H, iv ); /* get IV & auth. subkey H */
+ uint8_t* tag = (uint8_t*) crtxt + ptextLen;
+ block_t iv = { 0 }, H = { 0 }, G = { 0 };
- CTR_cipher( iv, 2, pntxt, ptextLen, crtxt );
+ GCMsetup( key, nonce, H, iv ); /* get IV & auth. subkey H */
+ CTR_cipher( iv, CCM_GCM, pntxt, ptextLen, crtxt );
rijndaelEncrypt( iv, iv );
BURN( RoundKey );
- Ghash( H, aData, crtxt, aDataLen, ptextLen, gh );
- xorBlock( iv, gh );
- memcpy( auTag, gh, BLOCKSIZE ); /* GMAC = Enc(iv) ^ G-HASH */
+ gHash( H, aData, crtxt, aDataLen, ptextLen, G );
+ xorBlock( iv, G );
+ memcpy( tag, G, GCM_TAG_LEN ); /* GMAC = Enc(iv) ^ G-HASH */
}
/**
* @brief decrypt the input ciphertext using GCM-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
* @param nonce a.k.a initialization vector with fixed size: GCM_NONCE_LEN
- * @param crtxt input cipher-text buffer + appended authentication tag
- * @param crtxtLen size of ciphertext, excluding tag
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param tagLen length of authentication tag
+ * @param crtxt input cipher-text buffer + appended authentication tag
+ * @param crtxtLen size of ciphertext, excluding tag
* @param pntxt resulting plaintext buffer
* @return whether message authentication/decryption was successful
*/
char AES_GCM_decrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* crtxt, const size_t crtxtLen,
- const uint8_t* aData, const size_t aDataLen,
- const uint8_t tagLen, uint8_t* pntxt )
+ const void* aData, const size_t aDataLen,
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- block_t gh = { 0 }, H = { 0 }, iv = { 0 };
- GCMinit( key, nonce, H, iv );
+ uint8_t const* tag = (uint8_t*) crtxt + crtxtLen;
+ block_t H = { 0 }, iv = { 0 }, G = { 0 };
- Ghash( H, aData, crtxt, aDataLen, crtxtLen, gh );
+ GCMsetup( key, nonce, H, iv );
+ gHash( H, aData, crtxt, aDataLen, crtxtLen, G );
rijndaelEncrypt( iv, H );
- xorBlock( gh, H ); /* tag = Enc(iv) ^ G-HASH */
+ xorBlock( H, G ); /* tag = Enc(iv) ^ G-HASH */
- if (MISMATCH( H, crtxt + crtxtLen, tagLen ))
+ if (memcmp_s( tag, G, GCM_TAG_LEN ))
{ /* compare tags and */
BURN( RoundKey ); /* ..proceed if they match */
return M_AUTHENTICATION_ERROR;
}
- CTR_cipher( iv, 2, crtxt, crtxtLen, pntxt );
+ CTR_cipher( iv, CCM_GCM, crtxt, crtxtLen, pntxt );
BURN( RoundKey );
return M_RESULT_SUCCESS;
}
@@ -1216,7 +1223,7 @@ static void CCMtag( const block_t iv, const void* aData, const void* pntxt,
const size_t aDataLen, const size_t ptextLen, block_t M )
{
block_t A = { 0 };
- uint8_t s = aDataLen < LAST ? aDataLen : sizeof A - 2;
+ uint8_t p = 1, s = 0;
memcpy( M, iv, BLOCKSIZE ); /* initialize CBC-MAC */
M[0] |= (CCM_TAG_LEN - 2) << 2; /* set some flags on M_* */
@@ -1226,13 +1233,14 @@ static void CCMtag( const block_t iv, const void* aData, const void* pntxt,
{
M[0] |= 0x40;
rijndaelEncrypt( M, M ); /* flag M_* and encrypt it */
- if (aDataLen > 0xFEFF)
+ if (aDataLen > 0xFEFFL)
{ /* assuming aDataLen < 2^32 */
- s -= 4;
+ p += 4;
A[0] = 0xFF, A[1] = 0xFE; /* prepend FFFE to aDataLen */
}
- xorBEint( A, aDataLen, LAST - s ); /* copy aDataLen into A, */
- memcpy( A + sizeof A - s, aData, s ); /* ..and append aData */
+ xorBEint( A, aDataLen, p ); /* copy aDataLen into A */
+ s = sizeof A - ++p;
+ memcpy( A + p, aData, aDataLen < s ? aDataLen : s );
}
/* digest the first s bytes of aData, the rest of it, and then plaintext: */
@@ -1251,58 +1259,55 @@ static void CCMtag( const block_t iv, const void* aData, const void* pntxt,
* @brief encrypt the input plaintext using CCM-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
* @param nonce a.k.a initialization vector with fixed size: CCM_NONCE_LEN
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param crtxt resulting cipher-text buffer
- * @param auTag message authentication tag
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
+ * @param crtxt resulting cipher-text buffer + message authentication tag
*/
void AES_CCM_encrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* pntxt, const size_t ptextLen,
- const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, uint8_t* auTag )
+ const void* aData, const size_t aDataLen,
+ const void* pntxt, const size_t ptextLen, void* crtxt )
{
- block_t iv = { 14 - CCM_NONCE_LEN, 0 }, tag;
- memcpy( iv + 1, nonce, CCM_NONCE_LEN );
+ uint8_t* tag = (uint8_t*) crtxt + ptextLen;
+ block_t iv = { 14 - CCM_NONCE_LEN, 0 }, C;
+ memcpy( iv + 1, nonce, CCM_NONCE_LEN );
AES_setkey( key );
- CCMtag( iv, aData, pntxt, aDataLen, ptextLen, tag );
- CTR_cipher( iv, 2, pntxt, ptextLen, crtxt );
+ CCMtag( iv, aData, pntxt, aDataLen, ptextLen, C );
+ CTR_cipher( iv, CCM_GCM, pntxt, ptextLen, crtxt );
BURN( RoundKey );
- memcpy( auTag, tag, CCM_TAG_LEN );
+
+ memcpy( tag, C, CCM_TAG_LEN );
}
/**
* @brief decrypt the input ciphertext using CCM-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
* @param nonce a.k.a initialization vector with fixed size: CCM_NONCE_LEN
- * @param crtxt input cipher-text buffer + appended authentication tag
- * @param crtxtLen size of ciphertext, excluding tag
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param tagLen length of authentication tag
+ * @param crtxt input cipher-text buffer + appended authentication tag
+ * @param crtxtLen size of ciphertext, excluding tag
* @param pntxt resulting plaintext buffer
* @return whether message decryption/authentication was successful
*/
char AES_CCM_decrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* crtxt, const size_t crtxtLen,
- const uint8_t* aData, const size_t aDataLen,
- const uint8_t tagLen, uint8_t* pntxt )
+ const void* aData, const size_t aDataLen,
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- block_t iv = { 14 - CCM_NONCE_LEN, 0 }, tag;
+ uint8_t const* tag = (uint8_t*) crtxt + crtxtLen;
+ block_t iv = { 14 - CCM_NONCE_LEN, 0 }, C;
+
memcpy( iv + 1, nonce, CCM_NONCE_LEN );
-
- if (tagLen != CCM_TAG_LEN) return M_DECRYPTION_ERROR;
-
AES_setkey( key );
- CTR_cipher( iv, 2, crtxt, crtxtLen, pntxt );
- CCMtag( iv, aData, pntxt, aDataLen, crtxtLen, tag );
+ CTR_cipher( iv, CCM_GCM, crtxt, crtxtLen, pntxt );
+ CCMtag( iv, aData, pntxt, aDataLen, crtxtLen, C );
BURN( RoundKey );
- if (MISMATCH( tag, crtxt + crtxtLen, tagLen ))
- { /* invalid tag: clear pntxt */
- SABOTAGE( pntxt, crtxtLen );
+ if (memcmp_s( tag, C, CCM_TAG_LEN ))
+ {
+ SABOTAGE( pntxt, crtxtLen ); /* invalid tag: clear pntxt */
return M_AUTHENTICATION_ERROR;
}
return M_RESULT_SUCCESS;
@@ -1316,12 +1321,11 @@ char AES_CCM_decrypt( const uint8_t* key, const uint8_t* nonce,
#if IMPLEMENT(SIV)
/** calculate the CMAC* of AAD unit(s), then plaintext, and synthesize the IV */
-static void S2V( const uint8_t* key,
- const void* aData, const void* pntxt,
+static void S2V( const uint8_t* key, const void* aData, const void* pntxt,
const size_t aDataLen, const size_t ptextLen, block_t IV )
{
block_t K[2] = { { 0 } }, Y;
- uint8_t r = ptextLen % BLOCKSIZE, *Q = K[1];
+ uint8_t r, *Q = K[1];
memcpy( IV, *K, BLOCKSIZE ); /* initialize/clear IV */
getSubkeys( &doubleBblock, 1, key, *K, Q );
@@ -1329,8 +1333,8 @@ static void S2V( const uint8_t* key,
/* in case of multiple AAD units, each one must be handled in a similar way.
* for example, let aData be a 2-D array and aDataLen a null-terminated one.
- * then, instead of `if (aDataLen) { cMac( *K, Q, aData,...` we could write:
- * for (int i = 0; *aDataLen; ){ cMac(*K, Q, aData[i++], *aDataLen++, IV) */
+ * then instead of `if (aDataLen) { cMac(*K, Q, aData, aDataLen, IV)` write:
+ * for (r = 0; *aDataLen; ) { cMac( *K, Q, aData[r++], *aDataLen++, IV ); */
if (aDataLen)
{
cMac( *K, Q, aData, aDataLen, IV );
@@ -1343,36 +1347,36 @@ static void S2V( const uint8_t* key,
doubleBblock( Y ); /* Y = double( Y_n ) */
r = 0;
}
- if (r)
+ else if ((r = ptextLen % sizeof Y) > 0)
{
memset( *K, 0, BLOCKSIZE );
}
xorBlock( Y, *K + r );
- cMac( *K, *K, pntxt, ptextLen - r, IV ); /* CMAC*( Y xor_end M ) */
- if (r)
- {
- cMac( NULL, Q, (char*) pntxt + ptextLen - r, r, IV );
- }
+ cMac( *K, *K, pntxt, ptextLen - r, IV ); /* CMAC*( Y xor_end MSG ) */
+
+ if (r == 0) return;
+
+ cMac( NULL, Q, (char*) pntxt + ptextLen - r, r, IV );
}
/**
* @brief encrypt the input plaintext using SIV-AES block-cipher method
* @param keys two-part encryption key with a fixed size of 2*KEYSIZE
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
* @param iv synthesized I.V block, typically prepended to ciphertext
* @param crtxt resulting cipher-text buffer
*/
void AES_SIV_encrypt( const uint8_t* keys,
- const void* pntxt, const size_t ptextLen,
const void* aData, const size_t aDataLen,
+ const void* pntxt, const size_t ptextLen,
block_t iv, void* crtxt )
{
S2V( keys, aData, pntxt, aDataLen, ptextLen, iv );
AES_setkey( keys + KEYSIZE );
- CTR_cipher( iv, 4, pntxt, ptextLen, crtxt );
+ CTR_cipher( iv, SIV_CTR, pntxt, ptextLen, crtxt );
BURN( RoundKey );
}
@@ -1380,25 +1384,24 @@ void AES_SIV_encrypt( const uint8_t* keys,
* @brief decrypt the input ciphertext using SIV-AES block-cipher method
* @param keys two-part encryption key with a fixed size of 2*KEYSIZE
* @param iv provided I.V block to validate
- * @param crtxt input cipher-text buffer
- * @param crtxtLen size of ciphertext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
+ * @param crtxt input cipher-text buffer
+ * @param crtxtLen size of ciphertext in bytes
* @param pntxt resulting plaintext buffer
* @return whether message decryption/authentication was successful
*/
char AES_SIV_decrypt( const uint8_t* keys, const block_t iv,
- const void* crtxt, const size_t crtxtLen,
const void* aData, const size_t aDataLen,
- void* pntxt )
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
block_t IV;
AES_setkey( keys + KEYSIZE );
- CTR_cipher( iv, 4, crtxt, crtxtLen, pntxt );
+ CTR_cipher( iv, SIV_CTR, crtxt, crtxtLen, pntxt );
S2V( keys, aData, pntxt, aDataLen, crtxtLen, IV );
BURN( RoundKey );
- if (MISMATCH( IV, iv, sizeof IV )) /* verify the synthesized IV */
+ if (memcmp_s( IV, iv, sizeof IV )) /* verify the synthesized IV */
{
SABOTAGE( pntxt, crtxtLen );
return M_AUTHENTICATION_ERROR;
@@ -1415,12 +1418,12 @@ char AES_SIV_decrypt( const uint8_t* keys, const block_t iv,
#if IMPLEMENT(GCM_SIV)
/** calculate the POLYVAL of plaintext and AAD using authentication subkey H. */
-static void Polyval( const block_t H, const void* aData, const void* pntxt,
+static void polyval( const block_t H, const void* aData, const void* pntxt,
const size_t aDataLen, const size_t ptextLen, block_t pv )
{
block_t len = { 0 }; /* save bit-sizes into len */
copyLint( len, aDataLen * 8, 0 );
- copyLint( len, ptextLen * 8, 8 );
+ copyLint( len, ptextLen * 8, HB );
xMac( aData, aDataLen, H, &dotGF128, pv ); /* first digest AAD, then */
xMac( pntxt, ptextLen, H, &dotGF128, pv ); /* ..plaintext, and then */
@@ -1428,11 +1431,11 @@ static void Polyval( const block_t H, const void* aData, const void* pntxt,
}
/** derive the pair of authentication-encryption-keys from main key and nonce */
-static void GCMSIVinit( const uint8_t* key, const uint8_t* nonce, block_t AK )
+static void GCM_SIVsetup( const uint8_t* key, const uint8_t* nonce, block_t AK )
{
uint8_t iv[5 * HB + KEYSIZE], *h, *k;
k = h = iv + BLOCKSIZE;
- memcpy( iv + 4, nonce, 12 );
+ memcpy( iv + 4, nonce, SIVGCM_NONCE_LEN );
AES_setkey( key );
for (*(int32_t*) iv = 0; *iv < 2 + Nk / 2; ++*iv)
@@ -1445,37 +1448,37 @@ static void GCMSIVinit( const uint8_t* key, const uint8_t* nonce, block_t AK )
}
/** get the tag in GCM-SIV mode, given the nonce and calculated POLYVAL block */
-static void GSIVtag( const uint8_t* nonce, block_t polyval, block_t tag )
+static void GCM_SIVtag( const uint8_t* nonce, block_t pv, block_t tag )
{
- XOR32BITS( nonce[0], polyval[0] );
- XOR32BITS( nonce[4], polyval[4] ); /* xor POLYVAL with nonce */
- XOR32BITS( nonce[8], polyval[8] );
- polyval[LAST] &= 0x7F; /* clear one bit & encrypt, */
- rijndaelEncrypt( polyval, tag );
+ XOR32BITS( nonce[0], pv[0] );
+ XOR32BITS( nonce[4], pv[4] ); /* xor POLYVAL with nonce */
+ XOR32BITS( nonce[8], pv[8] );
+ pv[LAST] &= 0x7F; /* clear one bit & encrypt, */
+ rijndaelEncrypt( pv, tag );
}
/**
* @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 provided 96-bit nonce
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param crtxt resulting cipher-text buffer,
- * @param auTag appended authentication tag. must be 16-bytes long
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
+ * @param crtxt resulting cipher-text buffer + message authentication tag
*/
void GCM_SIV_encrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* pntxt, const size_t ptextLen,
- const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, block_t auTag )
+ const void* aData, const size_t aDataLen,
+ const void* pntxt, const size_t ptextLen, void* crtxt )
{
- block_t H, P = { 0 };
- GCMSIVinit( key, nonce, H ); /* get authentication subkey */
+ block_t P = { 0 };
+ uint8_t *H, *tag = (uint8_t*) crtxt + ptextLen;
- Polyval( H, aData, pntxt, aDataLen, ptextLen, P );
- GSIVtag( nonce, P, auTag );
- CTR_cipher( auTag, 8, pntxt, ptextLen, crtxt );
+ H = tag; /* use a pre-allocated space */
+ GCM_SIVsetup( key, nonce, H );
+ polyval( H, aData, pntxt, aDataLen, ptextLen, P );
+ GCM_SIVtag( nonce, P, tag );
+ CTR_cipher( tag, SIVGCM_CTR, pntxt, ptextLen, crtxt );
BURN( RoundKey );
}
@@ -1483,31 +1486,27 @@ void GCM_SIV_encrypt( const uint8_t* key, const uint8_t* nonce,
* @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 provided 96-bit nonce
- * @param crtxt input cipher-text buffer + appended authentication tag
- * @param crtxtLen size of ciphertext, excluding tag
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param tagLen length of authentication tag; MUST be 16 bytes
+ * @param crtxt input cipher-text buffer + appended authentication tag
+ * @param crtxtLen size of ciphertext, excluding tag
* @param pntxt resulting plaintext buffer
* @return whether message decryption/authentication was successful
*/
char GCM_SIV_decrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* crtxt, const size_t crtxtLen,
- const uint8_t* aData, const size_t aDataLen,
- const uint8_t tagLen, uint8_t* pntxt )
+ const void* aData, const size_t aDataLen,
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- uint8_t const* tag = crtxt + crtxtLen;
block_t H, P = { 0 };
+ uint8_t const* tag = (uint8_t*) crtxt + crtxtLen;
- if (tagLen != sizeof P) return M_DECRYPTION_ERROR;
-
- GCMSIVinit( key, nonce, H ); /* get authentication subkey */
- CTR_cipher( tag, 8, crtxt, crtxtLen, pntxt );
- Polyval( H, aData, pntxt, aDataLen, crtxtLen, P );
- GSIVtag( nonce, P, P );
+ GCM_SIVsetup( key, nonce, H ); /* get authentication subkey */
+ CTR_cipher( tag, SIVGCM_CTR, crtxt, crtxtLen, pntxt );
+ polyval( H, aData, pntxt, aDataLen, crtxtLen, P );
+ GCM_SIVtag( nonce, P, P );
BURN( RoundKey );
- if (MISMATCH( P, tag, sizeof P ))
+ if (memcmp_s( tag, P, SIVGCM_TAG_LEN ))
{ /* tag verification failed */
SABOTAGE( pntxt, crtxtLen );
return M_AUTHENTICATION_ERROR;
@@ -1521,17 +1520,24 @@ char GCM_SIV_decrypt( const uint8_t* key, const uint8_t* nonce,
EAX-AES (encrypt-then-authenticate-then-translate): OMAC & main functions
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(EAX)
+#if EAXP
+#define GFDOUBLE doubleLblock
+#else
+#define GFDOUBLE doubleBblock
+#define nonceLen EAX_NONCE_LEN
+#endif
/** this function calculates the OMAC of a data array using D (K1) and Q (K2) */
-static void OMac( const uint8_t t, const block_t D, const block_t 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 )
{
#if EAXP
- const uint8_t zero_mac = t && !dataSize, *K = t ? Q : D;
-
- zero_mac ? memset( mac, 0, BLOCKSIZE ) : memcpy( mac, K, BLOCKSIZE );
-
- if (zero_mac) return; /* ignoring null ciphertext */
+ if (!dataSize && t)
+ {
+ memset( mac, 0, BLOCKSIZE );
+ return; /* ignoring null ciphertext */
+ }
+ memcpy( mac, t ? Q : D, BLOCKSIZE );
#else
dataSize ? memset( mac, 0, BLOCKSIZE ) : memcpy( mac, D, BLOCKSIZE );
@@ -1546,46 +1552,46 @@ static void OMac( const uint8_t t, const block_t D, const block_t Q,
/**
* @brief encrypt the input plaintext using EAX-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
- * @param nonce a.k.a init-vector with EAX_NONCE_LEN bytes unless EAX'
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
+ * @param nonce initialization vector with EAX_NONCE_LEN bytes unless EAX'
* @param nonceLen size of the nonce byte array; should be non-zero in EAX'
* @param aData additional authentication data; for EAX only, not EAX'
* @param aDataLen size of additional authentication data
- * @param crtxt resulting cipher-text buffer; 4 bytes mac appended in EAX'
- * @param auTag authentication tag; buffer must be 16 bytes long in EAX
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
+ * @param crtxt ciphertext result + auth. tag (4 bytes mac in EAX')
*/
void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* pntxt, const size_t ptextLen,
#if EAXP
-#define FDOUBLE_T &doubleLblock
- const size_t nonceLen, uint8_t* crtxt )
+ const size_t nonceLen,
#else
-#define FDOUBLE_T &doubleBblock
-#define nonceLen EAX_NONCE_LEN
- const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, block_t auTag )
+ const void* aData, const size_t aDataLen,
#endif
+ const void* pntxt, const size_t ptextLen, void* crtxt )
{
block_t D = { 0 }, Q, mac;
+#if !EAXP
+ block_t tag;
+#endif
+ uint8_t* auth = (uint8_t*) crtxt + ptextLen;
- getSubkeys( FDOUBLE_T, 1, key, D, Q );
- OMac( 0, D, Q, nonce, nonceLen, mac ); /* N = OMAC(0; nonce) */
+ getSubkeys( &GFDOUBLE, 1, key, D, Q );
+ oMac( 0, D, Q, nonce, nonceLen, mac ); /* N = OMAC(0; nonce) */
#if EAXP
- COPYDWORD( mac[12], crtxt[ptextLen] );
- mac[12] &= 0x7F;
- mac[14] &= 0x7F; /* clear 2 bits to get N' */
+ COPYDWORD( mac[12], *auth );
+ mac[12] &= 0x7F; /* clear 2 bits to get N' */
+ mac[14] &= 0x7F;
+#endif
+ CTR_cipher( mac, CTR_DEFAULT, pntxt, ptextLen, crtxt );
- CTR_cipher( mac, 0, pntxt, ptextLen, crtxt );
- OMac( 2, D, Q, crtxt, ptextLen, mac ); /* C' = CMAC'( ciphertext ) */
- XOR32BITS( mac[12], crtxt[ptextLen] ); /* tag (a.k.a mac) = N ^ C' */
+#if EAXP
+ oMac( 2, D, Q, crtxt, ptextLen, mac ); /* C' = CMAC'( ciphertext ) */
+ XOR32BITS( mac[12], *auth ); /* tag (mac) = N ^ C' */
#else
- OMac( 1, D, Q, aData, aDataLen, auTag ); /* H = OMAC(1; adata) */
- xorBlock( mac, auTag );
-
- CTR_cipher( mac, 0, pntxt, ptextLen, crtxt );
- OMac( 2, D, Q, crtxt, ptextLen, mac ); /* C = OMAC(2; ciphertext) */
- xorBlock( mac, auTag ); /* tag = N ^ H ^ C */
+ oMac( 1, D, Q, aData, aDataLen, tag ); /* H = OMAC(1; adata) */
+ xorBlock( mac, tag );
+ oMac( 2, D, Q, crtxt, ptextLen, mac ); /* C = OMAC(2; ciphertext) */
+ xorBlock( mac, tag ); /* tag = N ^ H ^ C */
+ memcpy( auth, tag, EAX_TAG_LEN );
#endif
BURN( RoundKey );
}
@@ -1593,52 +1599,49 @@ void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
/**
* @brief decrypt the input ciphertext using EAX-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
- * @param nonce a.k.a init-vector with EAX_NONCE_LEN bytes unless EAX'
- * @param crtxt input cipher-text buffer + appended authentication tag
- * @param crtxtLen size of cipher-text; excluding tag / 4-bytes mac in EAX'
+ * @param nonce initialization vector with EAX_NONCE_LEN bytes unless EAX'
* @param nonceLen size of the nonce byte array; should be non-zero in EAX'
* @param aData additional authentication data; for EAX only, not EAX'
* @param aDataLen size of additional authentication data
- * @param tagLen length of authentication tag; mandatory 4 bytes in EAX'
+ * @param crtxt input cipher-text buffer + appended authentication tag
+ * @param crtxtLen size of cipher-text; excluding tag / 4-bytes mac in EAX'
* @param pntxt resulting plaintext buffer
* @return whether message authentication/decryption was successful
*/
char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* crtxt, const size_t crtxtLen,
#if EAXP
const size_t nonceLen,
#else
- const uint8_t* aData, const size_t aDataLen,
- const uint8_t tagLen,
+ const void* aData, const size_t aDataLen,
#endif
- uint8_t* pntxt )
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
block_t D = { 0 }, Q, mac, tag;
+ uint8_t const* auth = (uint8_t*) crtxt + crtxtLen;
- getSubkeys( FDOUBLE_T, 1, key, D, Q );
- OMac( 2, D, Q, crtxt, crtxtLen, tag ); /* C = OMAC(2; ciphertext) */
+ getSubkeys( &GFDOUBLE, 1, key, D, Q );
+ oMac( 2, D, Q, crtxt, crtxtLen, tag ); /* C = OMAC(2; ciphertext) */
#if EAXP
- OMac( 0, D, Q, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
- XOR32BITS( crtxt[crtxtLen], tag[12] );
+ oMac( 0, D, Q, nonce, nonceLen, mac ); /* N = CMAC'( nonce ) */
+ XOR32BITS( auth[0], tag[12] );
XOR32BITS( mac[12], tag[12] );
mac[12] &= 0x7F;
mac[14] &= 0x7F; /* clear 2 bits to get N' */
if (*(int32_t*) &tag[12] != 0) /* result of mac validation */
#else
- OMac( 1, D, Q, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
+ oMac( 1, D, Q, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
xorBlock( mac, tag );
- OMac( 0, D, Q, nonce, nonceLen, mac ); /* N = OMAC(0; nonce) */
+ oMac( 0, D, Q, nonce, nonceLen, mac ); /* N = OMAC(0; nonce) */
xorBlock( mac, tag ); /* tag = N ^ H ^ C */
- #undef nonceLen
- if (MISMATCH( tag, crtxt + crtxtLen, tagLen ))
+ if (memcmp_s( auth, tag, EAX_TAG_LEN ))
#endif
{ /* authenticate then decrypt */
BURN( RoundKey );
return M_AUTHENTICATION_ERROR;
}
- CTR_cipher( mac, 0, crtxt, crtxtLen, pntxt );
+ CTR_cipher( mac, CTR_DEFAULT, crtxt, crtxtLen, pntxt );
BURN( RoundKey );
return M_RESULT_SUCCESS;
}
@@ -1659,20 +1662,20 @@ static void nop( const block_t x, block_t y ) {}
static void getDelta( const count_t index,
const block_t Ld, const block_t delta0, block_t delta )
{
- count_t r, b = 1;
- block_t L;
+ count_t mask, bit = 1;
+ block_t L; /* Δ_i = Δ_{i-1} ^ L_ntz(i) */
memcpy( L, Ld, sizeof L ); /* initialize L_$ and Δ */
memcpy( delta, delta0, BLOCKSIZE );
- while ((r = index - b) < index) /* Δ_i = Δ_{i-1} ^ L_ntz(i) */
- { /* where: */
- doubleBblock( L ); /* L_0 = double( L_$ ) */
- b *= 2; /* L_k = double( L_{k-1} ) */
-
- if (r & b) continue;
-
- xorBlock( L, delta );
+ while ((mask = index - bit) < index)
+ { /* L_0 = double( L_$ ), */
+ doubleBblock( L ); /* L_k = double( L_{k-1} ) */
+ mask &= bit <<= 1;
+ if (!mask)
+ {
+ xorBlock( L, delta );
+ }
}
}
@@ -1680,56 +1683,55 @@ static void getDelta( const count_t index,
* @brief encrypt or decrypt the data using OCB method
* @param key encryption or decryption key
* @param nonce byte array with a fixed size of OCB_NONCE_LEN
- * @param ptLen size of plaintext. ptLen = dataSize, only in encryption
- * @param aDataLen size of additional authentication data
+ * @param ptextLen size of input 'plain'text; will be zero in decryption
* @param aData additional authentication data
+ * @param aDataLen size of additional authentication data
* @param dataSize size of input data, to be encrypted/decrypted
* @param data result of encryption/decryption process
* @param tag calculated tag from plaintext checksum, and PMAC of aData
*/
static void OCB_cipher( const uint8_t* key, const uint8_t* nonce,
- const size_t ptLen,
- const size_t aDataLen, const void* aData,
+ const size_t ptextLen,
+ const void* aData, const size_t aDataLen,
const size_t dataSize, void* data, block_t tag )
{
- fmix_t cipher = ptLen ? &rijndaelEncrypt : &rijndaelDecrypt;
+ fmix_t cipher = ptextLen ? &rijndaelEncrypt : &rijndaelDecrypt;
block_t offset[4] = { { 0 } }; /* [L_$] [L_*] [Ktop] [Δ_n] */
- uint8_t *y = data;
+ uint8_t *y;
uint8_t *Ld = offset[0], *Ls = offset[1], *kt = offset[2], *del = offset[3];
- count_t i, n = nonce[OCB_NONCE_LEN - 1] % 64;
- uint8_t const s = 8 - n % 8, *a = aData;
+ count_t n = nonce[OCB_NONCE_LEN - 1] % 64, i;
+ uint8_t const s = 8 - n % 8, *x = kt + n / 8;
memcpy( kt + BLOCKSIZE - OCB_NONCE_LEN, nonce, OCB_NONCE_LEN );
- kt[0] = OCB_TAG_LEN << 4 & 0xFF;
- kt[LAST - OCB_NONCE_LEN] |= 1; /* set one and clear last 6 */
- kt[LAST] &= 0xC0; /* .. bits of nonce (kt) */
+ kt[0 ] |= OCB_TAG_LEN << 4;
+ kt[LAST - OCB_NONCE_LEN] |= 1; /* set one and clear last */
+ kt[LAST] &= 0xC0; /* ..six bits of nonce (kt) */
getSubkeys( &doubleBblock, 0, key, Ls, Ld );
rijndaelEncrypt( kt, kt ); /* construct K_top */
- memcpy( del, kt + 1, 8 ); /* stretch K_top */
- xorBlock( kt, del );
-
- n /= 8;
- for (i = 0; i < BLOCKSIZE; ++i, ++n) /* shift the stretched K_top */
+ memcpy( del, kt + 1, HB ); /* stretch K_top */
+ for (i = 0; i < BLOCKSIZE; ++i)
{
- kt[i] = (kt[n] << 8 | kt[n + 1]) >> s;
+ del[i] ^= kt[i];
+ kt[i] = (x[i] << 8 | x[i + 1]) >> s; /* shift the stretched K_top */
}
- xMac( data, ptLen, NULL, &nop, tag ); /* get plaintext? checksum */
+ xMac( data, ptextLen, NULL, &nop, tag ); /* get plaintext? checksum */
+ i = 0, n = dataSize / BLOCKSIZE;
- if ((n = dataSize / BLOCKSIZE) == 0)
- {
- del = kt; /* Δ_N = Δ_0 = K_top */
- kt = offset[3];
- }
- for (i = 0; i++ < n; y += BLOCKSIZE)
+ for (y = data; i < n; y += BLOCKSIZE)
{ /* calculate Δ_i using */
- getDelta( i, Ld, kt, del ); /* .. my 'magic' algorithm */
+ getDelta( ++i, Ld, kt, del ); /* ..my 'magic' algorithm */
xorBlock( del, y );
cipher( y, y );
xorBlock( del, y ); /* Y = Δ_i ^ Cipher(Δ_i ^ X) */
}
+ if (n == 0)
+ {
+ del = kt; /* Δ_N = Δ_0 = K_top */
+ kt = offset[3];
+ }
if ((i = dataSize % BLOCKSIZE) != 0)
{ /* Y_* = Enc(L_* ^ Δ_N) ^ X */
tag[i] ^= 0x80; /* and pad X_* or checksum */
@@ -1737,15 +1739,15 @@ static void OCB_cipher( const uint8_t* key, const uint8_t* nonce,
mixThenXor( &rijndaelEncrypt, del, kt, y, i, y );
}
- xMac( data, dataSize - ptLen, NULL, &nop, tag );
+ xMac( data, dataSize - ptextLen, NULL, &nop, tag );
cMac( Ld, NULL, del, BLOCKSIZE, tag );
/*- tag = Enc( checksum ^ Δ_* ^ L_$ ) so far. next, add "PMAC" of aData: **/
- n = aDataLen / BLOCKSIZE;
+ i = 0, n = aDataLen / BLOCKSIZE;
- for (i = 0; i < n; a += BLOCKSIZE)
+ for (x = aData; i < n; x += BLOCKSIZE)
{
- getDelta( ++i, Ld, a, del );
+ getDelta( ++i, Ld, x, del );
rijndaelEncrypt( del, del ); /* Δ = Enc( A_i ^ Δ_i ) */
xorBlock( del, tag ); /* add Δ to the tag */
}
@@ -1753,7 +1755,7 @@ static void OCB_cipher( const uint8_t* key, const uint8_t* nonce,
{
memset( kt, 0, BLOCKSIZE );
getDelta( n, Ld, kt, del );
- cMac( NULL, Ls, a, i, del ); /* Δ = Enc(L_* ^ A_* ^ Δ_N) */
+ cMac( NULL, Ls, x, i, del ); /* Δ = Enc(L_* ^ A_* ^ Δ_N) */
xorBlock( del, tag ); /* add Δ to the tag */
}
BURN( RoundKey );
@@ -1763,50 +1765,46 @@ static void OCB_cipher( const uint8_t* key, const uint8_t* nonce,
* @brief encrypt the input stream using OCB-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
* @param nonce a.k.a initialization vector with fixed size: OCB_NONCE_LEN
- * @param pntxt input plain-text buffer
- * @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param crtxt resulting cipher-text buffer
- * @param auTag message authentication tag
+ * @param pntxt input plain-text buffer
+ * @param ptextLen size of plaintext in bytes
+ * @param crtxt resulting cipher-text buffer + message authentication tag
*/
void AES_OCB_encrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* pntxt, const size_t ptextLen,
- const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, uint8_t* auTag )
+ const void* aData, const size_t aDataLen,
+ const void* pntxt, const size_t ptextLen, void* crtxt )
{
block_t tag = { 0 };
- memcpy( crtxt, pntxt, ptextLen ); /* doing in-place encryption */
+ uint8_t* auth = (uint8_t*) crtxt + ptextLen;
- OCB_cipher( key, nonce, ptextLen, aDataLen, aData, ptextLen, crtxt, tag );
- memcpy( auTag, tag, OCB_TAG_LEN );
+ memcpy( crtxt, pntxt, ptextLen ); /* doing in-place encryption */
+ OCB_cipher( key, nonce, ptextLen, aData, aDataLen, ptextLen, crtxt, tag );
+ memcpy( auth, tag, OCB_TAG_LEN );
}
/**
* @brief decrypt the input stream using OCB-AES block-cipher method
* @param key decryption key with a fixed size specified by KEYSIZE
* @param nonce a.k.a initialization vector with fixed size: OCB_NONCE_LEN
- * @param crtxt input cipher-text buffer + appended authentication tag
- * @param crtxtLen size of ciphertext, excluding tag
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param tagLen length of authentication tag
+ * @param crtxt input cipher-text buffer + appended authentication tag
+ * @param crtxtLen size of ciphertext, excluding tag
* @param pntxt resulting plaintext buffer
* @return whether message decryption/authentication was successful
*/
char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
- const uint8_t* crtxt, const size_t crtxtLen,
- const uint8_t* aData, const size_t aDataLen,
- const uint8_t tagLen, uint8_t* pntxt )
+ const void* aData, const size_t aDataLen,
+ const void* crtxt, const size_t crtxtLen, void* pntxt )
{
block_t tag = { 0 };
+ uint8_t const* auth = (uint8_t*) crtxt + crtxtLen;
- if (tagLen != OCB_TAG_LEN) return M_DECRYPTION_ERROR;
+ memcpy( pntxt, crtxt, crtxtLen ); /* doing in-place decryption */
+ OCB_cipher( key, nonce, 0, aData, aDataLen, crtxtLen, pntxt, tag );
- memcpy( pntxt, crtxt, crtxtLen ); /* in-place decryption */
- OCB_cipher( key, nonce, 0, aDataLen, aData, crtxtLen, pntxt, tag );
-
- if (MISMATCH( tag, crtxt + crtxtLen, tagLen ))
+ if (memcmp_s( auth, tag, OCB_TAG_LEN ))
{
SABOTAGE( pntxt, crtxtLen );
return M_AUTHENTICATION_ERROR;
@@ -1821,74 +1819,76 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(KWA)
/**
- * @brief wrap the input secret whose size is a multiple of 8 and >= 16
+ * @brief encrypt the input secret with key-wrapping method
* @param kek key-encryption-key a.k.a master key
- * @param secret input plain text secret
- * @param secretLen size of input, must be a multiple of HB (half-block size)
+ * @param secret input plaintext secret
+ * @param secretLen size of secret in bytes
* @param wrapped wrapped secret, prepended with an additional half-block
* @return error if size is not a multiple of HB, or size < BLOCKSIZE
*/
char AES_KEY_wrap( const uint8_t* kek,
- const void* secret, const size_t secretLen, uint8_t* wrapped )
+ const void* secret, const size_t secretLen, void* wrapped )
{
- size_t i = 0, n = secretLen / HB; /* number of semi-blocks */
+ uint8_t *w = wrapped;
+ uint8_t *r = w + HB, *endpoint = w + secretLen;
block_t A;
- uint8_t *r = wrapped + HB, *endpt = wrapped + secretLen;
+ count_t i, n = secretLen / HB; /* number of semi-blocks */
- if (n < 2 || secretLen % HB) return M_ENCRYPTION_ERROR;
+ if (n < 2 || secretLen % HB) return M_DATALENGTH_ERROR;
memset( A, 0xA6, HB ); /* initialization vector */
- memcpy( r, secret, secretLen ); /* copy input to the output */
+ memcpy( r, secret, secretLen ); /* in-place encryption */
AES_setkey( kek );
- for (n *= 6; i++ < n; )
+ for (i = 0, n *= 6; i++ < n; )
{
- memcpy( A + HB, r, HB );
- rijndaelEncrypt( A, A ); /* A = Enc( V | R_{k-1} ) */
- memcpy( r, A + HB, HB ); /* R_{k} = LSB(64, A) */
- xorBEint( A, i, HB - 1 ); /* V = MSB(64, A) ^ i */
- r = (r == endpt ? wrapped : r) + HB;
+ memcpy( A + HB, r, HB ); /* R = LSB(64, A) */
+ rijndaelEncrypt( A, A ); /* A* = Enc( L | R ) */
+ memcpy( r, A + HB, HB ); /* L* = MSB(64, A*) ^ i */
+ xorBEint( A, i, MIDST );
+ r = (r == endpoint ? w : r) + HB;
}
BURN( RoundKey );
- memcpy( wrapped, A, HB ); /* authentication vector */
+ memcpy( w, A, HB ); /* authentication vector */
return M_RESULT_SUCCESS;
}
/**
- * @brief unwrap a wrapped key input, whose size is a multiple of 8 and >= 24
+ * @brief unwrap/decrypt a wrapped secret according to RFC-3394
* @param kek key-encryption-key a.k.a master key
* @param wrapped cipher-text input, the wrapped secret
* @param wrapLen size of ciphertext/wrapped input in bytes
* @param secret unwrapped secret, which is a half block shorter than input
- * @return a value indicating whether decryption was successful
+ * @return whether decrypting/unwrapping secret was successful
*/
char AES_KEY_unwrap( const uint8_t* kek,
- const void* wrapped, const size_t wrapLen, uint8_t* secret )
+ const void* wrapped, const size_t wrapLen, void* secret )
{
- size_t n = 0, i = wrapLen / HB; /* number of semi-blocks */
+ uint8_t const* w = wrapped;
+ uint8_t *r = secret, *end = (uint8_t*) secret + wrapLen - HB;
block_t A;
- uint8_t *r = secret, *endpt = secret + wrapLen - HB;
+ count_t i, n = wrapLen / HB; /* number of semi-blocks */
- if (i-- < 3 || wrapLen % HB) return M_DECRYPTION_ERROR;
+ if (n < 0x3 || wrapLen % HB) return M_DATALENGTH_ERROR;
- memcpy( A, wrapped, HB );
- memcpy( r, (char*) wrapped + HB, wrapLen - HB );
+ memcpy( A, w, HB );
+ memcpy( r, w + HB, wrapLen - HB ); /* in-place decryption */
AES_setkey( kek );
- for (i *= 6; i; --i)
+ for (--n, i = n * 6; i; --i)
{
- r = (r == secret ? endpt : r) - HB;
- xorBEint( A, i, HB - 1 ); /* V = MSB(64, A) ^ i */
- memcpy( A + HB, r, HB ); /* A = Dec( V | R_{k} ) */
- rijndaelDecrypt( A, A ); /* R_{k-1} = LSB(64, A) */
- memcpy( r, A + HB, HB );
+ r = (r == secret ? end : r) - HB;
+ xorBEint( A, i, MIDST );
+ memcpy( A + HB, r, HB ); /* L = MSB(64, A) ^ i */
+ rijndaelDecrypt( A, A ); /* A* = Dec( L | R ) */
+ memcpy( r, A + HB, HB ); /* R* = LSB(64, A*) */
}
BURN( RoundKey );
- while (i < HB) /* authenticate/error check */
+ for (n = 0, i = HB; i--; ) /* authenticate/error-check */
{
- n |= A[i++] ^ 0xA6;
+ n |= A[i] - 0xA6;
}
return n ? M_AUTHENTICATION_ERROR : M_RESULT_SUCCESS;
}
@@ -1916,7 +1916,7 @@ static void modP1305( uint8_t* block, int32_t q )
{
if (q < 4) return; /* q is block's MSBs: B>>128 */
- block[SP - 1] &= 3; /* get rid of excess bits. */
+ block[PL - 1] &= 3; /* subtract (q >> 2) << 130 */
for (q = (q >> 2) * 5; q; q >>= 8) /* suppose Q = B / (2 ^ 130) */
{ /* ..then "almost" always: */
@@ -1928,16 +1928,16 @@ static void modP1305( uint8_t* block, int32_t q )
/** modular multiplication of two little-endian poly1305 blocks: y *= x mod P */
static void mulLblocks( const uint8_t* x, uint8_t* y )
{
- uint8_t n = SP, result[SP] = { 0 };
- while (n--) /* Y = [Y_0][Y_1]...[Y_n], */
- {
+ uint8_t n = PL, result[PL] = { 0 };
+ while (n--)
+ { /* Y = [Y_0][Y_1]...[Y_16], */
uint8_t s = 8 * (n != 0), i; /* multiply X by MSB of Y */
- int32_t m = 0; /* ..and add to the result */
+ int32_t m = 0, y_n = y[n]; /* ..and add to the result */
for (i = 0; i < sizeof result; ++i) /* if Y has another byte in */
{ /* ..queue, shift the result */
m >>= 8; /* ..but don't shift for Y_0 */
- m += (y[n] * x[i] + result[i]) << s;
+ m += (y_n * x[i] + result[i]) << s;
result[i] = (uint8_t) m;
}
modP1305( result, m ); /* modular multiplication */
@@ -1956,7 +1956,7 @@ static void mulLblocks( const uint8_t* x, uint8_t* y )
void AES_Poly1305( const uint8_t* keys, const block_t nonce,
const void* data, const size_t dataSize, block_t mac )
{
- uint8_t r[SP], rk[SP] = { 1 }, c[SP] = { 0 }, poly[SP] = { 0 }, s = SP - 1;
+ uint8_t r[PL], rk[PL] = { 1 }, c[PL] = { 0 }, poly[PL] = { 0 }, s = PL - 1;
count_t q = (dataSize - 1) / BLOCKSIZE;
const char* pos = (const char*) data + dataSize;
@@ -1977,11 +1977,11 @@ void AES_Poly1305( const uint8_t* keys, const block_t nonce,
{
memcpy( c, pos -= s, s ); /* copy message to chunk */
c[s] = 1; /* append 1 to each chunk */
+ s = BLOCKSIZE;
mulLblocks( r, rk ); /* r^k = r^{k-1} * r */
mulLblocks( rk, c ); /* calculate c_{q-k} * r^k */
- addLblocks( c, SP, poly ); /* ..and add it to poly, */
- s = SP - 1; /* ..then take mod(2^130-5) */
- modP1305( poly, poly[s] );
+ addLblocks( c, PL, poly ); /* ..and add it to poly, */
+ modP1305( poly, poly[s] ); /* ..then take mod(2^130-5) */
} while (q--);
@@ -2006,113 +2006,122 @@ void AES_Poly1305( const uint8_t* keys, const block_t nonce,
#include "micro_fpe.h"
#else
#define ALPHABET "0123456789"
-#define string_t char* /* string pointer type */
#define RADIX 10 /* strlen (ALPHABET) */
#define LOGRDX 3.32192809488736 /* log2 (RADIX) */
#define MINLEN 6 /* ceil (6 / log10 (RADIX)) */
-#define MAXLEN 0x38 /* only if FF_X == 3 */
+#define MAXLEN 56 /* only if FF_X == 3 */
#endif
-#if RADIX - 1 <= UCHAR_MAX
-typedef unsigned char rbase_t; /* digit type in base-radix */
+#if ALPHABET_IS_NON_ASCII
+typedef wchar_t alpha_t;
#else
-typedef unsigned short rbase_t;
+typedef char alpha_t; /* type of plain/ciphertext */
#endif
-#if FF_X != 3 /* FF1 method: */
+#if RADIX <= 1 + UCHAR_MAX
+typedef unsigned char radix_t; /* digit type in base-radix */
+#else
+typedef unsigned short radix_t;
+#endif
-static size_t bb; /* the b constant in FF1 */
+#if FF_X == 3 /* FF3 'tweakLen' is fixed */
+#define FPE_PERMUTE FF3_cipher
+#define TWEAK_PARAMS uint8_t* tweak
+#define TWEAK_AGRS tweak
+#else /* FF1 implementation: */
+#define FPE_PERMUTE FF1_cipher
+#define TWEAK_PARAMS uint8_t* tweak, const size_t tweakLen
+#define TWEAK_AGRS tweak, tweakLen
-/** convert a string `s` in base-RADIX to a big-endian number, denoted by num */
-static void numRadix( const rbase_t* s, size_t len, uint8_t* num, size_t bytes )
+static size_t b1; /* the b constant in FF1 */
+
+/** convert the string s in base-RADIX to a big-endian number, denoted by num */
+static void numRadix( const radix_t* s, size_t len, uint8_t* num, size_t bytes )
{
memset( num, 0, bytes );
while (len--)
- {
- size_t i, y = *s++;
+ { /* we can reasonably assume */
+ size_t i, y = *s++; /* .. RADIX^2 <= SIZE_MAX+1 */
for (i = bytes; i--; y >>= 8)
{
- y += num[i] * RADIX; /* num = num * RADIX + y */
- num[i] = (uint8_t) y;
+ y += num[i] * RADIX;
+ num[i] = (uint8_t) y; /* num = num * RADIX + y */
}
}
}
-/** convert a big-endian number to its base-RADIX representation string: `s`. */
-static void strRadix( const uint8_t* num, size_t bytes, rbase_t* s, size_t len )
+/** convert a big-endian number to string s, its representation in base-RADIX */
+static void strRadix( const uint8_t* num, size_t bytes, radix_t* s, size_t len )
{
- memset( s, 0, sizeof (rbase_t) * len );
+ memset( s, 0, sizeof (radix_t) * len );
while (bytes--)
{
size_t i, x = *num++;
for (i = len; i--; x /= RADIX)
{
- x += s[i] << 8; /* numstr = numstr << 8 + x */
+ x += s[i] << 8; /* str = (str << 8) + x */
s[i] = x % RADIX;
}
}
}
-/** add two numbers in base-RADIX represented by q and p, so that: p = p + q; */
-static void addRadix( const rbase_t* q, const size_t len, rbase_t* p )
+/** add two numbers x, y in base-RADIX and save the result in y, i.e. y += x; */
+static void addRadix( const radix_t* x, const size_t len, radix_t* y )
{
size_t i, a = 0;
for (i = len; i--; a /= RADIX) /* big-endian addition */
{
- a += p[i] + q[i]; /* a /= RADIX is equivalent */
- p[i] = a % RADIX; /* ..to: a = (a >= RADIX) */
+ a += y[i] + x[i]; /* a /= RADIX is equivalent */
+ y[i] = a % RADIX; /* ..to: a = (a >= RADIX) */
}
}
-/** subtract two numbers in base-RADIX represented by q and p, so that p -= q */
-static void subRadix( const rbase_t* q, const size_t len, rbase_t* p )
+/** subtract two numbers in base-RADIX and save the result in y, i.e. y -= x; */
+static void subRadix( const radix_t* x, const size_t len, radix_t* y )
{
size_t i, s = 1;
for (i = len; i--; s /= RADIX) /* big-endian subtraction */
{
- s += RADIX - 1 + p[i] - q[i];
- p[i] = s % RADIX;
+ s += RADIX - 1 + y[i] - x[i];
+ y[i] = s % RADIX;
}
}
/** derive C at step i of FF1 rounds, given the values: u, v and PRF_init = P */
static void FF1round( const uint8_t i, const block_t P,
- const size_t u, const size_t v, rbase_t* C )
+ const size_t u, const size_t v, radix_t* C )
{
- uint8_t* num = (void*) (C + u); /* use pre-allocated memory */
block_t R = { 0 };
- size_t k = bb % sizeof R, ext = (i & 1) * u;
+ uint8_t* num = (uint8_t*) &C[u]; /* use pre-allocated memory, */
+ size_t k = b1 % sizeof R, ext = (i & 1) * u;
- numRadix( C - v - ext, v, num, bb ); /* ..to get NUM_radix(B) */
- R[LAST - k] = i;
+ numRadix( C - v - ext, v, num, b1 ); /* ..to get NUM_radix(B) */
+ num[-1] = i;
+ memcpy( R + LAST - k, num - 1, k + 1 ); /* feed NUM_radix to the PRF */
- memcpy( R - k + sizeof R, num, k ); /* feed NUM_radix to the PRF */
xMac( P, BLOCKSIZE, R, &rijndaelEncrypt, R );
- xMac( num + k, bb - k, R, &rijndaelEncrypt, R );
+ xMac( num + k, b1 - k, R, &rijndaelEncrypt, R );
memcpy( num, R, sizeof R ); /* R = PRF(P || Q) */
- k = (bb + 3L) / sizeof R; /* total additional blocks */
+ k = (b1 + 3L) / sizeof R; /* total additional blocks */
for (ext = 0; k; ext = k--)
{ /* S = R | Enc(R ^[k]) | ... */
- ext ^= k;
- xorBEint( R, ext, LAST );
+ xorBEint( R, ext ^ k, LAST );
rijndaelEncrypt( R, num + k * sizeof R );
}
- strRadix( num, (bb + 7) & ~3L, C, u ); /* take first 'd' bytes of S */
+ strRadix( num, (b1 + 7) & ~3L, C, u ); /* take first 'd' bytes of S */
}
/** encrypt/decrypt a base-RADIX string X with length len using FF1 algorithm */
-static void FF1_cipher( const uint8_t* key, const char mode, const size_t len,
- const uint8_t* tweak, const size_t tweakLen,
- rbase_t* X )
+static void FF1_cipher( const uint8_t* key, const char mode,
+ const TWEAK_PARAMS, const size_t len, radix_t* X )
{
size_t u = (len + !mode) / 2, t = tweakLen;
- rbase_t* Xc = X + len;
+ radix_t* xC = X + len;
block_t P = { 1, 2, 1, RADIX >> 16, RADIX >> 8 & 0xFF, RADIX & 0xFF, 10 };
- uint8_t i = t % BLOCKSIZE;
+ uint8_t i = t % sizeof P + b1 % sizeof P < BLOCKSIZE ? t % sizeof P : 0;
- i *= i <= (uint8_t) ~bb % BLOCKSIZE; /* if i > (t+bb)%16 : i = 0 */
AES_setkey( key );
P[7] ^= len / 2; /* initializing P block */
@@ -2125,75 +2134,76 @@ static void FF1_cipher( const uint8_t* key, const char mode, const size_t len,
{
P[--i] ^= tweak[--t];
}
- for (; i < 10 * mode; u = len - u) /* Feistel procedure */
+ for (; i < 10 * mode; ++i, u = t) /* Feistel procedure */
{ /* encryption rounds */
- FF1round( i++, P, u, len - u, Xc );
- addRadix( Xc, u, i & 1 ? X : Xc - u ); /* add C to A then swap A,B */
+ FF1round( i, P, u, t = len - u, xC );
+ addRadix( xC, u, X + (i & 1) * t ); /* add C to A then swap A,B */
}
- for (i ^= 10; i != 0; u = len - u) /* decryption rounds */
+ for (i ^= 10; i-- != 0x00; u = t) /* decryption rounds */
{
- FF1round( --i, P, u, len - u, Xc );
- subRadix( Xc, u, i & 1 ? Xc - u : X ); /* subtract C from A */
+ FF1round( i, P, u, t = len - u, xC );
+ subRadix( xC, u, X + (i & 1) * t ); /* subtract C from A */
}
- BURN( RoundKey );
}
-#else /* FF3/FF3-1 method: */
+#endif /* FF1 */
+
+#if FF_X == 3 /* FF3/FF3-1 method: */
/** converts a string in base-RADIX to a little-endian number, denoted by num */
-static void numRadix( const rbase_t* s, uint8_t len, uint8_t* num, uint8_t bytes )
+static void numRadix( const radix_t* s, uint8_t len, uint8_t* num, char bytes )
{
memset( num, 0, bytes );
while (len--)
{
- size_t i, d = s[len];
- for (i = 0; i < bytes; d >>= 8)
+ size_t i, y = s[len];
+ for (i = 0; i < bytes; y >>= 8) /* bytes = 12 "always" */
{
- d += num[i] * RADIX; /* num = num * RADIX + d */
- num[i++] = (uint8_t) d;
+ y += num[i] * RADIX;
+ num[i++] = (uint8_t) y; /* num = num * RADIX + y */
}
}
}
/** convert a little-endian number to its base-RADIX representation string: s */
-static void strRadix( const uint8_t* num, uint8_t bytes, rbase_t* s, uint8_t len )
+static void strRadix( const uint8_t* num, char bytes, radix_t* s, uint8_t len )
{
- memset( s, 0, sizeof (rbase_t) * len );
+ memset( s, 0, sizeof (radix_t) * len );
while (bytes--)
{
- size_t i, b = num[bytes];
- for (i = 0; i < len; b /= RADIX)
+ size_t i, x = num[bytes];
+ for (i = 0; i < len; x /= RADIX)
{
- b += s[i] << 8; /* numstr = numstr << 8 + b */
- s[i++] = b % RADIX;
+ x += s[i] << 8; /* str = (str << 8) + x */
+ s[i++] = x % RADIX;
}
}
}
-/** add two numbers in base-RADIX represented by q and p, so that: p = p + q; */
-static void addRadix( const rbase_t* q, const uint8_t len, rbase_t* p )
+/** add two numbers x, y in base-RADIX and save the result in y, i.e. y += x; */
+static void addRadix( const radix_t* x, const uint8_t len, radix_t* y )
{
size_t i, a = 0;
for (i = 0; i < len; a /= RADIX) /* little-endian addition */
{
- a += p[i] + q[i];
- p[i++] = a % RADIX;
+ a += y[i] + x[i];
+ y[i++] = a % RADIX;
}
}
-/** subtract two numbers in base-RADIX represented by q and p, so that p -= q */
-static void subRadix( const rbase_t* q, const uint8_t len, rbase_t* p )
+/** subtract two numbers in base-RADIX and save the result in y, i.e. y -= x; */
+static void subRadix( const radix_t* x, const uint8_t len, radix_t* y )
{
size_t i, s = 1;
for (i = 0; i < len; s /= RADIX) /* little-endian subtraction */
{
- s += RADIX - 1 + p[i] - q[i];
- p[i++] = s % RADIX;
+ s += RADIX - 1 + y[i] - x[i];
+ y[i++] = s % RADIX;
}
}
/** calculate C at step i of FF3 rounds, given the values: u, v and tweak (T) */
static void FF3round( const uint8_t i, const uint8_t* T,
- const uint8_t u, const uint8_t v, rbase_t* C )
+ const uint8_t u, const uint8_t v, radix_t* C )
{
uint8_t w = (i & 1) * 4, ext = (i & 1) * u;
block_t P;
@@ -2206,17 +2216,18 @@ static void FF3round( const uint8_t i, const uint8_t* T,
}
/** encrypt/decrypt a base-RADIX string X with size len using FF3-1 algorithm */
-static void FF3_cipher( const uint8_t* key, const char mode, const uint8_t len,
- const uint8_t* tweak, rbase_t* X )
+static void FF3_cipher( const uint8_t* key, const char mode,
+ const TWEAK_PARAMS, const size_t len, radix_t* X )
{
- rbase_t* Xc = X + len;
- uint8_t T[8], u = (len + mode) / 2, *k = (void*) Xc, i;
+ radix_t* xC = X + len;
+ uint8_t T[8], u = (len + mode) / 2, v, i, *k = (void*) xC;
memcpy( k, tweak, FF3_TWEAK_LEN );
-#if FF3_TWEAK_LEN == 7
- k[7] = (uint8_t) (k[3] << 4); /* see the comments at the */
- k[3] &= 0xF0; /* ..bottom of header file */
-#endif
+ if (FF3_TWEAK_LEN == 7) /* FF3 vs. FF3-1 */
+ {
+ k[7] = (uint8_t) (k[3] << 4);
+ k[3] &= 0xF0;
+ }
for (i = 8; i --> 0; ) T[7 - i] = k[i];
for (i = KEYSIZE; i; ) k[--i] = *key++; /* key/tweak are reversed */
@@ -2224,69 +2235,84 @@ static void FF3_cipher( const uint8_t* key, const char mode, const uint8_t len,
AES_setkey( k );
SABOTAGE( k, KEYSIZE );
- for (; i < 8 * mode; u = len - u) /* Feistel procedure */
+ for (; i < 8 * mode; ++i, u = v) /* Feistel procedure */
{ /* encryption rounds */
- FF3round( i++, T, u, len - u, Xc );
- addRadix( Xc, u, i & 1 ? X : Xc - u ); /* add C to A then swap A,B */
+ FF3round( i, T, u, v = len - u, xC );
+ addRadix( xC, u, X + (i & 1) * v ); /* add C to A then swap A,B */
}
- for (i ^= 8; i != 0; u = len - u) /* decryption rounds */
+ for (i ^= 8; i-- != 0x00; u = v) /* decryption rounds */
{
- FF3round( --i, T, u, len - u, Xc );
- subRadix( Xc, u, i & 1 ? Xc - u : X );
+ FF3round( i, T, u, v = len - u, xC );
+ subRadix( xC, u, X + (i & 1) * v );
}
- BURN( RoundKey );
}
-#endif /* FF_X */
+#endif /* FF3 */
/*----------------------------------------------------------------------------*\
FPE-AES: main functions
\*----------------------------------------------------------------------------*/
#include
-/** allocate the required memory and validate the input string in FPE mode... */
-static char FPEinit( const string_t str, const size_t len, rbase_t** idx )
+/**
+ * @brief encrypt or decrypt the input string with FPE method
+ * @param key encryption or decryption key
+ * @param mode mode of operation: encrypting (1) or decrypting (0)
+ * @param tweak tweak byte array
+ * @param tweakLen size of tweak. must be exactly 7 in FF3-1
+ * @param input input string, consisted of characters in ALPHABET
+ * @param dataSize length of the string, or its number of characters
+ * @param output result of format-preserved encryption/decryption
+ * @return error character if failed, or '\0' if ended in success
+ */
+static char FPE_cipher( const uint8_t* key, const char mode, const TWEAK_PARAMS,
+ const void* input, const size_t dataSize, void* output )
{
- const string_t alpha = ALPHABET;
- size_t u = (len + 1) / 2;
- size_t n = (len + u) * sizeof (rbase_t);
+ size_t v = (dataSize + 1) / 2;
+ size_t n = (dataSize + v) * sizeof (radix_t);
+ alpha_t const* alpha = ALPHABET;
+ alpha_t* y = output;
+ radix_t* index;
-#if FF_X != 3 /* extra memory is needed.. */
- bb = (size_t) (LOGRDX * u + 8 - 1e-14) / 8; /* to store NUM_radix and.. */
- n += (bb + 4 + LAST) & ~LAST; /* mix it in Feistel rounds */
-#else
- u *= len > MAXLEN ? 0 : sizeof (rbase_t);
- n += u >= KEYSIZE ? 0 : KEYSIZE - u;
+ if (dataSize < MINLEN) return 'l';
+#if FF_X == 3
+ if (dataSize > MAXLEN) return 'L';
+
+ v *= sizeof (radix_t);
+ n += v < KEYSIZE ? KEYSIZE - v : 0;
+#else /* extra memory is needed.. */
+ b1 = (size_t) (LOGRDX * v + 8 - 1e-14) / 8; /* to store NUM_radix and.. */
+ n += (b1 + 4 + LAST) & ~LAST; /* mix it in Feistel rounds */
#endif
- if (!(len >= MINLEN && u)) return 'L'; /* invalid string-length */
-
- if (!(*idx = malloc( n ))) return 'M'; /* memory allocation failed */
-
- for (n = len; n--; )
+ if ((index = malloc( n )) == NULL)
{
- for (u = 0; alpha[u] != str[n]; )
+ return 'm'; /* memory allocation failed */
+ }
+ for (n = 0; n < dataSize; ++n) /* find index of each char */
+ {
+ const alpha_t *ch = (alpha_t*) input + n;
+ for (v = 0x0; *ch != alpha[v]; )
{
- if (++u == RADIX)
+ if (++v == RADIX)
{
- free( *idx ); /* invalid character found */
+ free( index ); /* invalid character found */
return 'C';
}
}
- (*idx)[n] = (rbase_t) u;
+ *(index + n) = (radix_t) v;
+ } /* now permute the indexes: */
+
+ FPE_PERMUTE( key, mode, TWEAK_AGRS, n, index );
+ BURN( RoundKey );
+
+ for (y[n] = 0; n--; ) /* construct the output as */
+ { /* null-terminated? string */
+ y[n] = alpha[index[n]];
}
+ free( index );
return 0;
}
-/** make the output string after completing the process of FPE en/decryption. */
-static void FPEfinalize( const rbase_t* index, size_t n, void* output )
-{
- const string_t alpha = ALPHABET;
- string_t str = output;
- str[n] = 0; /* null-terminated strings? */
-
- while (n--) str[n] = alpha[index[n]];
-}
-
/**
* @brief encrypt the input string using FPE-AES block-cipher method
* @param key encryption key with a fixed size specified by KEYSIZE
@@ -2295,26 +2321,13 @@ static void FPEfinalize( const rbase_t* index, size_t n, void* output )
* @param pntxt input plaintext string, consisted of ALPHABET characters
* @param ptextLen size of plaintext string, or number of characters
* @param crtxt resulting ciphertext string
- * @return whether all conditions of the algorithm were satisfied
+ * @return whether encryption was successful
*/
-char AES_FPE_encrypt( const uint8_t* key, const uint8_t* tweak,
-#if FF_X != 3
- const size_t tweakLen,
-#endif
+char AES_FPE_encrypt( const uint8_t* key, const TWEAK_PARAMS,
const void* pntxt, const size_t ptextLen, void* crtxt )
{
- rbase_t* index = NULL;
-
- if (FPEinit( pntxt, ptextLen, &index ) != 0) return M_ENCRYPTION_ERROR;
-
-#if FF_X == 3
- FF3_cipher( key, 1, ptextLen, tweak, index );
-#else
- FF1_cipher( key, 1, ptextLen, tweak, tweakLen, index );
-#endif
- FPEfinalize( index, ptextLen, crtxt );
- free( index );
- return M_RESULT_SUCCESS;
+ char result = FPE_cipher( key, 1, TWEAK_AGRS, pntxt, ptextLen, crtxt );
+ return result == 0 ? M_RESULT_SUCCESS : M_ENCRYPTION_ERROR;
}
/**
@@ -2325,25 +2338,12 @@ char AES_FPE_encrypt( const uint8_t* key, const uint8_t* tweak,
* @param crtxt input ciphertext string, consisted of ALPHABET characters
* @param crtxtLen size of ciphertext string, or number of characters
* @param pntxt resulting plaintext string
- * @return whether all conditions of the algorithm were satisfied
+ * @return whether decryption was successful
*/
-char AES_FPE_decrypt( const uint8_t* key, const uint8_t* tweak,
-#if FF_X != 3
- const size_t tweakLen,
-#endif
+char AES_FPE_decrypt( const uint8_t* key, const TWEAK_PARAMS,
const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- rbase_t* index = NULL;
-
- if (FPEinit( crtxt, crtxtLen, &index ) != 0) return M_DECRYPTION_ERROR;
-
-#if FF_X == 3
- FF3_cipher( key, 0, crtxtLen, tweak, index );
-#else
- FF1_cipher( key, 0, crtxtLen, tweak, tweakLen, index );
-#endif
- FPEfinalize( index, crtxtLen, pntxt );
- free( index );
- return M_RESULT_SUCCESS;
+ char result = FPE_cipher( key, 0, TWEAK_AGRS, crtxt, crtxtLen, pntxt );
+ return result == 0 ? M_RESULT_SUCCESS : M_DECRYPTION_ERROR;
}
#endif /* FPE */
diff --git a/micro_aes.h b/micro_aes.h
index 8bf575f..5e63970 100644
--- a/micro_aes.h
+++ b/micro_aes.h
@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.h
Author : polfosol
- Version : 10
+ Version : 11
Copyright : copyright © 2022 - polfosol
Description : μAES ™ is a minimalist all-in-one library for AES encryption
==============================================================================
@@ -72,7 +72,7 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
#define MICRO_RJNDL WTF /* none of above; just rijndael API. dude.., why? */
/**----------------------------------------------------------------------------
-Refer to the bottom of this document for more information about these macros:
+Parameters and MACROs; refer to the bottom of this document for more info:
-----------------------------------------------------------------------------*/
#if ECB || (CBC && !CTS) || (XEX && !XTS)
@@ -86,33 +86,47 @@ Refer to the bottom of this document for more information about these macros:
#if FPE
#define CUSTOM_ALPHABET 0 /* if disabled, use default alphabet (digits 0..9) */
#define FF_X 1 /* algorithm type: (1) for FF1, or (3) for FF3-1 */
-#if FF_X == 3
-#define FF3_TWEAK_LEN 7 /* if the old version of FF3: (8), else FF3-1: (7) */
#endif
+
+enum constant_parameters_of_modes
+{
+#if FF_X == 3
+ FF3_TWEAK_LEN = 7, /* fixed for FF3-1. (LEN=8 in old version of FF3) */
#endif
#if CTR_NA
-#define CTR_IV_LENGTH 12 /* for using the last 32 bits as counter */
-#define CTR_STARTVALUE 1 /* recommended value according to the RFC-3686. */
+ CTR_START_VALUE = 1, /* Recommended by the RFC-3686 */
+ CTR_IV_LENGTH = 12, /* use the last 32 bits of block for counting */
+#define PRESET_COUNTER 0 /* enable this macro if CTR_IV_LENGTH == 16 */
#endif
#if CCM
-#define CCM_NONCE_LEN 11 /* for 32-bit count (since one byte is reserved). */
-#define CCM_TAG_LEN 16 /* must be an even number in the range of 4..16 */
+ CCM_NONCE_LEN = 11, /* for 32-bit count (since one byte is reserved) */
+ CCM_TAG_LEN = 16, /* must be EVEN. at most 16 bytes in all modes */
#endif
-
#if GCM
-#define GCM_NONCE_LEN 12 /* RECOMMENDED. but other values are supported. */
+ GCM_NONCE_LEN = 12, /* Recommended; but other values are supported. */
+ GCM_TAG_LEN = 16,
#endif
-
-#if EAX && !EAXP
-#define EAX_NONCE_LEN 16 /* no specified limit; can be arbitrarily large. */
+#if GCM_SIV
+ SIVGCM_NONCE_LEN = 12, /* the only valid value recommended by RFC-8452 */
+ SIVGCM_TAG_LEN = 16, /* the only valid value recommended by RFC-8452 */
#endif
-
#if OCB
-#define OCB_NONCE_LEN 12 /* RECOMMENDED. must be positive and less than 16. */
-#define OCB_TAG_LEN 16 /* again, please see the bottom of this document! */
+ OCB_NONCE_LEN = 12, /* Recommended; must be positive and less than 16 */
+ OCB_TAG_LEN = 16,
#endif
+#if EAX && !EAXP
+ EAX_NONCE_LEN = 16, /* no specified limit; can be arbitrarily large */
+ EAX_TAG_LEN = 16, /* more info at the bottom of this document. */
+#endif
+
+#if AES___ != 256 && AES___ != 192
+ AES_KEYLENGTH = 16 /*- fallback value for invalid or undefined AES___ */
+#else
+ AES_KEYLENGTH = AES___ / 8
+#endif
+};
/**----------------------------------------------------------------------------
Since is not a part of ANSI-C, we may need a 'trick' to use uint8_t
@@ -257,19 +271,19 @@ Main functions for SIV-AES block ciphering
-----------------------------------------------------------------------------*/
#if SIV
void AES_SIV_encrypt( const uint8_t* keys, /* encryption key pair */
- const void* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
uint8_t iv[16], /* synthesized initial-vector */
void* crtxt ); /* ciphertext result */
char AES_SIV_decrypt( const uint8_t* keys, /* decryption key pair */
const uint8_t iv[16], /* provided initial-vector */
- const void* crtxt, /* ciphertext input */
- const size_t crtxtLen, /* length of ciphertext */
const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
+ const void* crtxt, /* ciphertext input */
+ const size_t crtxtLen, /* length of ciphertext */
void* pntxt ); /* plaintext result */
#endif /* SIV */
@@ -279,21 +293,19 @@ Main functions for GCM-AES block ciphering
#if GCM
void AES_GCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- uint8_t* crtxt, /* ciphertext result */
- uint8_t auTag[16] ); /* message authentication tag */
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
+ void* crtxt ); /* ciphertext + auth. tag */
char AES_GCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* crtxt, /* ciphertext + appended tag */
- const size_t crtxtLen, /* length of ciphertext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- const uint8_t tagLen, /* length of tag (if any) */
- uint8_t* pntxt ); /* plaintext result */
+ const void* crtxt, /* ciphertext + appended tag */
+ const size_t crtxtLen, /* length of ciphertext */
+ void* pntxt ); /* plaintext result */
#endif /* GCM */
/**----------------------------------------------------------------------------
@@ -302,21 +314,19 @@ Main functions for CCM-AES block ciphering
#if CCM
void AES_CCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- uint8_t* crtxt, /* ciphertext result */
- uint8_t* auTag ); /* message authentication tag */
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
+ void* crtxt ); /* ciphertext + auth. tag */
char AES_CCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* crtxt, /* ciphertext + appended tag */
- const size_t crtxtLen, /* length of ciphertext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- const uint8_t tagLen, /* length of tag (=CCM_TAG_LEN) */
- uint8_t* pntxt ); /* plaintext result */
+ const void* crtxt, /* ciphertext + appended tag */
+ const size_t crtxtLen, /* length of ciphertext */
+ void* pntxt ); /* plaintext result */
#endif /* CCM */
/**----------------------------------------------------------------------------
@@ -325,21 +335,19 @@ Main functions for OCB-AES block ciphering
#if OCB
void AES_OCB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- uint8_t* crtxt, /* ciphertext result */
- uint8_t* auTag ); /* message authentication tag */
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
+ void* crtxt ); /* ciphertext + auth. tag */
char AES_OCB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* nonce or IV (init. vector) */
- const uint8_t* crtxt, /* ciphertext + appended tag */
- const size_t crtxtLen, /* length of ciphertext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- const uint8_t tagLen, /* length of tag (=OCB_TAG_LEN) */
- uint8_t* pntxt ); /* plaintext result */
+ const void* crtxt, /* ciphertext + appended tag */
+ const size_t crtxtLen, /* length of ciphertext */
+ void* pntxt ); /* plaintext result */
#endif /* OCB */
/**----------------------------------------------------------------------------
@@ -348,30 +356,27 @@ Main functions for EAX-AES mode; more info at the bottom of this document.
#if EAX
void AES_EAX_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* nonce, /* arbitrary-size nonce array */
- const uint8_t* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
#if EAXP
const size_t nonceLen, /* length of provided nonce */
- uint8_t* crtxt ); /* ciphertext result + mac (4) */
#else
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- uint8_t* crtxt, /* ciphertext result */
- uint8_t auTag[16] ); /* message authentication tag */
#endif
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
+ void* crtxt ); /* ciphertext+ appended tag/mac */
char AES_EAX_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* arbitrary-size nonce array */
- const uint8_t* crtxt, /* ciphertext + appended tag */
- const size_t crtxtLen, /* length of ciphertext */
#if EAXP
const size_t nonceLen, /* length of provided nonce */
#else
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- const uint8_t tagLen, /* length of tag (if any) */
#endif
- uint8_t* pntxt ); /* plaintext result */
+ const void* crtxt, /* ciphertext+ appended tag/mac */
+ const size_t crtxtLen, /* length of ciphertext */
+ void* pntxt ); /* plaintext result */
#endif /* EAX */
/**----------------------------------------------------------------------------
@@ -380,21 +385,19 @@ 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* pntxt, /* plaintext input */
- const size_t ptextLen, /* length of plaintext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- uint8_t* crtxt, /* ciphertext result */
- uint8_t auTag[16] ); /* 16-bytes mandatory tag */
+ const void* pntxt, /* plaintext input */
+ const size_t ptextLen, /* length of plaintext */
+ void* crtxt ); /* ciphertext + auth. tag */
char GCM_SIV_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* provided 96-bit nonce */
- const uint8_t* crtxt, /* ciphertext + appended tag */
- const size_t crtxtLen, /* length of ciphertext */
- const uint8_t* aData, /* added authentication data */
+ const void* aData, /* added authentication data */
const size_t aDataLen, /* length of AAD (auth. data) */
- const uint8_t tagLen, /* length of tag (must be 16) */
- uint8_t* pntxt ); /* plaintext result */
+ const void* crtxt, /* ciphertext + appended tag */
+ const size_t crtxtLen, /* length of ciphertext */
+ void* pntxt ); /* plaintext result */
#endif /* GCM-SIV */
/**----------------------------------------------------------------------------
@@ -404,12 +407,12 @@ Main functions for AES key-wrapping
char AES_KEY_wrap( const uint8_t* kek, /* key encryption key */
const void* secret, /* the secret to be wrapped */
const size_t secretLen, /* length of plaintext secret */
- uint8_t* wrapped ); /* key-wrapped output */
+ void* wrapped ); /* key-wrapped output */
char AES_KEY_unwrap( const uint8_t* kek, /* key encryption key */
const void* wrapped, /* key-wrapped secret */
const size_t wrapLen, /* length of wrapped secret */
- uint8_t* secret ); /* the unwrapped key result */
+ void* secret ); /* the unwrapped key result */
#endif /* KWA */
/**----------------------------------------------------------------------------
@@ -461,27 +464,22 @@ void AES_CMAC( const uint8_t* key, /* encryption or cipher key */
#endif
/**----------------------------------------------------------------------------
-The error codes and key length should be defined here for external references:
+Define some error codes here
-----------------------------------------------------------------------------*/
-#if AES___ != 256 && AES___ != 192
-#define AES_KEY_SIZE 16
-#else
-#define AES_KEY_SIZE (AES___ / 8)
-#endif
-
enum function_result_codes
{
M_ENCRYPTION_ERROR = 0x1E,
M_DECRYPTION_ERROR = 0x1D,
M_AUTHENTICATION_ERROR = 0x1A,
- M_RESULT_SUCCESS = 0x00
+ M_DATALENGTH_ERROR = 0x1L,
+ M_RESULT_SUCCESS = 0
};
#endif /* header guard */
-/******************************************************************************\
+/*----------------------------------------------------------------------------*\
¦ Notes and remarks about the above-defined macros ¦
---------------------------------------------------------------------------------
+ ------------------------------------------------------------------------------
* The main difference between the standard AES methods is in their key-expansion
process. So for example, AES-128-GCM and AES-256-GCM are pretty much similar
@@ -509,11 +507,11 @@ enum function_result_codes
a part of the I.V, which itself can either be a full block or a partial one.
In CBC, CFB and OFB modes, the provided IV must be a full block. In pure CTR
(CTR_NA) mode, the IV can either be a full block, or a 96 bit one —which is
- also called nonce. In the latter case, counting begins at CTR_STARTVALUE.
+ also called nonce. In the latter case, counting begins at CTR_START_VALUE.
-* In AEAD modes, the size of nonce and tag might be a parameter of the algorithm
- such that changing them affect the results. The GCM and EAX modes support
- arbitrary sizes for nonce. In CCM, the nonce length may vary from 8 to 13
+* In AEAD modes, the size of nonce and tag are considered as constant parameters
+ and changing them might affect the results. The GCM and EAX modes support
+ arbitrary sizes for nonce. In CCM, the nonce length may vary from 7 to 13
bytes. Also the tag size is an EVEN number between 4..16. In OCB, the nonce
size is 1..15 and the tag is 0..16 bytes. Note that the "calculated" tag-
size is always 16 bytes which is then truncated to the desired values. So in
@@ -530,7 +528,7 @@ enum function_result_codes
* 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 on
4 bytes. So EAX-prime functions don't need to take additional authentication
- data and tag-size as separate parameters. It has been proven that EAX' has
+ data and its size as separate parameters. It has been proven that EAX' has
serious vulnerabilities and its usage is not recommended.
* In SIV mode, multiple separate units of authentication headers can be provided
@@ -556,7 +554,7 @@ enum function_result_codes
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. This
assumption is likely to be valid for some embedded systems and small-scale
- applications. Furthermore, enabling the DISCARD_SUBROUTINES macro may have a
+ applications. Furthermore, enabling the INLINE_SUBROUTINES macro may have a
positive effect on the speed while increasing the size of compiled code.
Nonetheless, it is also possible to get different results sometimes.
diff --git a/micro_fpe.h b/micro_fpe.h
index b2baa21..0444239 100644
--- a/micro_fpe.h
+++ b/micro_fpe.h
@@ -2,7 +2,7 @@
==============================================================================
Name : micro_fpe.h
Author : polfosol
- Version : 2.2.0.0
+ Version : 11
Copyright : copyright © 2022 - polfosol
Description : demonstrating some sample alphabets for the FPE mode of μAES ™
==============================================================================
@@ -11,159 +11,144 @@
#ifndef MICRO_FPE_H_
#define MICRO_FPE_H_
-/******************************************************************************
- * In what follows, a few sample alphabets and their corresponding macros are
- * provided. Accordingly, it would be straightforward to define any alphabet.
+/**
* If your desired alphabet contains non-ASCII characters, the CUSTOM_ALPHABET
- * macro 'must be' set to a double-digit number, e.g. 21. The declaration of an
- * alphabet needs to be followed by its number of characters (RADIX).
+ * macro 'must be' set to a double-digit number, e.g. 21.
*/
-#define NON_ASCII_CHARACTER_SET (CUSTOM_ALPHABET >= 10)
+#define ALPHABET_IS_NON_ASCII (CUSTOM_ALPHABET >= 10)
+#if ALPHABET_IS_NON_ASCII
+/**
+ * Note that C89/ANSI-C standard does not fully support such characters, and the
+ * code may lose its compliance in this case.
+ */
+#include
+#include
-/******************************************************************************
+#else
+/**
* These strings frequently appear in ASCII-based alphabets.
*/
-#define DECIMALS "0123456789"
+#define DIGITS01 "01"
#define LLETTERS "abcdefghijklmnopqrstuvwxyz"
#define ULETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-#define HEXCHARS DECIMALS "ABCDEFabcdef"
+#define DECIMALS DIGITS01"23456789"
+#endif
+
/**
- numbers
+ * In what follows, a few sample alphabets and their corresponding macros are
+ * provided. Accordingly, it would be straightforward to work with any kind of
+ * alphabets. The declaration of an alphabet must be followed by its number of
+ * characters (RADIX).
*/
-#if CUSTOM_ALPHABET == 0
+#if !CUSTOM_ALPHABET
#define ALPHABET DECIMALS
#define RADIX 10
-#endif
-
-/**
- binary numbers
- */
-#if CUSTOM_ALPHABET == 1
-#define ALPHABET "01"
-#define RADIX 2
-#endif
/**
lowercase english words
*/
-#if CUSTOM_ALPHABET == 2
+#elif CUSTOM_ALPHABET == 1
#define ALPHABET LLETTERS
#define RADIX 26
-#endif
+
+/**
+ PLACEHOLDER: define your ASCII alphabet here
+ */
+#elif CUSTOM_ALPHABET == 2
+#define ALPHABET "my Alphabet"
+#define RADIX 11
+
+/**
+ binary numbers
+ */
+#elif CUSTOM_ALPHABET == 3
+#define ALPHABET DIGITS01
+#define RADIX 2
/**
lowercase alphanumeric strings
*/
-#if CUSTOM_ALPHABET == 3
+#elif CUSTOM_ALPHABET == 4
#define ALPHABET DECIMALS LLETTERS
#define RADIX 36
-#endif
-
-/**
- the English alphabet
- */
-#if CUSTOM_ALPHABET == 4
-#define ALPHABET ULETTERS LLETTERS
-#define RADIX 52
-#endif
/**
base-64 encoded strings (RFC-4648), with no padding character
*/
-#if CUSTOM_ALPHABET == 5
+#elif CUSTOM_ALPHABET == 5
#define ALPHABET ULETTERS LLETTERS DECIMALS "+/"
#define RADIX 64
-#endif
/**
base-85 encoded strings (RFC-1924)
*/
-#if CUSTOM_ALPHABET == 6
+#elif CUSTOM_ALPHABET == 6
#define ALPHABET DECIMALS ULETTERS LLETTERS "!#$%&()*+-;<=>?@^_`{|}~"
#define RADIX 85
-#endif
-
-/**
- a character set with length 26, used by some test vectors
- */
-#if CUSTOM_ALPHABET == 7
-#define ALPHABET DECIMALS "abcdefghijklmnop"
-#define RADIX 26
-#endif
/**
base-64 character set with DIFFERENT ORDERING, used by some test vectors
*/
-#if CUSTOM_ALPHABET == 8
+#elif CUSTOM_ALPHABET == 7
#define ALPHABET DECIMALS ULETTERS LLETTERS "+/"
#define RADIX 64
-#endif
+
+/**
+ a character set with length 26, used by some test vectors
+ */
+#elif CUSTOM_ALPHABET == 8
+#define ALPHABET DECIMALS LLETTERS
+#define RADIX 26
/**
all printable ascii characters
*/
-#if CUSTOM_ALPHABET == 9
+#elif CUSTOM_ALPHABET == 9
#define ALPHABET " !\"#$%&\'()*+,-./"DECIMALS":;<=>?@"ULETTERS"[\\]^_`"LLETTERS"{|}~"
#define RADIX 95
-#endif
-
-
-/******************************************************************************
- * Here goes non-ASCII alphabets. Note that C89/ANSI-C standard does not fully
- * support such characters, and the code may lose its compliance in this case.
- */
-#if NON_ASCII_CHARACTER_SET
-#include
-#include
-
-#define string_t wchar_t* /* type of plain/cipher-text */
-#else
-#define string_t char*
-#endif
/**
+ And here goes NON-ASCII alphabets. The string literal must have an L-prefix.
+ ------------------------------------------------------------------------------
+ **
Greek alphabet (LTR)
*/
-#if CUSTOM_ALPHABET == 10
+#elif CUSTOM_ALPHABET == 10
#define ALPHABET L"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφϕχψω"
#define RADIX 50
-#endif
/**
Persian alphabet (RTL)
*/
-#if CUSTOM_ALPHABET == 20
+#elif CUSTOM_ALPHABET == 20
#define ALPHABET L"ءئؤآابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهی"
#define RADIX 36
#endif
-/******************************************************************************
- * It is mandatory to determine these constants for the alphabet. You can either
- * pre-calculate the logarithm value (with at least 15 significant digits) and
- * set it as a constant, or leave its calculation to the standard math library.
- * Other constants are directly related to the value of logarithm, and MAXLEN is
- * needed only in the FF3 mode.
- *
-#define MINLEN (RADIX < 8 ? 40 / RADIX + (RADIX / 4) * (RADIX - 4) : \
- (RADIX < 1000) + (RADIX < 100) - (RADIX == 10) + 2 + 31 / RADIX)
- *
- * The above lines illustrate that MINLEN can also be defined independently,
- * using pure integer arithmetics.
+/**
+ * You can either pre-calculate the value of logarithm (up to 14 decimal places
+ * to be safe) and set it as a constant, or use the standard math library.
*/
#include
-#ifdef MATH_ERRNO
+#ifdef MATH_ERRNO /* then STDC version >= C99 */
#define LOGRDX log2( RADIX )
-#else /* this means std-C <= C90 */
+#else
#define LOGRDX (log( RADIX ) / log( 2 ))
#endif
-#define MINLEN ((int) (19.931568 / LOGRDX + 1))
+#define MINLEN (1 + (int) (19.931561 / LOGRDX))
#if FF_X == 3
#define MAXLEN (2 * (int) (96.000001 / LOGRDX))
#endif
+/**
+ * MINLEN can also be defined independently, using pure integer arithmetics:
+ *
+#define MINLEN (RADIX < 5 ? 40 / RADIX : \
+ 32 / (1 + RADIX) + (RADIX < 100) + (RADIX < 1000) + 2)
+ */
#endif /* header guard */
diff --git a/prj_vc++.vcxproj b/prj_vc++.vcxproj
index 4f24c04..2ad4e7a 100644
--- a/prj_vc++.vcxproj
+++ b/prj_vc++.vcxproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -30,15 +30,13 @@
Unicode
-
-
+
-
true
@@ -47,8 +45,6 @@
-
-
Level3
Disabled
WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
@@ -61,8 +57,6 @@
Level3
-
-
MaxSpeed
true
true
@@ -75,9 +69,6 @@
true
-
-
-
@@ -88,6 +79,7 @@
+
@@ -95,7 +87,7 @@
-
-
-
+
+
+
\ No newline at end of file
diff --git a/testvectors/EAX_AES128.tv b/testvectors/EAX_AES128.tv
new file mode 100644
index 0000000..361d21b
--- /dev/null
+++ b/testvectors/EAX_AES128.tv
@@ -0,0 +1,64 @@
+# EAX-AES-128 test vectors
+# Taken from:
+# Bellare, M., Rogaway, P., Wagner, D.A. (2004). The EAX Mode of Operation. Fast Software Encryption Workshop.
+
+
+MSG:
+KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478
+NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3
+HEADER: 6BFB914FD07EAE6B
+CIPHER: E037830E8389F27B025A2D6527E79D01
+
+MSG: F7FB
+KEY: 91945D3F4DCBEE0BF45EF52255F095A4
+NONCE: BECAF043B0A23D843194BA972C66DEBD
+HEADER: FA3BFD4806EB53FA
+CIPHER: 19DD5C4C9331049D0BDAB0277408F67967E5
+
+MSG: 1A47CB4933
+KEY: 01F74AD64077F2E704C0F60ADA3DD523
+NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E
+HEADER: 234A3463C1264AC6
+CIPHER: D851D5BAE03A59F238A23E39199DC9266626C40F80
+
+MSG: 481C9E39B1
+KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8
+NONCE: 8408DFFF3C1A2B1292DC199E46B7D617
+HEADER: 33CCE2EABFF5A79D
+CIPHER: 632A9D131AD4C168A4225D8E1FF755939974A7BEDE
+
+MSG: 40D0C07DA5E4
+KEY: 35B6D0580005BBC12B0587124557D2C2
+NONCE: FDB6B06676EEDC5C61D74276E1F8E816
+HEADER: AEB96EAEBE2970E9
+CIPHER: 071DFE16C675CB0677E536F73AFE6A14B74EE49844DD
+
+MSG: 4DE3B35C3FC039245BD1FB7D
+KEY: BD8E6E11475E60B268784C38C62FEB22
+NONCE: 6EAC5C93072D8E8513F750935E46DA1B
+HEADER: D4482D1CA78DCE0F
+CIPHER: 835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F
+
+MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636
+KEY: 7C77D6E813BED5AC98BAA417477A2E7D
+NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19
+HEADER: 65D2017990D62528
+CIPHER: 02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2
+
+MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56
+KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D
+NONCE: DDE59B97D722156D4D9AFF2BC7559826
+HEADER: 54B9F04E6A09189A
+CIPHER: 2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A
+
+MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11
+KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123
+NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC
+HEADER: 899A175897561D7E
+CIPHER: 0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700
+
+MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7
+KEY: 8395FCF1E95BEBD697BD010BC766AAC3
+NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44
+HEADER: 126735FCC320D25A
+CIPHER: CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E
diff --git a/testvectors/gcmEncryptExtIV128.rsp b/testvectors/GcmEncryptExtIV128.rsp
similarity index 100%
rename from testvectors/gcmEncryptExtIV128.rsp
rename to testvectors/GcmEncryptExtIV128.rsp
diff --git a/testvectors/gcmEncryptExtIV192.rsp b/testvectors/GcmEncryptExtIV192.rsp
similarity index 100%
rename from testvectors/gcmEncryptExtIV192.rsp
rename to testvectors/GcmEncryptExtIV192.rsp
diff --git a/testvectors/gcmEncryptExtIV256.rsp b/testvectors/GcmEncryptExtIV256.rsp
similarity index 100%
rename from testvectors/gcmEncryptExtIV256.rsp
rename to testvectors/GcmEncryptExtIV256.rsp
diff --git a/testvectors/ccmVNT128.rsp b/testvectors/VNT128.rsp
similarity index 100%
rename from testvectors/ccmVNT128.rsp
rename to testvectors/VNT128.rsp
diff --git a/testvectors/ccmVNT192.rsp b/testvectors/VNT192.rsp
similarity index 100%
rename from testvectors/ccmVNT192.rsp
rename to testvectors/VNT192.rsp
diff --git a/testvectors/ccmVNT256.rsp b/testvectors/VNT256.rsp
similarity index 100%
rename from testvectors/ccmVNT256.rsp
rename to testvectors/VNT256.rsp
diff --git a/testvectors/aes_tests.cbp b/testvectors/aes_tests.cbp
index e5b00f2..2682c60 100644
--- a/testvectors/aes_tests.cbp
+++ b/testvectors/aes_tests.cbp
@@ -42,6 +42,7 @@
+
diff --git a/testvectors/aes_testvectors.c b/testvectors/aes_testvectors.c
index 0acfe66..c49c1a0 100644
--- a/testvectors/aes_testvectors.c
+++ b/testvectors/aes_testvectors.c
@@ -2,7 +2,7 @@
==============================================================================
Name : aes_testvectors.c
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : check the test-vectors for enabled modes of µAES ™
==============================================================================
@@ -12,6 +12,7 @@
#include "aes_testvectors_CCM.h"
#include "aes_testvectors_XTS.h"
#include "aes_testvectors_FPE.h"
+#include "aes_testvectors_EAX.h"
#include "aes_testvectors_OCB.h"
#include "aes_testvectors_GCMSIV.h"
#include "aes_testvectors_CMAC.h"
@@ -19,36 +20,33 @@
int main(void)
{
+ int ret = 0;
#ifdef CMAC_TEST_FILE
- check_testvectors("CMAC", CMAC_TEST_FILE, &aes_cmac_test);
+ ret |= check_testvectors("CMAC", CMAC_TEST_FILE, &aes_cmac_test);
#endif
-
#ifdef POLY_TEST_FILE
- check_testvectors("POLY1305", POLY_TEST_FILE, &aes_poly1305_test);
+ ret |= check_testvectors("POLY1305", POLY_TEST_FILE, &aes_poly1305_test);
#endif
-
#ifdef GCM_TEST_FILE
- check_testvectors("GCM", GCM_TEST_FILE, &aes_gcm_test);
+ ret |= check_testvectors("GCM", GCM_TEST_FILE, &aes_gcm_test);
#endif
-
#ifdef CCM_TEST_FILE
- check_testvectors("CCM", CCM_TEST_FILE, &aes_ccm_test);
+ ret |= check_testvectors("CCM", CCM_TEST_FILE, &aes_ccm_test);
+#endif
+#ifdef EAX_TEST_FILE
+ ret |= check_testvectors("EAX", EAX_TEST_FILE, &aes_eax_test);
#endif
-
#ifdef OCB_TEST_FILE
- check_testvectors("OCB", OCB_TEST_FILE, &aes_ocb_test);
+ ret |= check_testvectors("OCB", OCB_TEST_FILE, &aes_ocb_test);
#endif
-
#ifdef GCMSIV_TEST_FILE
- check_testvectors("GCM-SIV", GCMSIV_TEST_FILE, &aes_gcmsiv_test);
+ ret |= check_testvectors("GCM-SIV", GCMSIV_TEST_FILE, &aes_gcmsiv_test);
#endif
-
#ifdef XTS_TEST_FILE
- check_testvectors("XTS", XTS_TEST_FILE, &aes_xts_test);
+ ret |= check_testvectors("XTS", XTS_TEST_FILE, &aes_xts_test);
#endif
-
#ifdef FPE_TEST_FILE
- check_testvectors("FPE", FPE_TEST_FILE, &aes_fpe_test);
+ ret |= check_testvectors("FPE", FPE_TEST_FILE, &aes_fpe_test);
#endif
- return 0;
+ return ret;
}
diff --git a/testvectors/aes_testvectors.h b/testvectors/aes_testvectors.h
index 25786cb..6252f6b 100644
--- a/testvectors/aes_testvectors.h
+++ b/testvectors/aes_testvectors.h
@@ -2,7 +2,7 @@
==============================================================================
Name : aes_testvectors.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : methods and definitions for the test-functions of AES modes
==============================================================================
@@ -12,81 +12,152 @@
#define _TEST_AES_MODES_H_
#include
+#include
#include "../micro_aes.h"
#ifdef _CRT_SECURE_NO_WARNINGS
-#define _LOOKUP_ "testvectors/"
+#define VEC_PATH "testvectors/"
#else
-#define _LOOKUP_
+#define VEC_PATH
#endif
#if CMAC
#if AES___ == 256
-#define CMAC_TEST_FILE _LOOKUP_ "CMACGenAES256.rsp"
+#define CMAC_TEST_FILE VEC_PATH "CMACGenAES256.rsp"
#elif AES___ == 192
-#define CMAC_TEST_FILE _LOOKUP_ "CMACGenAES192.rsp"
+#define CMAC_TEST_FILE VEC_PATH "CMACGenAES192.rsp"
#else
-#define CMAC_TEST_FILE _LOOKUP_ "CMACGenAES128.rsp"
+#define CMAC_TEST_FILE VEC_PATH "CMACGenAES128.rsp"
#endif
#define CMAC_HEADLINES { "Key = ", "Msg = ", "Mac = " }
#endif
#if CCM
#if AES___ == 256
-#define CCM_TEST_FILE _LOOKUP_ "ccmVNT256.rsp"
+#define CCM_TEST_FILE VEC_PATH "VNT256.rsp"
#elif AES___ == 192
-#define CCM_TEST_FILE _LOOKUP_ "ccmVNT192.rsp"
+#define CCM_TEST_FILE VEC_PATH "VNT192.rsp"
#else
-#define CCM_TEST_FILE _LOOKUP_ "ccmVNT128.rsp"
+#define CCM_TEST_FILE VEC_PATH "VNT128.rsp"
#endif
#define CCM_HEADLINES { "Key = ", "Nonce = ", "Adata = ", "Payload = ", "CT = " }
#endif
#if GCM
#if AES___ == 256
-#define GCM_TEST_FILE _LOOKUP_ "gcmEncryptExtIV256.rsp"
+#define GCM_TEST_FILE VEC_PATH "GcmEncryptExtIV256.rsp"
#elif AES___ == 192
-#define GCM_TEST_FILE _LOOKUP_ "gcmEncryptExtIV192.rsp"
+#define GCM_TEST_FILE VEC_PATH "GcmEncryptExtIV192.rsp"
#else
-#define GCM_TEST_FILE _LOOKUP_ "gcmEncryptExtIV128.rsp"
+#define GCM_TEST_FILE VEC_PATH "GcmEncryptExtIV128.rsp"
#endif
#define GCM_HEADLINES { "Key = ", "IV = ", "AAD = ", "PT = ", "CT = ", "Tag = " }
#endif
#if XTS
-#if AES___ == 256
-#define XTS_TEST_FILE _LOOKUP_ "XTSGenAES256.rsp"
-#else
-#define XTS_TEST_FILE _LOOKUP_ "XTSGenAES128.rsp"
+#if AES___ == 256
+#define XTS_TEST_FILE VEC_PATH "XTSGenAES256.rsp"
+#elif AES___ != 192
+#define XTS_TEST_FILE VEC_PATH "XTSGenAES128.rsp"
#endif
#define XTS_HEADLINES { "Key = ", "i = ", "PT = ", "CT = ", "DataUnitLen = " }
#endif
+#if POLY1305
+#define POLY_TEST_FILE VEC_PATH "Poly1305AES128.tv"
+#define POLY_HEADLINES { "Keys = ", "Nonce = ", "Msg = ", "PolyMac = " }
+#endif
+
+#if EAX
+#define EAX_TEST_FILE VEC_PATH "EAX_AES128.tv"
+#define EAX_HEADLINES { "MSG: ", "KEY: ", "NONCE: ", "HEADER: ", "CIPHER: " }
+#endif
+
+#if GCM_SIV
+#define GCMSIV_TEST_FILE VEC_PATH "SIV_GCM_ACVP.tv"
+#define GCMSIV_HEADLINES { "key = ", "iv = ", "aad = ", "pt = ", "ct = " }
+#endif
+
#if FPE
-#define FPE_TEST_FILE _LOOKUP_ "FPE_FF1&FF3&FF3-1.tv"
+#define FPE_TEST_FILE VEC_PATH "FPE_FF1&FF3&FF3-1.tv"
#define FPE_HEADLINES { "Method = ", "Alphabet = ", "Key = ", "Tweak = ", \
"PT = ", "CT = " }
-#define FPE_ALPHABETS { "0123456789", "01", "abcdefghijklmnopqrstuvwxyz", \
- "0123456789abcdefghijklmnopqrstuvwxyz", "******", \
- "*******", "*****", "0123456789abcdefghijklmnop", \
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/" }
+#define FPE_ALPHABETS { DECIMALS, LLETTERS, "PLACEHOLDER: your alphabet", \
+ DIGITS01, DECIMALS LLETTERS, ULETTERS LLETTERS DECIMALS "+/", \
+ DECIMALS ULETTERS LLETTERS "!#$%&()*+-;<=>?@^_`{|}~", DECIMALS \
+ ULETTERS LLETTERS "+/", DECIMALS "abcdefghijklmnop", " !\"#$%&" \
+ "\'()*+,-./" DECIMALS ":;<=>?@" ULETTERS"[\\]^_`" LLETTERS"{|}~" }
#endif
#if OCB
-#define OCB_TEST_FILE _LOOKUP_ "OCB_AES128.tv"
+#define OCB_TEST_FILE VEC_PATH "OCB_AES128.tv"
#define OCB_HEADLINES { "Key = ", "IV = ", "AAD = ", "Plaintext = ", \
"Ciphertext = ", "Tag = ", "Result = " }
#endif
-#if GCM_SIV
-#define GCMSIV_TEST_FILE _LOOKUP_ "SIV_GCM_ACVP.tv"
-#define GCMSIV_HEADLINES { "key = ", "iv = ", "aad = ", "pt = ", "ct = " }
-#endif
+#define LINES_MAX_LEN 0x20040L /* maximum length of a line among all files. */
-#if POLY1305
-#define POLY_TEST_FILE _LOOKUP_ "Poly1305AES128.tv"
-#define POLY_HEADLINES { "Keys = ", "Nonce = ", "Msg = ", "PolyMac = " }
-#endif
+/** function pointer as a template for all the test functions. its arguments are
+ * an array of pre-determined files and the number of test cases/failed ones. */
+typedef void (*ftest_t)(FILE**, unsigned*);
+
+static int check_testvectors(const char* mode, const char* path, ftest_t test)
+{
+ char i, log[2][22], error = -1;
+ FILE* files[3]; /* test vectors file, success log, errors log */
+ unsigned count[3] = { 0 }; /* total tests, encrypt fails, decrypt fails. */
+
+ printf("\nVerifying vectors: AES%d-%s\n", AES_KEYLENGTH * 8, mode);
+ files[0] = fopen(path, "r");
+ files[1] = fopen(strcat(strcpy(log[0], mode), "success.log"), "w");
+ files[2] = fopen(strcat(strcpy(log[1], mode), "failure.log"), "w");
+
+ if (files[0] && files[1] && files[2])
+ {
+ test(files, count);
+ error = count[1] || (count[2] && ~count[2]);
+ }
+ for (i = 0; i < 3; i++) /* close and delete unnecessary logs. */
+ {
+ if (files[i] && -fclose(files[i]) >= error)
+ {
+ error += i ? remove(log[i - 1]) : error;
+ }
+ }
+ switch (2 * !error + !*count)
+ {
+ case 0:
+ printf("Nmber of tests: %d, there were some errors.\n", count[0]);
+ if (count[2] == ~0U) /* MAC test, no encryption/decryption */
+ {
+ printf("Failed cases: %d, see the log files.\n", count[1]);
+ }
+ else
+ {
+ printf("Encryption failures: %d, decryption failures: %d\n"
+ "See the log files for more info.\n", count[1], count[2]);
+ }
+ break;
+ case 1:
+ printf("Error: Test has failed.\n");
+ if (error == -1)
+ {
+ printf("File not found: %s\n", path);
+ }
+ else
+ {
+ printf("Cannot save log files...\n");
+ }
+ break;
+ case 2:
+ printf("Nmber of tests: %3d, All Passed!\n", count[0]);
+ break;
+ case 3:
+ printf("No valid cases found in %s\n", path);
+ break;
+ }
+ return error;
+}
/** convert hex-string to byte array; e.g. "7142075A340d" results in qB\aZ4\r */
static void str2bytes(const char* hex, uint8_t* bytes)
@@ -102,90 +173,14 @@ static void str2bytes(const char* hex, uint8_t* bytes)
/** convert byte array to hex-string; e.g. +\n50\tK results in "2b0a3530094b" */
static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
+#define UPPERCASE_HEXSTRING 0
{
- const char offset = 0x27; /* offset must be 7 for UPPERCASE */
size_t i = len + len, shr = 0;
for (str[i] = 0; i--; shr ^= 4)
{
- str[i] = bytes[i / 2] >> shr & 0xF | '0';
- if (str[i] > '9') str[i] += offset;
+ str[i] = bytes[i / 2] >> shr & 0xF;
+ str[i] += str[i] < 10 ? '0' : (UPPERCASE_HEXSTRING ? '7' : 'W');
}
}
-/** function pointer as a template for all the test functions. its arguments are
- * an array of pre-determined files and the number of test cases/failed ones. */
-typedef void (*ftest_t)(FILE**, unsigned*);
-
-static int check_testvectors(const char* mode, const char* path, ftest_t test)
-{
- int error = 0, i;
- char p_log[20], e_log[20];
- FILE* files[3]; /* test vectors file, errors log, success log */
- unsigned count[3]; /* total tests, encrypt fails, decrypt fails. */
-
- printf("\nVerifying vectors: AES%d-%s\n", AES_KEY_SIZE * 8, mode);
- strcpy(p_log, mode);
- strcpy(e_log, mode);
- files[0] = fopen(path, "r");
- files[1] = fopen(strcat(p_log, "passed.log"), "w");
- files[2] = fopen(strcat(e_log, "failed.log"), "w");
-
- if (!files[0])
- {
- printf("Error: file not found: %s\n", path);
- error |= 1;
- }
- if (!files[1] || !files[2])
- {
- printf("Error: cannot save log files...\n");
- error |= 1;
- }
- if (error)
- {
- for (i = 0; i < 3; ++i)
- {
- if (files[i])
- {
- fclose(files[i]);
- if (i) remove(i == 1 ? p_log : e_log);
- }
- }
- printf("Test has failed.\n");
- return error;
- }
- memset(count, 0, sizeof count);
- test(files, count);
-
- for (i = 0; i < 3; i++)
- {
- fclose(files[i]);
- }
- error = count[1] + (~count[2] ? count[2] : 0);
- if (error)
- {
- printf("Nmber of tests: %d, there were some errors:\n", count[0]);
- if (count[2] == ~0U) /* MAC test, no encryption/decryption */
- {
- printf("Failed cases: %d, see the log files.\n", count[1]);
- }
- else
- {
- printf("Encryption failures: %d, decryption failures: %d\n"
- "See the log files for more info.\n", count[1], count[2]);
- }
- return error;
- }
- else
- {
- if (count[0] == 0) printf("There was no test cases.\n");
- else
- {
- printf("Nmber of tests: %4d, All Passed!\n", count[0]);
- }
- remove(p_log);
- remove(e_log);
- }
- return 0;
-}
-
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_CCM.h b/testvectors/aes_testvectors_CCM.h
index ab0d417..98f7f56 100644
--- a/testvectors/aes_testvectors_CCM.h
+++ b/testvectors/aes_testvectors_CCM.h
@@ -2,39 +2,38 @@
==============================================================================
Name : aes_testvectors_CCM.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-CCM
==============================================================================
*/
-#ifndef _TESTING_CCM_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_CCM_H_) ^ defined(CCM_TEST_FILE)
#define _TESTING_CCM_H_
-#include "aes_testvectors.h"
-#ifdef CCM_TEST_FILE
-
-static int verifyccm(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
- size_t np, size_t na, char* r)
+int verifyccm(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, char* r)
{
- char sk[2 * AES_KEY_SIZE + 1], si[33], sp[80], sc[96], sa[80], msg[30];
+ char sk[2 * AES_KEYLENGTH + 1], si[30], sp[80], sc[96], sa[80], msg[30];
uint8_t tmp[64], v = 0;
strcpy(msg, "passed the test");
- AES_CCM_encrypt(key, i, p, np, a, na, tmp, tmp + np);
+ AES_CCM_encrypt(key, i, a, na, p, np, tmp);
if (memcmp(c, tmp, np + CCM_TAG_LEN))
{
strcpy(msg, "encrypt failure");
v = 1;
}
memset(tmp, 0xcc, sizeof tmp);
- *sk = AES_CCM_decrypt(key, i, c, np, a, na, CCM_TAG_LEN, tmp);
- if (*sk || memcmp(p, tmp, np))
+ *r = AES_CCM_decrypt(key, i, a, na, c, np, tmp);
+ if (*r || memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(key, sk, AES_KEYLENGTH);
bytes2str(i, si, CCM_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
@@ -43,60 +42,55 @@ static int verifyccm(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t*
return v;
}
-static void aes_ccm_test(FILE** files, unsigned* count)
+void aes_ccm_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = CCM_HEADLINES;
+ const char* head[] = CCM_HEADLINES;
char buffer[0x800], *value = NULL;
size_t s[5] = { 0 };
- uint8_t j, n = 0, key[AES_KEY_SIZE], iv[16], p[64], c[80], a[64];
+ uint8_t h, e = 0, key[32], iv[15], p[64], c[80], a[64];
while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 5; j++)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 5 : 0; h < 5; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) != 0) continue;
+
+ value = strrchr(buffer, ' ') + 1;
+ s[h] = strlen(value) / 2 - CCM_TAG_LEN * (h == 4);
+ switch (h)
{
- value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
- n += j > 2;
+ case 0:
+ str2bytes(value, key);
+ break;
+ case 1:
+ str2bytes(value, iv);
+ break;
+ case 2:
+ str2bytes(value, a);
+ break;
+ case 3:
+ str2bytes(value, p);
+ break;
+ case 4:
+ str2bytes(value, c);
break;
}
+ e += (h == 3 || h == 4);
}
- switch (j)
+ if (e == 2)
{
- case 0:
- if (s[0] == AES_KEY_SIZE) str2bytes(value, key);
- break;
- case 1:
- if (s[1] == CCM_NONCE_LEN) str2bytes(value, iv);
- break;
- case 2:
- str2bytes(value, a);
- break;
- case 3:
- str2bytes(value, p);
- break;
- case 4:
- s[4] -= CCM_TAG_LEN;
- str2bytes(value, c);
- break;
- }
- if (n == 2)
- {
- if (s[0] == AES_KEY_SIZE && s[1] == CCM_NONCE_LEN && s[3] == s[4])
+ if (AES_KEYLENGTH == *s && CCM_NONCE_LEN == s[1] && s[3] == s[4])
{
- n = verifyccm(key, iv, p, a, c, s[3], s[2], buffer);
- fprintf(files[2 - !n], "%s\n", buffer); /* save the log */
+ e = verifyccm(key, iv, p, a, c, s[3], s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (n & 1) ++count[1];
- if (n & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- n = 0;
+ e = 0;
}
}
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_CMAC.h b/testvectors/aes_testvectors_CMAC.h
index 7391ae3..66bf7f5 100644
--- a/testvectors/aes_testvectors_CMAC.h
+++ b/testvectors/aes_testvectors_CMAC.h
@@ -2,83 +2,86 @@
==============================================================================
Name : aes_testvectors_CMAC.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-CMAC
==============================================================================
*/
-#ifndef _TESTING_CMAC_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_CMAC_H_) ^ defined(CMAC_TEST_FILE)
#define _TESTING_CMAC_H_
-#include "aes_testvectors.h"
-#ifdef CMAC_TEST_FILE
-
-static int verifycmac(uint8_t* key, uint8_t* d, uint8_t* m,
- size_t nd, size_t nm, char* r)
+int verifycmac(uint8_t* key, uint8_t* d, uint8_t* m,
+ size_t nd, size_t nm, char* r)
{
- char sk[2 * AES_KEY_SIZE + 1], smac[33], msg[30];
+ char sk[2 * AES_KEYLENGTH + 1], smac[33], msg[30];
uint8_t tmp[16], v = 0;
strcpy(msg, "passed the test");
AES_CMAC(key, d, nd, tmp);
if ((v = memcmp(m, tmp, nm)) != 0) strcpy(msg, "failed");
- bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(key, sk, AES_KEYLENGTH);
bytes2str(m, smac, nm);
sprintf(r, "%s\nK: %s\nmac: %s\n", msg, sk, smac);
return v;
}
-static void aes_cmac_test(FILE** files, unsigned* count)
+void aes_cmac_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = CMAC_HEADLINES;
- char buffer[0x20100], *value = NULL;
+ const char* head[] = CMAC_HEADLINES;
size_t s[3] = { 0 };
- uint8_t j, n = 0, key[AES_KEY_SIZE], d[0x10100], m[16];
+ uint8_t h, *d, e = 0, key[AES_KEYLENGTH], m[16];
+ char *value = NULL, *buffer;
count[2] = ~0U;
-
- while (fgets(buffer, sizeof buffer, *files) != NULL)
+ if ((buffer = malloc(LINES_MAX_LEN / 2 * 3)) == NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 3; j++)
+ printf("Memory allocation failed.\n");
+ return;
+ }
+ while (fgets(buffer, LINES_MAX_LEN, *files) != NULL)
+ {
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 3 : 0; h < 3; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) == 0)
{
value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
- n += j > 0;
+ d = (uint8_t*) &buffer[LINES_MAX_LEN];
+ s[h] = strlen(value) / 2;
+ e += (h == 1 || h == 2);
break;
}
}
- switch (j)
+ switch (h)
{
case 0:
- if (s[0] == AES_KEY_SIZE) str2bytes(value, key);
+ if (s[0] == sizeof key) str2bytes(value, key);
break;
case 1:
str2bytes(value, d);
- s[1] -= (s[1] == 1 && d[0] == 0); /* null message */
+ s[1] -= (s[1] == !d[0]); /* null message */
break;
case 2:
str2bytes(value, m);
break;
}
- if (n == 2)
+ if (e == 2)
{
- if (s[0] == AES_KEY_SIZE)
+ if (s[0] == sizeof key)
{
- n = verifycmac(key, d, m, s[1], s[2], buffer);
- fprintf(files[2 - !n], "%s\n", buffer); /* save the log */
+ e = verifycmac(key, d, m, s[1], s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (n) ++count[1];
+ count[1] += e != 0;
}
- n = 0;
+ e = 0;
}
}
+ free(buffer);
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_EAX.h b/testvectors/aes_testvectors_EAX.h
new file mode 100644
index 0000000..d42193c
--- /dev/null
+++ b/testvectors/aes_testvectors_EAX.h
@@ -0,0 +1,96 @@
+/*
+ ==============================================================================
+ Name : aes_testvectors_EAX.h
+ Author : polfosol
+ Version : 1.0.0.0
+ Copyright : copyright © 2024 - polfosol
+ Description : checking the test vectors for AES-EAX
+ ==============================================================================
+ */
+
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_EAX_H_) ^ defined(EAX_TEST_FILE)
+#define _TESTING_EAX_H_
+
+int verifyeax(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, char* r)
+{
+ char sk[2 * AES_KEYLENGTH + 1], si[33], sp[80], sc[96], sa[80], msg[30];
+ uint8_t tmp[64], v = 0;
+ strcpy(msg, "passed the test");
+
+ AES_EAX_encrypt(key, i, a, na, p, np, tmp);
+ if (memcmp(c, tmp, np + EAX_TAG_LEN))
+ {
+ strcpy(msg, "encrypt failure");
+ v = 1;
+ }
+ memset(tmp, 0xcc, sizeof tmp);
+ *r = AES_EAX_decrypt(key, i, a, na, c, np, tmp);
+ if (*r || memcmp(p, tmp, np))
+ {
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
+ v |= 2;
+ }
+ bytes2str(key, sk, AES_KEYLENGTH);
+ bytes2str(i, si, EAX_NONCE_LEN);
+ bytes2str(p, sp, np);
+ bytes2str(a, sa, na);
+ bytes2str(c, sc, np + EAX_TAG_LEN);
+ sprintf(r, "%s\nK: %s\ni: %s\nP: %s\nA: %s\nC: %s", msg, sk, si, sp, sa, sc);
+ return v;
+}
+
+void aes_eax_test(FILE** files, unsigned* count)
+{
+ const char* head[] = EAX_HEADLINES;
+ char buffer[0x400], *value = NULL;
+ size_t s[5] = { 0 };
+ uint8_t h, e = 0, key[32], iv[EAX_NONCE_LEN], p[32], c[48], a[32];
+
+ while (fgets(buffer, sizeof buffer, *files) != NULL)
+ {
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 5 : 0; h < 5; ++h)
+ {
+ if (strncmp(buffer, head[h], strlen(head[h])) != 0) continue;
+
+ value = strrchr(buffer, ' ') + 1;
+ s[h] = strlen(value) / 2 - EAX_TAG_LEN * (h == 4);
+ switch (h)
+ {
+ case 0:
+ str2bytes(value, p);
+ break;
+ case 1:
+ str2bytes(value, key);
+ break;
+ case 2:
+ if (s[2] == sizeof iv) str2bytes(value, iv);
+ break;
+ case 3:
+ str2bytes(value, a);
+ break;
+ case 4:
+ str2bytes(value, c);
+ break;
+ }
+ e += (h == 3 || h == 4);
+ }
+ if (e == 2)
+ {
+ if (s[1] == AES_KEYLENGTH && s[2] == EAX_NONCE_LEN && s[4] == *s)
+ {
+ e = verifyeax(key, iv, p, a, c, s[0], s[3], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
+ ++count[0];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
+ }
+ e = 0;
+ }
+ }
+}
+
+#endif /* header guard */
diff --git a/testvectors/aes_testvectors_FPE.h b/testvectors/aes_testvectors_FPE.h
index c751b25..7c6ef1d 100644
--- a/testvectors/aes_testvectors_FPE.h
+++ b/testvectors/aes_testvectors_FPE.h
@@ -2,119 +2,108 @@
==============================================================================
Name : aes_testvectors_FPE.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-FPE
==============================================================================
*/
-#ifndef _TESTING_FPE_H_
-#define _TESTING_FPE_H_
-
#include "aes_testvectors.h"
-#ifdef FPE_TEST_FILE
-static int verifyfpe(uint8_t* key, uint8_t* twk, char* a, char* p, char* c,
- size_t np, size_t nt, char* r)
+#if defined(_TESTING_FPE_H_) ^ defined(FPE_TEST_FILE)
+#define _TESTING_FPE_H_
+#include "../micro_fpe.h"
+
+int verifyfpe(uint8_t* key, uint8_t* twk, const char* a, char* p, char* c,
+ size_t np, size_t nt, char* r)
{
- char sk[2 * AES_KEY_SIZE + 1], st[65], msg[30], tmp[0x800], v = 0;
- strcpy(msg, "passed the test");
#if FF_X == 3
- AES_FPE_encrypt(key, twk, p, np, tmp);
+#define TWK_ARGS twk
#else
- AES_FPE_encrypt(key, twk, nt, p, np, tmp);
+#define TWK_ARGS twk, nt
#endif
+ char sk[2 * AES_KEYLENGTH + 1], st[65], msg[30], tmp[0x800], v = 0;
+ strcpy(msg, "passed the test");
+
+ AES_FPE_encrypt(key, TWK_ARGS, p, np, tmp);
if (memcmp(c, tmp, np))
{
strcpy(msg, "encrypt failure");
v = 1;
}
memset(tmp, 0xcc, sizeof tmp);
-#if FF_X == 3
- *sk = AES_FPE_decrypt(key, twk, c, np, tmp);
-#else
- *sk = AES_FPE_decrypt(key, twk, nt, c, np, tmp);
-#endif
- if (*sk || memcmp(p, tmp, np))
+ *r = AES_FPE_decrypt(key, TWK_ARGS, c, np, tmp);
+ if (*r || memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(key, sk, AES_KEYLENGTH);
bytes2str(twk, st, nt);
sprintf(r, "%s\nA: %s\nK: %s\nT: %s\nP: %s\nC: %s", msg, a, sk, st, p, c);
return v;
}
-static void aes_fpe_test(FILE** files, unsigned* count)
+void aes_fpe_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = FPE_HEADLINES, *alphabets[] = FPE_ALPHABETS;
- char buffer[0x1000], alpha[90], p[0x800], c[0x800], m[6], a = 0, *value = NULL;
- size_t s[3] = { 0 };
- uint8_t j, key[2 * AES_KEY_SIZE], twk[32], n = 0;
+ const char *head[] = FPE_HEADLINES, *alphabets[] = FPE_ALPHABETS, *a;
+ char buffer[0x1000], p[0x800], c[0x800], *value = NULL;
+ size_t s[6] = { 0 };
+ uint8_t h, key[32], twk[32], e = 0;
while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 6; j++)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 6 : 0; h < 6; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) == 0)
{
value = strrchr(buffer, ' ') + 1;
- n += j > 2;
+ s[h] = h ? strlen(value) : value[2] != '3'; /* is it FF1 */
+ e += (h == 3 || h == 4 || h == 5);
break;
}
}
- switch (j)
+ switch (h)
{
- case 0:
- strcpy(m, value);
- break;
case 1:
- for (j = 0; j < 9; j++)
- {
- if ((a = strlen(alphabets[j])) != strlen(value)) continue;
- if (strncmp(value, alphabets[j], a) == 0) break;
- }
- strcpy(alpha, value), a = j;
+ do
+ a = alphabets[h - 1];
+ while ((strlen(a) != s[1] || memcmp(a, value, s[1])) && h++ < 10);
+
+ s[1] = h - 1;
break;
case 2:
- s[0] = strlen(value) / 2;
+ s[2] /= 2;
str2bytes(value, key);
break;
case 3:
- s[1] = strlen(value) / 2;
+ s[3] /= 2;
str2bytes(value, twk);
break;
case 4:
- s[2] = strlen(value);
strcpy(p, value);
break;
case 5:
strcpy(c, value);
break;
}
- if (n == 3)
+ if (e == 3)
{
- n = (FF_X == 3) ^ (m[2] != '3');
-#if FF3_TWEAK_LEN == 8
- n &= s[1] == 8; /* old FF3 with 8-byte tweak */
-#else
- n &= FF_X != 3 || s[1] != 8 || !twk[7]; /* FF3-1 */
+#if FF_X == 3
+ s[0] = !*s && (s[3] == FF3_TWEAK_LEN || !(twk[3] + twk[7]));
#endif
- if (n && a == CUSTOM_ALPHABET && s[0] == AES_KEY_SIZE)
+ if (s[0] && s[1] == CUSTOM_ALPHABET && s[2] == AES_KEYLENGTH)
{
- n = verifyfpe(key, twk, alpha, p, c, s[2], s[1], buffer);
- fprintf(files[2 - !n], "%s\n\n", buffer); /* save the log */
+ e = verifyfpe(key, twk, a, p, c, s[4], s[3], buffer);
+ fprintf(files[2 - !e], "%s\n\n", buffer); /* save the log */
++count[0];
- if (n & 1) ++count[1];
- if (n & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- n = 0;
+ e = 0;
}
}
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_GCM.h b/testvectors/aes_testvectors_GCM.h
index 824fa38..e52d54a 100644
--- a/testvectors/aes_testvectors_GCM.h
+++ b/testvectors/aes_testvectors_GCM.h
@@ -2,108 +2,98 @@
==============================================================================
Name : aes_testvectors_GCM.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-GCM
==============================================================================
*/
-#ifndef _TESTING_GCM_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_GCM_H_) ^ defined(GCM_TEST_FILE)
#define _TESTING_GCM_H_
-#include "aes_testvectors.h"
-#ifdef GCM_TEST_FILE
-
-static int verifygcm(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
- size_t np, size_t na, uint8_t nt, char* r)
+int verifygcm(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, char* r)
{
char sk[65], si[2 * GCM_NONCE_LEN + 1], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[0x80], v = 0;
strcpy(msg, "passed the test");
- AES_GCM_encrypt(key, i, p, np, a, na, tmp, tmp + np);
- if (memcmp(c, tmp, np + nt))
+ AES_GCM_encrypt(key, i, a, na, p, np, tmp);
+ if (memcmp(c, tmp, np + GCM_TAG_LEN))
{
strcpy(msg, "encrypt failure");
v = 1;
}
memset(tmp, 0xcc, sizeof tmp);
- *sk = AES_GCM_decrypt(key, i, c, np, a, na, nt, tmp);
- if (*sk || memcmp(p, tmp, np))
+ *r = AES_GCM_decrypt(key, i, a, na, c, np, tmp);
+ if (*r || memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(key, sk, AES_KEYLENGTH);
bytes2str(i, si, GCM_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
- bytes2str(c, sc, np + nt);
+ bytes2str(c, sc, np + GCM_TAG_LEN);
sprintf(r, "%s\nK: %s\ni: %s\nP: %s\nA: %s\nC: %s", msg, sk, si, sp, sa, sc);
return v;
}
-static void aes_gcm_test(FILE** files, unsigned* count)
+void aes_gcm_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = GCM_HEADLINES;
- char buffer[0x800], *value = NULL, *line = NULL;
+ const char* head[] = GCM_HEADLINES;
+ char buffer[0x800], *value = NULL;
size_t s[6] = { 0 };
- uint8_t key[AES_KEY_SIZE], tmp[AES_KEY_SIZE], iv[GCM_NONCE_LEN];
- uint8_t j, p[96], c[112], a[96], t[16], r = 1;
+ uint8_t h, e = 0, key[32], iv[GCM_NONCE_LEN], p[96], c[112], a[96];
- do
+ while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- if ((line = fgets(buffer, sizeof buffer, *files)) != NULL)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 6 : 0; h < 6; ++h)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- }
- for (j = 0; j < 6; j++)
- {
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) != 0) continue;
+
+ value = strrchr(buffer, ' ') + 1;
+ s[h] = strlen(value) / 2;
+ switch (h)
{
- value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
+ case 0:
+ str2bytes(value, key);
+ break;
+ case 1:
+ if (s[1] == sizeof iv) str2bytes(value, iv);
+ break;
+ case 2:
+ str2bytes(value, a);
+ break;
+ case 3:
+ str2bytes(value, p);
+ break;
+ case 4:
+ str2bytes(value, c);
+ break;
+ case 5:
+ str2bytes(value, c + s[4]);
break;
}
+ e += (h == 3 || h == 4 || h == 5);
}
- switch (j)
+ if (e == 3)
{
- case 0:
- if (s[0] == AES_KEY_SIZE) str2bytes(value, tmp);
- break;
- case 1:
- if (s[1] == GCM_NONCE_LEN) str2bytes(value, iv);
- break;
- case 2:
- str2bytes(value, a);
- break;
- case 3:
- str2bytes(value, p);
- break;
- case 4:
- str2bytes(value, c);
- break;
- case 5:
- str2bytes(value, t);
- break;
- }
- if (j == 0 || line == NULL)
- {
- if (!r && s[1] == GCM_NONCE_LEN && s[0] == AES_KEY_SIZE)
+ if (AES_KEYLENGTH == *s && GCM_NONCE_LEN == s[1] && s[5] >= GCM_TAG_LEN)
{
- memcpy(c + s[3], t, s[5]); /* put the tag at the end */
- r = verifygcm(key, iv, p, a, c, s[3], s[2], s[5], buffer);
- fprintf(files[2 - !r], "%s\n", buffer); /* save the log */
+ e = verifygcm(key, iv, p, a, c, s[3], s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (r & 1) ++count[1];
- if (r & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- memcpy(key, tmp, sizeof key);
- r = 0;
+ e = 0;
}
- } while (line != NULL);
+ }
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_GCMSIV.h b/testvectors/aes_testvectors_GCMSIV.h
index dc69176..a7c41a6 100644
--- a/testvectors/aes_testvectors_GCMSIV.h
+++ b/testvectors/aes_testvectors_GCMSIV.h
@@ -2,100 +2,95 @@
==============================================================================
Name : aes_testvectors_GCMSIV.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-GCM-SIV
==============================================================================
*/
-#ifndef _TESTING_GCMSIV_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_GCMSIV_H_) ^ defined(GCMSIV_TEST_FILE)
#define _TESTING_GCMSIV_H_
-#include "aes_testvectors.h"
-#ifdef GCMSIV_TEST_FILE
-
-static int verifygcmsiv(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
- size_t np, size_t na, char* r)
+int verifygcmsiv(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, char* r)
{
- char sk[2 * AES_KEY_SIZE + 1], si[25], sp[0x100], sc[0x100], sa[0x100], msg[30];
+ char sk[65], si[25], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[0x90], v = 0;
strcpy(msg, "passed the test");
- GCM_SIV_encrypt(key, i, p, np, a, na, tmp, tmp + np);
+ GCM_SIV_encrypt(key, i, a, na, p, np, tmp);
if (memcmp(c, tmp, np + 16))
{
strcpy(msg, "encrypt failure");
v = 1;
}
memset(tmp, 0xcc, sizeof tmp);
- *sk = GCM_SIV_decrypt(key, i, c, np, a, na, 16, tmp);
- if (*sk || memcmp(p, tmp, np))
+ *r = GCM_SIV_decrypt(key, i, a, na, c, np, tmp);
+ if (*r || memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, AES_KEY_SIZE);
- bytes2str(i, si, 12);
+ bytes2str(key, sk, AES_KEYLENGTH);
+ bytes2str(i, si, SIVGCM_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
- bytes2str(c, sc, np + 16);
+ bytes2str(c, sc, np + SIVGCM_TAG_LEN);
sprintf(r, "%s\nK: %s\ni: %s\nP: %s\nA: %s\nC: %s", msg, sk, si, sp, sa, sc);
return v;
}
-static void aes_gcmsiv_test(FILE** files, unsigned* count)
+void aes_gcmsiv_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = GCMSIV_HEADLINES;
+ const char* head[] = GCMSIV_HEADLINES;
char buffer[0x400], *value = NULL;
size_t s[5] = { 0 };
- uint8_t key[AES_KEY_SIZE], iv[12], p[80], c[96], a[80], j, n = 0;
+ uint8_t key[32], iv[12], p[80], c[96], a[80], h, e = 0;
while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 5; j++)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 5 : 0; h < 5; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) != 0) continue;
+
+ value = strrchr(buffer, ' ') + 1;
+ s[h] = strlen(value) / 2;
+ switch (h)
{
- value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
- n += j > 2;
+ case 0:
+ str2bytes(value, key);
+ break;
+ case 1:
+ str2bytes(value, iv);
+ break;
+ case 2:
+ str2bytes(value, a);
+ break;
+ case 3:
+ str2bytes(value, p);
+ break;
+ case 4:
+ str2bytes(value, c);
break;
}
+ e += (h == 3 || h == 4);
}
- switch (j)
+ if (e == 2)
{
- case 0:
- if (s[0] == AES_KEY_SIZE) str2bytes(value, key);
- break;
- case 1:
- if (s[1] == 12) str2bytes(value, iv);
- break;
- case 2:
- str2bytes(value, a);
- break;
- case 3:
- str2bytes(value, p);
- break;
- case 4:
- str2bytes(value, c);
- break;
- }
- if (n == 2)
- {
- if (s[0] == AES_KEY_SIZE)
+ if (s[0] == AES_KEYLENGTH)
{
- n = verifygcmsiv(key, iv, p, a, c, s[3], s[2], buffer);
- fprintf(files[2 - !n], "%s\n", buffer); /* save the log */
+ e = verifygcmsiv(key, iv, p, a, c, s[3], s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (n & 1) ++count[1];
- if (n & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- n = 0;
+ e = 0;
}
}
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_OCB.h b/testvectors/aes_testvectors_OCB.h
index f3adce0..d19403d 100644
--- a/testvectors/aes_testvectors_OCB.h
+++ b/testvectors/aes_testvectors_OCB.h
@@ -2,39 +2,38 @@
==============================================================================
Name : aes_testvectors_OCB.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-OCB
==============================================================================
*/
-#ifndef _TESTING_OCB_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_OCB_H_) ^ defined(OCB_TEST_FILE)
#define _TESTING_OCB_H_
-#include "aes_testvectors.h"
-#ifdef OCB_TEST_FILE
-
-static int verifyocb(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
- size_t np, size_t na, uint8_t err, char* r)
+int verifyocb(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, uint8_t err, char* r)
{
- char sk[2 * AES_KEY_SIZE + 1], si[31], sp[0x100], sc[0x100], sa[0x100], msg[30];
+ char sk[65], si[31], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[0x90], v = 0;
strcpy(msg, "passed the test");
- AES_OCB_encrypt(key, i, p, np, a, na, tmp, tmp + np);
+ AES_OCB_encrypt(key, i, a, na, p, np, tmp);
if (memcmp(c, tmp, np + OCB_TAG_LEN) && !err)
{
strcpy(msg, "encrypt failure");
v = 1;
}
memset(tmp, 0xcc, sizeof tmp);
- *sk = AES_OCB_decrypt(key, i, c, np, a, na, OCB_TAG_LEN, tmp) && !err;
- if (*sk || memcmp(p, tmp, np))
+ *r = AES_OCB_decrypt(key, i, a, na, c, np, tmp);
+ if (*r && !err || memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(key, sk, AES_KEYLENGTH);
bytes2str(i, si, OCB_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
@@ -43,34 +42,32 @@ static int verifyocb(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* a, uint8_t*
return v;
}
-static void aes_ocb_test(FILE** files, unsigned* count)
+void aes_ocb_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = OCB_HEADLINES;
+ const char* head[] = OCB_HEADLINES;
char buffer[0x800], *value = NULL;
size_t s[7] = { 0 };
- uint8_t key[AES_KEY_SIZE], tmp[AES_KEY_SIZE], iv[OCB_NONCE_LEN];
- uint8_t j, p[0x80], c[0x90], a[0x80], t[16], r = 1;
+ uint8_t h, e, key[2 * AES_KEYLENGTH], iv[16], p[0x80], c[0x90], a[0x80];
while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 7; j++)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 7 : 0; h < 7; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) == 0)
{
value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
+ s[h] = strlen(value) / 2;
break;
}
}
- switch (j)
+ switch (h)
{
case 0:
- if (s[0] == AES_KEY_SIZE) str2bytes(value, tmp);
+ if (s[0] == AES_KEYLENGTH) str2bytes(value, key + *s);
break;
case 1:
- if (s[1] == OCB_NONCE_LEN) str2bytes(value, iv);
+ str2bytes(value, iv);
break;
case 2:
str2bytes(value, a);
@@ -82,30 +79,26 @@ static void aes_ocb_test(FILE** files, unsigned* count)
str2bytes(value, c);
break;
case 5:
- s[5] -= OCB_TAG_LEN;
- str2bytes(value, t);
+ str2bytes(value, c + sizeof p);
break;
case 6:
- j = strstr(value, "ERROR") - value;
- j = 7 + (j > 0 && j < 0x100);
+ h = strstr(value, "ERROR") != NULL ? 8 : 0;
break;
}
- if (j == 0 || j > 7)
+ if (h % 8 == 0 && s[0] == AES_KEYLENGTH)
{
- if (s[0] == AES_KEY_SIZE && s[1] == OCB_NONCE_LEN && !s[5] && !r)
+ if (s[1] == OCB_NONCE_LEN && s[5] == OCB_TAG_LEN)
{
- memcpy(c + s[3], t, OCB_TAG_LEN); /* put tag at the end */
- r = verifyocb(key, iv, p, a, c, s[3], s[2], j, buffer);
- fprintf(files[2 - !r], "%s\n", buffer); /* save the log */
+ memmove(c + s[4], c + sizeof p, s[5]); /* tag appended */
+ e = verifyocb(key, iv, p, a, c, s[3], s[2], h, buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (r & 1) ++count[1];
- if (r & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- memcpy(key, tmp, sizeof key);
- r = 0;
+ memcpy(key, key + *s, s[0]);
}
}
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_POLY1305.h b/testvectors/aes_testvectors_POLY1305.h
index 2804390..8797c61 100644
--- a/testvectors/aes_testvectors_POLY1305.h
+++ b/testvectors/aes_testvectors_POLY1305.h
@@ -2,64 +2,67 @@
==============================================================================
Name : aes_testvectors_POLY1305.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-POLY1305
==============================================================================
*/
-#ifndef _TESTING_POLY1305_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_POLY1305_H_) ^ defined(POLY_TEST_FILE)
#define _TESTING_POLY1305_H_
-#include "aes_testvectors.h"
-#ifdef POLY_TEST_FILE
-
-static int verifypoly(uint8_t* key, uint8_t* non, uint8_t* d, uint8_t* m,
- size_t nd, char* r)
+int verifypoly(uint8_t* key, uint8_t* non, uint8_t* d, uint8_t* m,
+ size_t nd, char* r)
{
- char sk[2 * AES_KEY_SIZE + 33], smac[33], msg[30];
+ char sk[2 * AES_KEYLENGTH + 33], smac[33], msg[30];
uint8_t tmp[16], v = 0;
strcpy(msg, "passed the test");
AES_Poly1305(key, non, d, nd, tmp);
if ((v = memcmp(m, tmp, 16)) != 0) strcpy(msg, "failed");
- bytes2str(key, sk, AES_KEY_SIZE + 16);
+ bytes2str(key, sk, AES_KEYLENGTH + 16);
bytes2str(m, smac, 16);
sprintf(r, "%s\nK: %s\npoly: %s\n", msg, sk, smac);
return v;
}
-static void aes_poly1305_test(FILE** files, unsigned* count)
+void aes_poly1305_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = POLY_HEADLINES;
- char buffer[0x20100], *value = NULL;
+ const char* head[] = POLY_HEADLINES;
size_t s[4] = { 0 };
- uint8_t j, n = 0, key[AES_KEY_SIZE + 16], nc[16], d[0x10100], m[16];
+ uint8_t h, *d, e = 0, key[AES_KEYLENGTH + 16], n[16], m[16];
+ char *value = NULL, *buffer;
count[2] = ~0U;
-
- while (fgets(buffer, sizeof buffer, *files) != NULL)
+ if ((buffer = malloc(LINES_MAX_LEN / 2 * 3)) == NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 4; j++)
+ printf("Memory allocation failed.\n");
+ return;
+ }
+ while (fgets(buffer, LINES_MAX_LEN, *files) != NULL)
+ {
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 4 : 0; h < 4; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) == 0)
{
value = strrchr(buffer, ' ') + 1;
- s[j] = strlen(value) / 2;
- n += j > 1;
+ d = (uint8_t*) &buffer[LINES_MAX_LEN];
+ s[h] = strlen(value) / 2;
+ e += (h == 2 || h == 3);
break;
}
}
- switch (j)
+ switch (h)
{
case 0:
- if (s[0] == AES_KEY_SIZE + 16) str2bytes(value, key);
+ if (s[0] == sizeof key) str2bytes(value, key);
break;
case 1:
- str2bytes(value, nc);
+ str2bytes(value, n);
break;
case 2:
str2bytes(value, d);
@@ -68,19 +71,19 @@ static void aes_poly1305_test(FILE** files, unsigned* count)
str2bytes(value, m);
break;
}
- if (n == 2)
+ if (e == 2)
{
- if (s[0] == AES_KEY_SIZE + 16)
+ if (s[0] == sizeof key)
{
- n = verifypoly(key, nc, d, m, s[2], buffer);
- fprintf(files[2 - !n], "%s\n", buffer); /* save the log */
+ e = verifypoly(key, n, d, m, s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (n) ++count[1];
+ count[1] += e != 0;
}
- n = 0;
+ e = 0;
}
}
+ free(buffer);
}
-#endif
#endif /* header guard */
diff --git a/testvectors/aes_testvectors_XTS.h b/testvectors/aes_testvectors_XTS.h
index b31a290..3ae8c60 100644
--- a/testvectors/aes_testvectors_XTS.h
+++ b/testvectors/aes_testvectors_XTS.h
@@ -2,22 +2,21 @@
==============================================================================
Name : aes_testvectors_XTS.h
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.2.0.0
Copyright : copyright © 2024 - polfosol
Description : checking the test vectors for AES-XTS
==============================================================================
*/
-#ifndef _TESTING_XTS_H_
+#include "aes_testvectors.h"
+
+#if defined(_TESTING_XTS_H_) ^ defined(XTS_TEST_FILE)
#define _TESTING_XTS_H_
-#include "aes_testvectors.h"
-#ifdef XTS_TEST_FILE
-
-static int verifyxts(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* c,
- size_t np, char* r)
+int verifyxts(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* c,
+ size_t np, char* r)
{
- char sk[4 * AES_KEY_SIZE + 1], si[33], sp[0x80], sc[0x80], msg[30];
+ char sk[4 * AES_KEYLENGTH + 1], si[33], sp[0x80], sc[0x80], msg[30];
uint8_t tmp[0x80], v = 0;
strcpy(msg, "passed the test");
@@ -31,10 +30,10 @@ static int verifyxts(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* c,
AES_XTS_decrypt(key, i, c, np, tmp);
if (memcmp(p, tmp, np))
{
- sprintf(msg, "%sdecrypt failure", v ? "encrypt & " : "");
+ strcat(strcpy(msg, v ? "encrypt & " : ""), "decrypt failure");
v |= 2;
}
- bytes2str(key, sk, 2 * AES_KEY_SIZE);
+ bytes2str(key, sk, 2 * AES_KEYLENGTH);
bytes2str(i, si, 16);
bytes2str(p, sp, np);
bytes2str(c, sc, np);
@@ -42,31 +41,30 @@ static int verifyxts(uint8_t* key, uint8_t* i, uint8_t* p, uint8_t* c,
return v;
}
-static void aes_xts_test(FILE** files, unsigned* count)
+void aes_xts_test(FILE** files, unsigned* count)
{
- const char *linehdr[] = XTS_HEADLINES;
+ const char* head[] = XTS_HEADLINES;
char buffer[0x800], *value = NULL;
- size_t s = 0, sk = 0;
- uint8_t j, n = 0, key[2 * AES_KEY_SIZE], iv[16], p[0x80], c[0x80], ul[2];
+ size_t s[5] = { 0 };
+ uint8_t h, e = 0, key[2 * AES_KEYLENGTH], iv[16], p[0x80], c[0x80];
while (fgets(buffer, sizeof buffer, *files) != NULL)
{
- buffer[strcspn(buffer, "\n")] = 0;
- if (strlen(buffer) < 4) continue;
- for (j = 0; j < 5; j++)
+ buffer[ strcspn(buffer, "\n") ] = 0;
+ for (h = strlen(buffer) < 4 ? 5 : 0; h < 5; ++h)
{
- if (strncmp(buffer, linehdr[j], strlen(linehdr[j])) == 0)
+ if (strncmp(buffer, head[h], strlen(head[h])) == 0)
{
value = strrchr(buffer, ' ') + 1;
- n += (j == 2 || j == 3);
+ s[h] = strlen(value) / 2;
+ e += (h == 2 || h == 3);
break;
}
}
- switch (j)
+ switch (h)
{
case 0:
- sk = strlen(value) / 4;
- if (sk == AES_KEY_SIZE) str2bytes(value, key);
+ if (s[0] == sizeof key) str2bytes(value, key);
break;
case 1:
str2bytes(value, iv);
@@ -78,24 +76,22 @@ static void aes_xts_test(FILE** files, unsigned* count)
str2bytes(value, c);
break;
case 4:
- str2bytes(value, ul);
- s = (ul[0] >> 4) *100 + (ul[0] & 15) *10 + (ul[1] >> 4);
+ for (s[4] = 0; *value; s[4] *= 10) s[4] += *value++ - '0';
break;
}
- if (n == 2)
+ if (e == 2)
{
- if (sk == AES_KEY_SIZE && s % 8 == 0)
+ if (s[0] == sizeof key && s[4] == s[2] * 80)
{
- n = verifyxts(key, iv, p, c, s / 8, buffer);
- fprintf(files[2 - !n], "%s\n", buffer); /* save the log */
+ e = verifyxts(key, iv, p, c, s[2], buffer);
+ fprintf(files[2 - !e], "%s\n", buffer); /* save the log */
++count[0];
- if (n & 1) ++count[1];
- if (n & 2) ++count[2];
+ if (e & 1) ++count[1];
+ if (e & 2) ++count[2];
}
- n = 0;
+ e = 0;
}
}
}
-#endif
#endif /* header guard */