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**. -[![this](https://img.shields.io/badge/%C2%B5AES-white.png?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFGklEQVR42r1XA5RjSxD9Wtu2bWX2e23btm3btm17Nxpmx8zYiK3XLzO/6vz0nuxb7yQ759xJ0l1V93Z1tX762r+cnJyCFoulJnxWART5Cvu8n+n+atLShJBlgCCi1WrtsbEpbHx8CnzXQZsUsAtEVef6sSzb12w1m6FfAXgIv/tgO8MwF+C3HuAL2Avxy3ySHIynEr1eyW7dKrB37ChlW7fOBuRQ2D084sjcuXwik8mA4AAEy099IbhXlVlV/POMzqPusb2HAAltNlsjaZo0Fdp0xSYVi3wc+DgEOCZ9bNS/QMc5wucHs+3apSLZZ9GmjZ5cveoDJBLwLQm+zcOTwxN/G/VbNiBnzvk5KGAFiDzRbWs3AbYBbCmKlEywr8zlx/QdJvfvSyA4gwRfiWx240Yk8gEB5ztt7kSJTHKdXA6jb6A1apUweg22N17S2AtsH3yMfCATEhIDAU1cEjuPF0tGjhSSceP49n/+CYE2O8fGjsJ1Zp2JErVZ1UYEgq4B5q25uUaEbQhMPwjo9kHqoTGcdOoU+F7gtm0zyNOnflh0IPAQFh6OlISERENtRL1n2727ZO2NtWJKJIwQRoHtn4AonHdsKzKhSDTEiUW+9wSgIfH2DuPMr46Ni0uCvgVcB6x0VqPJYni8eGpP9u8XlZteLgiJik4oiuRhaPcs+FkYFbXo0iIhtC/CGFwBe8iMGQJnATiv2P6ZlTKdvHz5LmMmiV84kLBIVGF6hUDozzKajRn4nQp44P8A0/8CBpSHK+CJvVOnIOfCIqmpGWBY6TP7xG/Eas2A1ZKFPno/LxyplZLlH5s/Jf+Y/Jn0NwLqQ2+wGPTgW4wrQGz/448op/RroS3zI7xcv5dQlMHoQ+bP548/Oh5XgJ0S4pRg0RUcVzABfzdf1lwMPne4IykGjTFY6c7zD20qwLYvIAKLj64Ext8/qvKMyv604KA/C7DLxtiU/HB+ZKIsEX//4UxeGBqi2ePHxbipOE0Bw/bv7/01AD+5Q7QxPjYkDsgJClhxbYUIC5hOF9RES/jN4xbSHPbECTEGyDXGjRMO3DuQ75hrncagUQBxiS/N4Wpa/bmFOdA/Kt/ofFko4M+NfwphCZ5Gjh8igPz9d/DeJ3u9kRyQHZAQEA/ZbfXjBJw/74UVT/cAPAExvisFMOzAgV7s8OHcYsXtWuEv9Y6iJ+CBpwd8IP1jXSqAPH7sj2se0nqdjYjA5Wp51zdvHt9jnYfQsflkmS1mPGoLuE5Au3YpMKI4CPqrw+cZ6dFDQjcsVWxEfJ5ReQwoYPC+wXzo34l2LhMAJCpiMOC2XN7h85bufriEeWt5QiQHkISshAyr1VrLtQIAZM0aPJg2OE7ChJTU2DTy4IHEpFKo6dYL6U+HKUqksV1bhKtWYWqXQxYKAYkJDxrcanc92uWF5Ihpp6bxoe+yWwSQmzd9YeQD8HbjG+sb3XJFSzGS0ttPwfEF4+HqlQoCy7pFgF0qjYe5rYPnBpIhqRPo5XM5xnSHAAuc+wxeQOC+z+ClkiPAqNAp5Dh69wiAjQangGRmKrpv7y4oMblEhLOAdqvb4eXzEsZziwAKMnq06Ib3Nf+qs6u+LTu1bDAV4CX1wnPfw+0CEHgTZqOjEyvP+v/SUWZKGbzjBX/3+w8rm0gkEfQt8DUgly550zo4zT8twWfc9/LTLOxjMzOziL9/5NeAzcjAa5UyWZEsg88AfBe64iVcAp/fX4ka+E4AlAH8lhve/wC9phuOb7e8lwAAAABJRU5ErkJggg==)](../../ "µAES") ![C](https://img.shields.io/badge/langauge-C-blue.svg) [![version](https://img.shields.io/badge/version-1.9.3-blue)](../../../../user-attachments/files/18098067/micro_aes-v1.9.3.zip "µAES-v1.9.3.zip") [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![this](https://img.shields.io/badge/%C2%B5AES-white.png?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFGklEQVR42r1XA5RjSxD9Wtu2bWX2e23btm3btm17Nxpmx8zYiK3XLzO/6vz0nuxb7yQ759xJ0l1V93Z1tX762r+cnJyCFoulJnxWART5Cvu8n+n+atLShJBlgCCi1WrtsbEpbHx8CnzXQZsUsAtEVef6sSzb12w1m6FfAXgIv/tgO8MwF+C3HuAL2Avxy3ySHIynEr1eyW7dKrB37ChlW7fOBuRQ2D084sjcuXwik8mA4AAEy099IbhXlVlV/POMzqPusb2HAAltNlsjaZo0Fdp0xSYVi3wc+DgEOCZ9bNS/QMc5wucHs+3apSLZZ9GmjZ5cveoDJBLwLQm+zcOTwxN/G/VbNiBnzvk5KGAFiDzRbWs3AbYBbCmKlEywr8zlx/QdJvfvSyA4gwRfiWx240Yk8gEB5ztt7kSJTHKdXA6jb6A1apUweg22N17S2AtsH3yMfCATEhIDAU1cEjuPF0tGjhSSceP49n/+CYE2O8fGjsJ1Zp2JErVZ1UYEgq4B5q25uUaEbQhMPwjo9kHqoTGcdOoU+F7gtm0zyNOnflh0IPAQFh6OlISERENtRL1n2727ZO2NtWJKJIwQRoHtn4AonHdsKzKhSDTEiUW+9wSgIfH2DuPMr46Ni0uCvgVcB6x0VqPJYni8eGpP9u8XlZteLgiJik4oiuRhaPcs+FkYFbXo0iIhtC/CGFwBe8iMGQJnATiv2P6ZlTKdvHz5LmMmiV84kLBIVGF6hUDozzKajRn4nQp44P8A0/8CBpSHK+CJvVOnIOfCIqmpGWBY6TP7xG/Eas2A1ZKFPno/LxyplZLlH5s/Jf+Y/Jn0NwLqQ2+wGPTgW4wrQGz/448op/RroS3zI7xcv5dQlMHoQ+bP548/Oh5XgJ0S4pRg0RUcVzABfzdf1lwMPne4IykGjTFY6c7zD20qwLYvIAKLj64Ext8/qvKMyv604KA/C7DLxtiU/HB+ZKIsEX//4UxeGBqi2ePHxbipOE0Bw/bv7/01AD+5Q7QxPjYkDsgJClhxbYUIC5hOF9RES/jN4xbSHPbECTEGyDXGjRMO3DuQ75hrncagUQBxiS/N4Wpa/bmFOdA/Kt/ofFko4M+NfwphCZ5Gjh8igPz9d/DeJ3u9kRyQHZAQEA/ZbfXjBJw/74UVT/cAPAExvisFMOzAgV7s8OHcYsXtWuEv9Y6iJ+CBpwd8IP1jXSqAPH7sj2se0nqdjYjA5Wp51zdvHt9jnYfQsflkmS1mPGoLuE5Au3YpMKI4CPqrw+cZ6dFDQjcsVWxEfJ5ReQwoYPC+wXzo34l2LhMAJCpiMOC2XN7h85bufriEeWt5QiQHkISshAyr1VrLtQIAZM0aPJg2OE7ChJTU2DTy4IHEpFKo6dYL6U+HKUqksV1bhKtWYWqXQxYKAYkJDxrcanc92uWF5Ihpp6bxoe+yWwSQmzd9YeQD8HbjG+sb3XJFSzGS0ttPwfEF4+HqlQoCy7pFgF0qjYe5rYPnBpIhqRPo5XM5xnSHAAuc+wxeQOC+z+ClkiPAqNAp5Dh69wiAjQangGRmKrpv7y4oMblEhLOAdqvb4eXzEsZziwAKMnq06Ib3Nf+qs6u+LTu1bDAV4CX1wnPfw+0CEHgTZqOjEyvP+v/SUWZKGbzjBX/3+w8rm0gkEfQt8DUgly550zo4zT8twWfc9/LTLOxjMzOziL9/5NeAzcjAa5UyWZEsg88AfBe64iVcAp/fX4ka+E4AlAH8lhve/wC9phuOb7e8lwAAAABJRU5ErkJggg==)](../../ "µAES") +![C](https://img.shields.io/badge/langauge-C-blue.svg) +[![version](https://img.shields.io/badge/version-1.11.0-blue)](../../../../user-attachments/files/22698833/micro_aes-v1.11.0.zip "µAES-v1.11.0.zip") +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](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 */