diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..2e9c7d7
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,23 @@
+{
+ "configurations": [
+ {
+ "name": "GCC",
+ "includePath": [
+ "${workspaceFolder}/**"
+ ],
+ "defines": [
+ "_DEBUG",
+ "UNICODE",
+ "_UNICODE"
+ ],
+ "compilerPath": "/usr/bin/gcc",
+ "cStandard": "c89",
+ "cppStandard": "c++17",
+ "intelliSenseMode": "gcc-x64",
+ "compilerArgs": [
+ "-pedantic"
+ ]
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..86c67fc
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,34 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "C/C++: gcc build and debug active file",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "${fileDirname}/bin/${fileBasenameNoExtension}.out",
+ "args": [],
+ "stopAtEntry": false,
+ "cwd": "${fileDirname}",
+ "environment": [],
+ "externalConsole": false,
+ "MIMode": "gdb",
+ "miDebuggerPath": "/usr/bin/gdb",
+ "setupCommands": [
+ {
+ "description": "Enable pretty-printing for gdb",
+ "text": "-enable-pretty-printing",
+ "ignoreFailures": true
+ },
+ {
+ "description": "Set Disassembly Flavor to Intel",
+ "text": "-gdb-set disassembly-flavor intel",
+ "ignoreFailures": true
+ }
+ ],
+ "preLaunchTask": "C/C++: gcc build active file"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..cddef93
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,28 @@
+{
+ "tasks": [
+ {
+ "type": "cppbuild",
+ "label": "C/C++: gcc build active file",
+ "command": "gcc",
+ "args": [
+ "-fdiagnostics-color=always",
+ "-g",
+ "${workspaceFolder}/*.c",
+ "-o",
+ "${fileDirname}/bin/${fileBasenameNoExtension}.out"
+ ],
+ "options": {
+ "cwd": "${fileDirname}"
+ },
+ "problemMatcher": [
+ "$gcc"
+ ],
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "detail": "Building microAES with GCC/VScode."
+ }
+ ],
+ "version": "2.0.0"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 7ac2ebf..62be214 100644
--- a/README.md
+++ b/README.md
@@ -1,61 +1,80 @@
-# µAES
+# **µAES**
-**A minimalist ANSI-C compatible code for most of the AES-related algorithms**.
+**A minimalist ANSI-C compatible API for the AES encryption and block cipher modes**.
-[](https://github.com/polfosol/micro-AES)  [](https://github.com/polfosol/micro-AES/files/10149095/micro_aes-v1.2.0.zip) [](https://opensource.org/licenses/Apache-2.0)
+[](../../ "µAES")  [](../../files/12339506/micro_aes-v1.8.0.zip "micro_aes-v1.8.0.zip") [](https://opensource.org/licenses/Apache-2.0)
-This library is a highly flexible and portable implementation of different AES encryption schemes and block cipher modes.
+This is a highly flexible, small and portable implementation of most of the AES related algorithms.
## Features
-* $\textrm{\textbf{Comprehensive}}$ — supports all standard AES key sizes (128, 192 and 256 bits) along with almost every block-cipher mode.
+* Comprehensive — supports all standard AES key sizes (128, 192 and 256 bits) along with almost every block-cipher mode.
- All popular (and some unpopular) block ciphering modes of the AES are implemented in this library, such as [**_ECB_**, **_CBC_**, **_CFB_**, **_OFB_**, **_CTR_**](https://csrc.nist.gov/publications/detail/sp/800-38a/final), [**_GCM_**](https://csrc.nist.gov/publications/detail/sp/800-38d/final), [**_CCM_**](https://csrc.nist.gov/publications/detail/sp/800-38c/final), [**_XTS_**](https://csrc.nist.gov/publications/detail/sp/800-38e/final), [**_OCB_**](https://www.rfc-editor.org/rfc/rfc7253.html), [**_EAX_**](https://en.wikipedia.org/wiki/EAX_mode), [**_KW_** (**_KWA_**)](https://csrc.nist.gov/publications/detail/sp/800-38f/final), [**_SIV_**](https://www.rfc-editor.org/rfc/rfc5297.html), [**_GCM-SIV_**](https://www.rfc-editor.org/rfc/rfc8452.html), [**_FPE_**](https://csrc.nist.gov/publications/detail/sp/800-38g/final), and furthermore, authentication APIs for [**_CMAC_**](https://csrc.nist.gov/publications/detail/sp/800-38b/final) and [**_Poly1305-AES_**](https://cr.yp.to/mac.html).
+ All popular (and some unpopular) block ciphering modes of the AES are implemented in this library, such as [**_ECB_**, **_CBC_**, **_CFB_**, **_OFB_**, **_CTR_**](https://csrc.nist.gov/publications/detail/sp/800-38a/final "Described in NIST SP 800-38A"), [**_GCM_**](https://csrc.nist.gov/publications/detail/sp/800-38d/final "NIST SP 800-38D"), [**_CCM_**](https://csrc.nist.gov/publications/detail/sp/800-38c/final "NIST SP 800-38C"), [**_XTS_**](https://csrc.nist.gov/publications/detail/sp/800-38e/final "NIST SP 800-38E"), [**_KW_**](https://csrc.nist.gov/publications/detail/sp/800-38f/final "NIST SP 800-38F") [(_KWA_)](https://www.rfc-editor.org/rfc/rfc3394 "RFC-3394"), [**_OCB_**](https://www.rfc-editor.org/rfc/rfc7253.html "RFC-7253"), [**_EAX_**](../../files/10318260/eax.pdf "Bellare-Rogaway-Wagner paper. For more info, see wikipedia.") / [**_EAX'_**](../../files/10318265/eax-prime.pdf "It is theoretically broken and shouldn't be used. The ANSI C12.22 has not withdrawn it yet, so here we go."), [**_SIV_**](../../files/10318348/siv.pdf "You may also refer to the RFC-5297"), [**_GCM-SIV_**](https://www.rfc-editor.org/rfc/rfc8452.html "RFC-8452"), [**_FPE_** (**_FF1_** / **_FF3-1_**)](https://csrc.nist.gov/publications/detail/sp/800-38g/final "NIST SP 800-38G"), and furthermore, authentication APIs for [**_CMAC_**](https://csrc.nist.gov/publications/detail/sp/800-38b/final "NIST SP 800-38B") and [**_Poly1305-AES_**](../../files/10319003/poly1305.pdf "From D. J. Bernstein's website: cr.yp.to/mac.html").
-* $\textrm{\textbf{All in one}}$ — the whole implementation code is in a single C file with no external dependencies.
+* All in one — the whole implementation code is in a single C file with no external dependencies.
-* $\textrm{\textbf{Clear and readable code}}$ — hopefully, the code is 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.
+* 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.
-* $\textrm{\textbf{Flexible}}$ — many features of µAES are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These macros are defined in the header file `micro_aes.h` and comments are added for each of them to explain what they represent. *Please read those comments carefully before using the code*.
+* Flexible — most features are controllable by macros, so that you can just pick up what you need and disable the unnecessary parts. These macros are defined in [the header file](micro_aes.h) and comments are added for each of them to explain what they represent. *Please read those comments carefully before using the code*.
-* $\textrm{\textbf{Lightweight}}$ — the API has very little memory footprint and compiled code size. In my own tests, the amount of RAM used by the functions didn't exceed a few hundred bytes in most extreme cases. Moreover, the ROM space of µAES is optimized as much as possible. For example if you disable all other macros and just stick with the GCM, the compiled code size will be around **3KB** with `gcc -Os` on x86 machine for either AES-128-GCM or AES-256-GCM.
+* 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.
-* $\textrm{\textbf{Fast}}$ — the encryption or decryption speed is fairly high, especially when there is no authentication. Since code simplicity and minimizing memory usage was a top priority, some functions may not look so efficient speed-wise. But it is worth noting that faster methods are hardly portable or easy to understand. So it's no surprise that paralellization or advanced CPU optimizations are not a feature of µAES —which will affect its overall speed.
+ For example if you disable all other macros and just stick with the GCM, the compiled code size with `gcc -Os` will be less than **3KB** for either _AES-128-GCM_ or _AES-256-GCM_. You can verify this by running:
+ ```
+ $ arm-none-eabi-gcc -Os -c micro_aes.c -o arm.o
+ $ avr-gcc -mmcu=atmega16 -Os -c micro_aes.c -o avr.o
+ ```
+ and checking the results with `size` command. See [this page](https://stackoverflow.com/q/31217181/5358284) for more info.
+ ```
+ $ size arm.o
+ text data bss dec hex filename
+ 2092 0 176 2268 8dc arm.o
- As a side note, speed is not always a blessing in cryptography and sometimes slower codes turn out to be more secure. One must be wary of those speedups that make the code more susceptible to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
+ $ avr-size avr.o
+ text data bss dec hex filename
+ 2246 0 176 2422 976 avr.o
+ ```
-* $\textrm{\textbf{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.
+* 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/):
+ ```
+ path/to/tcc.exe -c micro_aes.c
+ path/to/tcc.exe micro_aes.c -run main.c
+ ```
+
+* Fast — the encryption or decryption speed is fairly high, especially when there is no authentication. Since code simplicity and minimizing memory usage was a top priority, some functions may not look so efficient speed-wise; though faster methods are hardly portable or easy to understand. As a result, paralellization or advanced CPU optimizations are not a feature of µAES —which might affect its overall speed.
+
+ For 32-bit CPUs a few tweaks are discussed in [x86 improvements](x86-improvements). It's worth noting that speed is not always a blessing in cryptography and sometimes slower codes turn out to be more secure. One must be wary of those speedups that make the code more susceptible to [timing attacks](https://en.wikipedia.org/wiki/Timing_attack).
- ```
- tcc -c main.c -o main.o
- tcc -c micro_aes.c -o micro_aes.o
- tcc -o micro_aes.exe main.o micro_aes.o
- ```
## Examples
-See the `main.c` file which has some example codes illustrating how to use the API functions, along with test vectors.
+See the [main C](main.c) file which has some example codes demonstrating how to use the API functions, along with test vectors. Also check out the [/testvectors](testvectors/README.md) directory.
## Remarks
* First, please keep in mind that most security experts strongly warn *against* implementing your own version of AES—or other ciphering algorithms; AND THEY ARE ABSOLUTELY RIGHT!
- Everyone who is becoming familiar with cryptography, should first sign [Jeff Moser's](https://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html) so-called "Foot Shooting Prevention Agreement". To save you a click and scroll, I have put a copy of it below (but it is recommended to follow the link and read that article if you haven't).
+ Everyone who is becoming familiar with cryptography, should first sign [Jeff Moser's](https://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html "A stick figure guide to AES") so-called "Foot Shooting Prevention Agreement". To save you a click and scroll, I have put a copy of it below (but please follow the link and read that article if you haven't).
With that in mind, I shall say that the main purpose of developing µAES was purely educational. I learned a lot during writing these codes and I hope that somebody, some day, would gain a bit of knowledge from it.
+* The code is optimized for small embedded systems and 8-bit microcontrollers with limited amount of memory. So for stronger CPUs it is plausible to speed-up the code [by applying some simple changes](x86-improvements). If you are working with an 8-bit microcontroller, it is recommended to take a look at Nigel Jones' rather old article "[Efficient C Code for 8-bit Microcontrollers](https://barrgroup.com/embedded-systems/how-to/efficient-c-code)". It contains some highly useful tips to better program such systems.
+
* For the sake of simplicity, it is often assumed that the input parameters of the functions are well defined, and the user knows what they're doing. As a result, a bunch of error checks are just skipped. Obviously, this is a naive and sometimes dangerous assumption. One must be aware that in a serious application, anything can be fed into the functions and they must take all the necessary precautions for erroneous parameters.
-* Part of µAES is palpably influenced by [kokke's tiny-AES](https://github.com/kokke/tiny-AES-c) library, but I have made some modifications to make it smaller and more efficient. I shall give kudos to their great effort which paved the way for many other branches.
+* µAES was originally influenced by [kokke's tiny-AES](https://github.com/kokke/tiny-AES-c) library, but I have made a handful of modifications to make it smaller and more efficient.
-
+
---
All the contents of this repository (except the ones that I didn't write!) are subject to the terms of Apache 2.0 license.
+
+
Copyright © 2022 - polfosol
-$In$ $sorrowful$ $memory$ $of$ [**_Mahsa Amini_**](https://en.wikipedia.org/wiki/Death_of_Mahsa_Amini) :black_heart:
+_In sorrowful memory of_ [**_Mahsa Amini_**](https://en.wikipedia.org/wiki/Death_of_Mahsa_Amini "MAY ALL THE DICTATORS ROT IN HELL") :black_heart:
diff --git a/images/header.png b/images/header.png
new file mode 100644
index 0000000..6c0c54a
Binary files /dev/null and b/images/header.png differ
diff --git a/images/logo-smooth.svg b/images/logo-smooth.svg
new file mode 100644
index 0000000..8065121
--- /dev/null
+++ b/images/logo-smooth.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/logo.png b/images/logo.png
new file mode 100644
index 0000000..f25e56a
Binary files /dev/null and b/images/logo.png differ
diff --git a/images/logo.svg b/images/logo.svg
new file mode 100644
index 0000000..a021705
--- /dev/null
+++ b/images/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/logo.xcf b/images/logo.xcf
new file mode 100644
index 0000000..93e15bd
Binary files /dev/null and b/images/logo.xcf differ
diff --git a/images/micro_aes.svg b/images/micro_aes.svg
new file mode 100644
index 0000000..7bd5981
--- /dev/null
+++ b/images/micro_aes.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/main.c b/main.c
index d763799..ac88bc3 100644
--- a/main.c
+++ b/main.c
@@ -2,378 +2,396 @@
==============================================================================
Name : main.c
Author : polfosol
- Version : 9.8.1.0
+ Version : 10
Copyright : copyright © 2022 - polfosol
Description : test vectors for µAES ™ library, mostly generated by Crypto++ ®
==============================================================================
*/
+#define HEXSTR_LENGTH 114 /* plaintext hex characters */
#include "micro_aes.h"
-#define TestStringSize 114 /* hex characters in plain-text */
-#define BuffL ((TestStringSize / 2 + 31) & ~15)
-
-static const char
- *masterKey = "0001020304050607 08090A0B0C0D0E0F 1011121314151617 18191A1B1C1D1E1F",
- *secretKey = "0011223344556677 8899AABBCCDDEEFF 0001020304050607 08090A0B0C0D0E0F",
- *cipherKey = "279fb74a7572135e 8f9b8ef6d1eee003 69c4e0d86a7b0430 d8cdb78070b4c55a",
- *iVec = "8ea2b7ca516745bf eafc49904b496089",
- *plainText = "c9f775baafa36c25 cd610d3c75a482ea dda97ca4864cdfe0 6eaf70a0ec0d7191\
- d55027cf8f900214 e634412583ff0b47 8ea2b7ca516745bf ea",
-#if AES_KEY_LENGTH == 16
- *ecbcipher = "5d00c273f8b2607d a834632dcbb521f4 697dd4ab20bb0645 32a6545e24e33ae9\
- f545176111f93773 dbecd262841cf83b 10d145e71b772cf7 a12889cda84be795",
-#if !CTS /* ↑↑ and ↓↓ both zero-padded plain text. */
- *cbccipher = "65c48fdf9fbd6261 28f2d8bac3f71251 75e7f4821fda0263 70011632779d7403\
- 7e9e2d298e154bc4 2dc7a9bc419b915d c119ef461ac4e1bc 8a7e36bf92b3b3d1",
-#else
- *cbccipher = "65c48fdf9fbd6261 28f2d8bac3f71251 75e7f4821fda0263 70011632779d7403\
- c119ef461ac4e1bc 8a7e36bf92b3b3d1 7e9e2d298e154bc4 2d",
-#endif
- *cfbcipher = "edab3105e673bc9e b9102539a9f457bc 245c14e1bff81b5b 4a4a147c988cb0a6\
- 3f9c56525efbe64a 876ad1d761d3fc93 59fb4f5b2354acd4 90",
- *ofbcipher = "edab3105e673bc9e b9102539a9f457bc d28c8e4c92995f5c d9426926be1e775d\
- e22b8ce4d0278b18 181b8bec93b9726f 959aa5d701d46102 f0",
-#if CTR_IV_LENGTH == 16
- *ctrcipher = "edab3105e673bc9e b9102539a9f457bc f2e2606dfa3f93c5 c51b910a89cddb67\
- 191a118531ea0427 97626c9bfd370426 fdf3f59158bf7d4d 43",
-#elif CTR_STARTVALUE == 1
- *ctrcipher = "6c6bae886c235d8c 7997d45c1bf0bca2 48b4bca9eb396d1b f6945e5b7a4fc10f\
- 488cfe76fd5eaeff 2b8fb469f78fa61e 285e4cf9b9aee3d0 a8",
-#endif
- *xtscipher = "10f9301a157bfceb 3eb9e7bd38500b7e 959e21ba3cc1179a d7f7d7d99460e695\
- 5e8bcb177571c719 6de58ff28c381913 e7c82d0adfd90c45 ca",
- *ccmcipher = "d2575123438338d7 0b2955537fdfcf41 729870884e85af15 f0a74975a72b337d\
- 04d426de87594b9a be3e6dcf07f21c99 db3999f81299d302 ad1e5ba683e9039a\
- 5483685f1bd2c3fa 3b", /* <---- with 16 bytes tag */
- *gcmcipher = "5ceab5b7c2d6dede 555a23c7e3e63274 4075a51df482730b a31485ec987ddcc8\
- 73acdcfc6759a47b a424d838e7c0cb71 b9a4d8f4572e2141 18c8ab284ca845c1\
- 4394618703cddf3a fb", /* <---- with 16 bytes tag */
- *ocbcipher = "fc254896eb785b05 dd87f240722dd935 61f5a0ef6aff2eb6 5953da0b26257ed0\
- d69cb496e9a0cb1b f646151aa07e629a 28d99f0ffd7ea753 5c39f440df33c988\
- c55cbcc8ac086ffa 23", /* <---- with 16 bytes tag */
-#if EAXP
- *eaxcipher = "f516e9c20069292c c51ba8b6403ddedf 5a34798f62187f58 d723fa33573fd80b\
- f08ffbb09dadbd0b 6fa4812ca4bb5e6d db9a384943b36690 e81738a7a1",
-#else /* ↑↑↑↑ with 4 bytes tag */
- *eaxcipher = "4e2fa1bef9ffc23f 6965ee7135981c91 af9bfe97a6b13c01 b8b99e114dda2391\
- 50661c618335a005 47cca55a8f22fbd5 ed5ab4b4a17d0aa3 29febd14ef271bae\
- 986810a504f01ec6 02", /* <---- with 16 bytes tag */
-#endif
- *gsvcipher = "2f1488496ada3f70 9760420ac72e5acf a977f6add4c55ac6 85f1b9dff8f381e0\
- 2a64bbdd64cdd778 525462949bb0b141 db908c5cfa365750 3666f879ac879fcb\
- f25c15d496a1e6f7 f8", /* <---- with 16 bytes tag */
- *sivcipher = "f6d8137b17d58d13 af040e8abadd965b 9bae3a3de90ca6f7 049c2528767da2cf\
- ef17de85b1d07b59 d26b0595071ae428 3015840928e2c7f5 9abf06003b14b9ee\
- 25111d34bb2bfcc2 25", /* 16 bytes i.v. PREPENDED */
- *cmac_hash = "b887df1fd8c239c3 e8a64d9822e21128",
- *p1305_mac = "3175bed9bd01821a 62d4c7bef26722be",
- *fpe_plain = "0123456789abcdefghi",
- *wrapped = "1FA68B0A8112B447 AEF34BD8FB5A7B82 9D3E862371D2CFE5";
-#elif AES_KEY_LENGTH == 24 /* ↓↓↓↓ PKCS#7 is enabled */
- *ecbcipher = "af1893f0fbb09a43 7f6b0fd4f4977890 7bb85cccf1e9d2e3 ebe5bae935107868\
- c6d72cb2ca375c12 ce6b6b1141141fd0 d268d14db351d680 5aabb99427341da9",
- *wrapped = "031D33264E15D332 68F24EC260743EDC E1C6C7DDEE725A93 6BA814915C6762D2";
-#else
- *xtscipher = "40bfcc14845b1bb4 15dd13abf1e6f89d 3bfd794cf6655ffd 14c0d7e4177eeaf4\
- 5dd95f05663fcfb4 47671154a91b9d00 d1bd7a35c14c7410 9a",
- *wrapped = "28C9F404C4B810F4 CBCCB35CFB87F826 3F5786E2D80ED326 CBC7F0E71A99F43B\
- FB988B9B7A02DD21"; /* <---- it is in RFC-3394 */
-#endif
-
#include
-static void check(const char* method, uint8_t* result, uint8_t* expected, size_t size)
+static const char
+ *secretKey = "0001020304050607 08090A0B0C0D0E0F 1011121314151617 18191A1B1C1D1E1F",
+ *secondKey = "0011223344556677 8899AABBCCDDEEFF 0001020304050607 08090A0B0C0D0E0F",
+ *cipherKey = "279fb74a7572135e 8f9b8ef6d1eee003 69c4e0d86a7b0430 d8cdb78070b4c55a",
+ *plainText = "c9f775baafa36c25 cd610d3c75a482ea dda97ca4864cdfe0 6eaf70a0ec0d7191"
+ "d55027cf8f900214 e634412583ff0b47 8ea2b7ca516745bf ea",
+ *iVec = "8ea2b7ca516745bf eafc49904b496089",
+#if AES___ == 256
+ *k_wrapped = "28C9F404C4B810F4 CBCCB35CFB87F826 3F5786E2D80ED326 CBC7F0E71A99F43B"
+ "FB988B9B7A02DD21", /* <---- p. 34 of RFC-3394 */
+ *xtscipher = "40bfcc14845b1bb4 15dd13abf1e6f89d 3bfd794cf6655ffd 14c0d7e4177eeaf4"
+ "5dd95f05663fcfb4 47671154a91b9d00 d1bd7a35c14c7410 9a";
+#elif AES___ == 192 /* ↓↓↓↓ if PKCS#7 enabled */
+ *ecbcipher = "af1893f0fbb09a43 7f6b0fd4f4977890 7bb85cccf1e9d2e3 ebe5bae935107868"
+ "c6d72cb2ca375c12 ce6b6b1141141fd0 d268d14db351d680 5aabb99427341da9",
+ *k_wrapped = "031D33264E15D332 68F24EC260743EDC E1C6C7DDEE725A93 6BA814915C6762D2";
+#else /* ↓↓↓↓ zero-padded input */
+ *ecbcipher = "5d00c273f8b2607d a834632dcbb521f4 697dd4ab20bb0645 32a6545e24e33ae9"
+ "f545176111f93773 dbecd262841cf83b 10d145e71b772cf7 a12889cda84be795",
+#if CTS
+ *cbccipher = "65c48fdf9fbd6261 28f2d8bac3f71251 75e7f4821fda0263 70011632779d7403"
+ "c119ef461ac4e1bc 8a7e36bf92b3b3d1 7e9e2d298e154bc4 2d",
+#else /* ↓↓↓↓ zero-padded input */
+ *cbccipher = "65c48fdf9fbd6261 28f2d8bac3f71251 75e7f4821fda0263 70011632779d7403"
+ "7e9e2d298e154bc4 2dc7a9bc419b915d c119ef461ac4e1bc 8a7e36bf92b3b3d1",
+#endif
+ *xtscipher = "10f9301a157bfceb 3eb9e7bd38500b7e 959e21ba3cc1179a d7f7d7d99460e695"
+ "5e8bcb177571c719 6de58ff28c381913 e7c82d0adfd90c45 ca",
+ *cfbcipher = "edab3105e673bc9e b9102539a9f457bc 245c14e1bff81b5b 4a4a147c988cb0a6"
+ "3f9c56525efbe64a 876ad1d761d3fc93 59fb4f5b2354acd4 90",
+ *ofbcipher = "edab3105e673bc9e b9102539a9f457bc d28c8e4c92995f5c d9426926be1e775d"
+ "e22b8ce4d0278b18 181b8bec93b9726f 959aa5d701d46102 f0",
+#if CTR_IV_LENGTH == 16
+ *ctrcipher = "edab3105e673bc9e b9102539a9f457bc f2e2606dfa3f93c5 c51b910a89cddb67"
+ "191a118531ea0427 97626c9bfd370426 fdf3f59158bf7d4d 43",
+#else
+ *ctrcipher = "6c6bae886c235d8c 7997d45c1bf0bca2 48b4bca9eb396d1b f6945e5b7a4fc10f"
+ "488cfe76fd5eaeff 2b8fb469f78fa61e 285e4cf9b9aee3d0 a8",
+#endif
+ *ccmcipher = "d2575123438338d7 0b2955537fdfcf41 729870884e85af15 f0a74975a72b337d"
+ "04d426de87594b9a be3e6dcf07f21c99 db3999f81299d302 ad1e5ba683e9039a"
+ "5483685f1bd2c3fa 3b", /* <---- with 16 bytes tag */
+ *gcmcipher = "5ceab5b7c2d6dede 555a23c7e3e63274 4075a51df482730b a31485ec987ddcc8"
+ "73acdcfc6759a47b a424d838e7c0cb71 b9a4d8f4572e2141 18c8ab284ca845c1"
+ "4394618703cddf3a fb", /* <---- with 16 bytes tag */
+ *sivcipher = "ff2537a371fba0bb ed11acf2a3631300 97964f088881bdbd f163e261afd158e6"
+ "09272e759213c76a edc83a451d094c9e 06e2600e50a27cbb c0d9fad10eb6d369"
+ "4614362e5cd68b90 a9", /* 16 bytes i.v. PREPENDED */
+ *ocbcipher = "fc254896eb785b05 dd87f240722dd935 61f5a0ef6aff2eb6 5953da0b26257ed0"
+ "d69cb496e9a0cb1b f646151aa07e629a 28d99f0ffd7ea753 5c39f440df33c988"
+ "c55cbcc8ac086ffa 23", /* ↑↑↓↓ with 16 bytes tag */
+ *gsvcipher = "2f1488496ada3f70 9760420ac72e5acf a977f6add4c55ac6 85f1b9dff8f381e0"
+ "2a64bbdd64cdd778 525462949bb0b141 db908c5cfa365750 3666f879ac879fcb"
+ "f25c15d496a1e6f7 f8",
+#if EAXP /* ↓↓↓↓ with 4 bytes tag */
+ *eaxcipher = "f516e9c20069292c c51ba8b6403ddedf 5a34798f62187f58 d723fa33573fd80b"
+ "f08ffbb09dadbd0b 6fa4812ca4bb5e6d db9a384943b36690 e81738a7a1",
+#else /* ↓↓↓↓ with 16 bytes tag */
+ *eaxcipher = "4e2fa1bef9ffc23f 6965ee7135981c91 af9bfe97a6b13c01 b8b99e114dda2391"
+ "50661c618335a005 47cca55a8f22fbd5 ed5ab4b4a17d0aa3 29febd14ef271bae"
+ "986810a504f01ec6 02",
+#endif /* ↓↓ a large Prime Number */
+ *fpe_plain = "122333444455555666666777777788888888999999999012345682747",
+#if FF_X == 3 /* <-- MAXLEN=56 if RDX=10 */
+ *fpecipher = "0053317760589559020399280014720716878020198371161819152",
+#else
+ *fpecipher = "000260964766881620856103152534002821752468680082944565411",
+#endif
+ *ptextcmac = "b887df1fd8c239c3 e8a64d9822e21128",
+ *poly_1305 = "3175bed9bd01821a 62d4c7bef26722be",
+ *k_wrapped = "1FA68B0A8112B447 AEF34BD8FB5A7B82 9D3E862371D2CFE5";
+#endif
+
+enum buffer_sizes
{
- int c = memcmp(expected, result, size);
- printf("AES-%d %s: %s\n", AES_KEY_LENGTH *8, method, c ? "FAILED :(" : "PASSED!");
- memset(result, 0xcc , BuffL);
+ PBYTES = HEXSTR_LENGTH / 2,
+ PADDED = PBYTES + 15 & ~15,
+ TAGGED = PBYTES + 16
+};
+
+static void hex2bytes(const char* hex, uint8_t* bytes)
+{
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
+ {
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
+ }
}
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void check(const char* method, void* result, const void* expected, size_t size)
{
- unsigned i, j;
- for (i = 0, j = ~0U; str[i]; ++i)
- {
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
- }
+ int c = memcmp(expected, result, size);
+ printf("AES-%d %s: %s\n", AES_KEY_SIZE * 8, method, c ? "FAILED :`(" : "PASSED!");
+ memset(result, 0xcc, TAGGED);
}
int main()
{
- uint8_t mainKey[32], key[64], iv[16], input[BuffL - 16], test[BuffL], output[BuffL],
- *a = mainKey + 1, sa = sizeof mainKey - 1, st = TestStringSize / 2;
- str2bytes(cipherKey, key);
- str2bytes(secretKey, key + 32);
- str2bytes(masterKey, mainKey);
- str2bytes(iVec, iv);
- str2bytes(plainText, input);
- printf("Test results...\n");
-
+ uint8_t iv[16], key[64], authKey[32], input[PADDED], test[TAGGED], output[TAGGED],
+ *a = authKey + 1, sa = sizeof authKey - 1, sp = PBYTES;
+ hex2bytes(cipherKey, key);
+ hex2bytes(secondKey, key + 32);
+ hex2bytes(secretKey, authKey);
+ hex2bytes(iVec, iv);
+ hex2bytes(plainText, input);
#if M_RIJNDAEL
- memcpy(input + 48, iv, 16);
- a = AES_KEY_LENGTH == 16 ? key : input + (AES_KEY_LENGTH - 24) * 4;
+ hex2bytes(iVec, input + 48);
+ hex2bytes(secondKey, test);
+ a = AES_KEY_SIZE == 16 ? key : input + (AES___ - 192) / 2;
- memcpy(test, a, 32);
- memcpy(test + 32, mainKey, 16);
- memcpy(test + 48, key + 32, 16);
- AES_Cipher(key + 32, 'E', mainKey, output);
- AES_Cipher(mainKey, 'E', key + 32, output + 16);
- AES_Cipher(key + 32, 'D', a, output + 32);
- AES_Cipher(mainKey, 'D', a + 16, output + 48);
- check("encryption & decryption", output, test, 64);
+ AES_Cipher(test, 'E', authKey, output);
+ AES_Cipher(authKey, 'E', test, output + 16);
+ check("Encryption test", output, a, 32);
+ AES_Cipher(test, 'D', a, output + 16);
+ AES_Cipher(authKey, 'D', a + 16, output);
+ check("Decryption test", output, test, 32);
+ return 0;
#endif
-#if ECB && AES_KEY_LENGTH + 8 * !AES_PADDING == 24
- str2bytes(ecbcipher, test);
- AES_ECB_encrypt(key, input, st, output);
+ printf("%s %s Test results\n", __DATE__, __TIME__);
+
+#if ECB && AES_KEY_SIZE + 8 * !AES_PADDING == 24
+ 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, st);
+ check("ECB decryption", output, input, sp);
#endif
-#if CBC && AES_KEY_LENGTH == 16
- str2bytes(cbccipher, test);
- AES_CBC_encrypt(key, iv, input, st, output);
- check("CBC encryption", output, test, CTS ? st : sizeof input);
- AES_CBC_decrypt(key, iv, test, CTS ? st : sizeof input, output);
- check("CBC decryption", output, input, st);
+#if CBC && AES_KEY_SIZE == 16
+ 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_LENGTH == 16
- str2bytes(cfbcipher, test);
- AES_CFB_encrypt(key, iv, input, st, output);
- check("CFB encryption", output, test, st);
- AES_CFB_decrypt(key, iv, test, st, output);
- check("CFB decryption", output, input, st);
+#if CFB && AES_KEY_SIZE == 16
+ 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_LENGTH == 16
- str2bytes(ofbcipher, test);
- AES_OFB_encrypt(key, iv, input, st, output);
- check("OFB encryption", output, test, st);
- AES_OFB_decrypt(key, iv, test, st, output);
- check("OFB decryption", output, input, st);
+#if OFB && AES_KEY_SIZE == 16
+ 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_LENGTH == 16
- str2bytes(ctrcipher, test);
- AES_CTR_encrypt(key, iv, input, st, output);
- check("CTR encryption", output, test, st);
- AES_CTR_decrypt(key, iv, test, st, output);
- check("CTR decryption", output, input, st);
+#if CTR_NA && AES_KEY_SIZE == 16
+ 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_LENGTH != 24
- str2bytes(xtscipher, test);
- AES_XTS_encrypt(key, iv, input, st, output);
- check("XTS encryption", output, test, st);
- AES_XTS_decrypt(key, iv, test, st, output);
- check("XTS decryption", output, input, st);
+#if XTS && AES_KEY_SIZE != 24
+ 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_LENGTH == 16
- str2bytes(cmac_hash, test);
- AES_CMAC(key, input, st, output);
- check("validate CMAC ", output, test, 16);
+#if CMAC && AES_KEY_SIZE == 16
+ hex2bytes(ptextcmac, test);
+ AES_CMAC(key, input, sp, output);
+ check("plaintext CMAC", output, test, 16);
#endif
-#if POLY1305 && AES_KEY_LENGTH == 16
- str2bytes(p1305_mac, test);
- AES_Poly1305(key, iv, input, st, output);
- check("Poly-1305 mac ", output, test, 16);
+#if POLY1305 && AES_KEY_SIZE == 16
+ hex2bytes(poly_1305, test);
+ AES_Poly1305(key, iv, input, sp, output);
+ check("Poly-1305 mac.", output, test, 16);
#endif
-#if GCM && AES_KEY_LENGTH == 16
- str2bytes(gcmcipher, test);
- AES_GCM_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("GCM encryption", output, test, st + 16);
- *output ^= AES_GCM_decrypt(key, iv, test, st, a, sa, 16, output);
- check("GCM decryption", output, input, st);
+#if GCM && AES_KEY_SIZE == 16
+ 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);
+ check("GCM decryption", output, input, sp);
#endif
-#if CCM && AES_KEY_LENGTH == 16
- str2bytes(ccmcipher, test);
- AES_CCM_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("CCM encryption", output, test, st + CCM_TAG_LEN);
- *output ^= AES_CCM_decrypt(key, iv, test, st, a, sa, CCM_TAG_LEN, output);
- check("CCM decryption", output, input, st);
+#if CCM && AES_KEY_SIZE == 16
+ hex2bytes(ccmcipher, test);
+ AES_CCM_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ check("CCM encryption", output, test, sp + CCM_TAG_LEN);
+ *output ^= AES_CCM_decrypt(key, iv, test, sp, a, sa, CCM_TAG_LEN, output);
+ check("CCM decryption", output, input, sp);
#endif
-#if OCB && AES_KEY_LENGTH == 16
- str2bytes(ocbcipher, test);
- AES_OCB_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("OCB encryption", output, test, st + OCB_TAG_LEN);
- *output ^= AES_OCB_decrypt(key, iv, test, st, a, sa, OCB_TAG_LEN, output);
- check("OCB decryption", output, input, st);
+#if OCB && AES_KEY_SIZE == 16
+ hex2bytes(ocbcipher, test);
+ AES_OCB_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ check("OCB encryption", output, test, sp + OCB_TAG_LEN);
+ *output ^= AES_OCB_decrypt(key, iv, test, sp, a, sa, OCB_TAG_LEN, output);
+ check("OCB decryption", output, input, sp);
#endif
-#if SIV && AES_KEY_LENGTH == 16
- str2bytes(sivcipher, test);
- AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
- check("SIV encryption", output, test, st + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
- check("SIV decryption", output, input, st);
+#if SIV && AES_KEY_SIZE == 16
+ hex2bytes(sivcipher, test);
+ AES_SIV_encrypt(key, input, sp, a, sa, output, output + 16);
+ check("SIV encryption", output, test, sp + 16);
+ *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, output);
+ check("SIV decryption", output, input, sp);
#endif
-#if GCM_SIV && AES_KEY_LENGTH == 16
- str2bytes(gsvcipher, test);
- GCM_SIV_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("GCMSIV encrypt", output, test, st + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, st, a, sa, 16, output);
- check("GCMSIV decrypt", output, input, st);
+#if GCM_SIV && AES_KEY_SIZE == 16
+ 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);
+ check("GCMSIV decrypt", output, input, sp);
#endif
-#if EAX && AES_KEY_LENGTH == 16
- str2bytes(eaxcipher, test);
+#if EAX && AES_KEY_SIZE == 16
+ hex2bytes(eaxcipher, test);
#if EAXP
- AES_EAX_encrypt(key, a, input, st, sa, output);
- check("EAX encryption", output, test, st + 4);
- *output ^= AES_EAX_decrypt(key, a, test, st, sa, output);
+ AES_EAX_encrypt(key, a, input, sp, sa, output);
+ check("EAX encryption", output, test, sp + 4);
+ AES_EAX_decrypt(key, a, test, sp, sa, output);
#else
- AES_EAX_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("EAX encryption", output, test, st + 16);
- *output ^= AES_EAX_decrypt(key, iv, test, st, a, sa, 16, output);
+ 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);
#endif
- check("EAX decryption", output, input, st);
+ check("EAX decryption", output, input, sp);
+#endif
+#if FPE && AES_KEY_SIZE + CUSTOM_ALPHABET == 16
+ memcpy(test, fpecipher, FF_X == 3 ? (sp = 55) : sp);
+#if FF_X == 3
+ AES_FPE_encrypt(key, a, fpe_plain, sp, output);
+ check("FF3 encryption", output, test, sp);
+ AES_FPE_decrypt(key, a, test, sp, output);
+#else
+ AES_FPE_encrypt(key, a, sa, fpe_plain, sp, output);
+ check("FF1 encryption", output, test, sp);
+ AES_FPE_decrypt(key, a, sa, test, sp, output);
+#endif
+ check("FPE decryption", output, fpe_plain, sp);
#endif
#if KWA
- str2bytes(wrapped, test);
- AES_KEY_wrap(mainKey, key + 32, AES_KEY_LENGTH, output);
- check("key wrapping ", output, test, AES_KEY_LENGTH + 8);
- AES_KEY_unwrap(mainKey, test, AES_KEY_LENGTH + 8, output);
- check("key unwrapping", output, key + 32, AES_KEY_LENGTH);
+ 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);
#endif
-#if FF_X == 3 && AES_KEY_LENGTH == 16
- str2bytes("EF 43 59 D8 D5 80 AA 4F 7F 03 6D 6F 04 FC 6A 94", key);
- str2bytes("D8 E7 92 0A FA 33 0A 73", a);
-#elif FPE && AES_KEY_LENGTH == 16
- str2bytes("2B 7E 15 16 28 AE D2 A6 AB F7 15 88 09 CF 4F 3C", key);
-#if CUSTOM_ALPHABET == 2
- st = 19; sa = 11;
- str2bytes("37 37 37 37 70 71 72 73 37 37 37", a);
- memcpy(test, "a9tv40mll9kdu509eum", st);
-#elif !CUSTOM_ALPHABET
- sa = 10; st = 10;
- str2bytes("39 38 37 36 35 34 33 32 31 30", a);
- memcpy(test, "6124200773", st);
- AES_FPE_encrypt(key, a, sa, fpe_plain, st, output);
- check("FF1 encryption", output, test, st);
- AES_FPE_decrypt(key, a, sa, test, st, output);
- check("FF1 decryption", output, (void*) fpe_plain, st);
- memcpy(test, "2433477484", st); sa = 0;
-#endif
- AES_FPE_encrypt(key, a, sa, fpe_plain, st, output);
- check("FF1 encryption", output, test, st);
- AES_FPE_decrypt(key, a, sa, test, st, output);
- check("FF1 decryption", output, (void*) fpe_plain, st);
-#endif
-
/** a template for "OFFICIAL TEST VECTORS": */
-#if OCB && EAX && SIV && GCM_SIV && POLY1305 && AES_KEY_LENGTH == 16
+#if OCB * EAX * SIV * GCM_SIV * POLY1305 * FPE * (16 / AES_KEY_SIZE)
printf("+-> Let's do some extra tests\n");
- st = sa = 24; /* taken from RFC 7253: */
- str2bytes("000102030405060708090A0B0C0D0E0F", key);
- str2bytes("BBAA99887766554433221107", iv);
- str2bytes("000102030405060708090A0B0C0D0E0F1011121314151617", a);
- str2bytes("000102030405060708090A0B0C0D0E0F1011121314151617", input);
- str2bytes("1CA2207308C87C010756104D8840CE1952F09673A448A122\
+ sp = sa = 24; /* taken from RFC 7253: */
+ hex2bytes("000102030405060708090A0B0C0D0E0F", key);
+ hex2bytes("BBAA99887766554433221107", iv);
+ hex2bytes("000102030405060708090A0B0C0D0E0F1011121314151617", a);
+ hex2bytes("000102030405060708090A0B0C0D0E0F1011121314151617", input);
+ hex2bytes("1CA2207308C87C010756104D8840CE1952F09673A448A122\
C92C62241051F57356D7F3C90BB0E07F", test);
- AES_OCB_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("OCB encryption", output, test, st + OCB_TAG_LEN);
- *output ^= AES_OCB_decrypt(key, iv, test, st, a, sa, OCB_TAG_LEN, output);
- check("OCB decryption", output, input, st);
+ AES_OCB_encrypt(key, iv, input, sp, a, sa, output, output + sp);
+ check("OCB encryption", output, test, sp + OCB_TAG_LEN);
+ *output ^= AES_OCB_decrypt(key, iv, test, sp, a, sa, OCB_TAG_LEN, output);
+ check("OCB decryption", output, input, sp);
- st = 11; sa = 7; /* taken from RFC 8452: */
- str2bytes("ee8e1ed9ff2540ae8f2ba9f50bc2f27c", key);
- str2bytes("752abad3e0afb5f434dc4310", iv);
- str2bytes("6578616d706c65", a);
- str2bytes("48656c6c6f20776f726c64", input);
- str2bytes("5d349ead175ef6b1def6fd4fbcdeb7e4793f4a1d7e4faa70100af1", test);
- GCM_SIV_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("GCMSIV encrypt", output, test, st + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, st, a, sa, 16, output);
- check("GCMSIV decrypt", output, input, st);
- st = 12; sa = 1; /* taken from RFC 8452: */
- str2bytes("01000000000000000000000000000000", key);
- str2bytes("030000000000000000000000", iv);
- str2bytes("01", a);
- str2bytes("020000000000000000000000", input);
- str2bytes("296c7889fd99f41917f4462008299c51\
+ 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);
+ check("GCMSIV encrypt", output, test, sp + 16);
+ *output ^= GCM_SIV_decrypt(key, iv, test, sp, a, sa, 16, output);
+ check("GCMSIV decrypt", output, input, sp);
+ sp = 12; 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, st, a, sa, output, output + st);
- check("GCMSIV encrypt", output, test, st + 16);
- *output ^= GCM_SIV_decrypt(key, iv, test, st, a, sa, 16, output);
- check("GCMSIV decrypt", output, input, st);
+ 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);
+ check("GCMSIV decrypt", output, input, sp);
- st = 14; sa = 24; /* taken from RFC 5297: */
- str2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
+ sp = 14; sa = 24; /* taken from RFC 5297: */
+ hex2bytes("fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0\
f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff", key);
- str2bytes("10111213 14151617 18191a1b 1c1d1e1f\
+ hex2bytes("10111213 14151617 18191a1b 1c1d1e1f\
20212223 24252627", a);
- str2bytes("11223344 55667788 99aabbcc ddee", input);
- str2bytes("85632d07 c6e8f37f 950acd32 0a2ecc93\
+ hex2bytes("11223344 55667788 99aabbcc ddee", input);
+ hex2bytes("85632d07 c6e8f37f 950acd32 0a2ecc93\
40c02b96 90c4dc04 daef7f6a fe5c", test);
- AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
- check("SIV encryption", output, test, st + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
- check("SIV decryption", output, input, st);
- st = 16; sa = 0; /* from miscreant: https://bit.ly/3yc2GBs */
- str2bytes("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", key);
- str2bytes("00112233445566778899aabbccddeeff", input);
- str2bytes("f304f912863e303d5b540e5057c7010c942ffaf45b0e5ca5fb9a56a5263bb065", test);
- AES_SIV_encrypt(key, input, st, a, sa, output, output + 16);
- check("SIV encryption", output, test, st + 16);
- *output ^= AES_SIV_decrypt(key, test, test + 16, st, a, sa, output);
- check("SIV decryption", output, input, st);
+ AES_SIV_encrypt(key, input, sp, a, sa, output, output + 16);
+ check("SIV encryption", output, test, sp + 16);
+ *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, 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);
+ check("SIV encryption", output, test, sp + 16);
+ *output ^= AES_SIV_decrypt(key, test, test + 16, sp, a, sa, output);
+ check("SIV decryption", output, input, sp);
#if EAXP
- st = 0; sa = 50; /* from Annex G of the IEEE Std 1703-2012 */
- str2bytes("01020304050607080102030405060708", mainKey);
- str2bytes("A20D060B607C86F7540116007BC175A8\
+ sp = 0; sa = 50; /* from Annex G of the IEEE Std 1703-2012 */
+ hex2bytes("01020304050607080102030405060708", key);
+ hex2bytes("A20D060B607C86F7540116007BC175A8\
03020100BE0D280B810984A60C060A60\
7C86F7540116007B040248F3C2040330\
- 0005", test);
- str2bytes("515AE775", key);
- AES_EAX_encrypt(mainKey, test, input, st, sa, output);
- check("EAX encryption", output, key, st + 4);
- *output ^= AES_EAX_decrypt(mainKey, test, key, st, sa, output);
- check("EAX decryption", output, input, st);
- st = 28; sa = 65; /* from Moise-Beroset-Phinney-Burns paper: */
- str2bytes("10 20 30 40 50 60 70 80 90 a0 b0 c0 d0 e0 f0 00", mainKey);
- str2bytes("a2 0e 06 0c 60 86 48 01 86 fc 2f 81 1c aa 4e 01\
+ 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);
+ 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\
a8 06 02 04 39 a0 0e bb ac 0f a2 0d a0 0b a1 09\
80 01 00 81 04 4b ce e2 c3 be 25 28 23 81 21 88\
a6 0a 06 08 2b 06 01 04 01 82 85 63 00 4b ce e2\
c3", test);
- str2bytes("17 51 30 30 30 30 30 30 30 30 30 30 30 30 30 30\
+ hex2bytes("17 51 30 30 30 30 30 30 30 30 30 30 30 30 30 30\
30 30 30 30 30 30 00 00 03 30 00 01", input);
- str2bytes("9c f3 2c 7e c2 4c 25 0b e7 b0 74 9f ee e7 1a 22\
+ 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(mainKey, test, input, st, sa, output);
- check("EAX encryption", output, key, st + 4);
- *output ^= AES_EAX_decrypt(mainKey, test, key, st, sa, output);
+ 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
- st = 12; sa = 8; /* from Bellare-Rogaway-Wagner 2004 paper: */
- str2bytes("BD8E6E11475E60B268784C38C62FEB22", key);
- str2bytes("6EAC5C93072D8E8513F750935E46DA1B", iv);
- str2bytes("D4482D1CA78DCE0F", a);
- str2bytes("4DE3B35C3FC039245BD1FB7D", input);
- str2bytes("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F", test);
- AES_EAX_encrypt(key, iv, input, st, a, sa, output, output + st);
- check("EAX encryption", output, test, st + 16);
- *output ^= AES_EAX_decrypt(key, iv, test, st, a, sa, 16, output);
+ 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);
#endif
- check("EAX decryption", output, input, st);
+ check("EAX decryption", output, input, sp);
- st = 32; /* D.J.B. [2005] https://cr.yp.to/mac.html */
- str2bytes("66 3c ea 19 0f fb 83 d8 95 93 f3 f4 76 b6 bc 24\
+#if FF_X == 3 && !CUSTOM_ALPHABET
+ 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);
+#elif 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);
+#endif
+ sp = 32; /* ↓ from Daniel J. Bernstein's 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);
- str2bytes("6a cb 5f 61 a7 17 6d d3 20 c5 c1 eb 2e dc dc 74\
+ hex2bytes("6a cb 5f 61 a7 17 6d d3 20 c5 c1 eb 2e dc dc 74\
48 44 3d 0b b0 d2 11 09 c8 9a 10 0b 5c e2 c2 08", key);
- str2bytes("ae 21 2a 55 39 97 29 59 5d ea 45 8b c6 21 ff 0e", iv);
- str2bytes("0e e1 c1 6b b7 3f 0f 4f d1 98 81 75 3c 01 cd be", test);
- AES_Poly1305(key, iv, input, st, output);
- check("Poly-1305 mac ", output, test, 16);
- st = 63;
- str2bytes("ab 08 12 72 4a 7f 1e 34 27 42 cb ed 37 4d 94 d1\
+ hex2bytes("ae 21 2a 55 39 97 29 59 5d ea 45 8b c6 21 ff 0e", iv);
+ hex2bytes("0e e1 c1 6b b7 3f 0f 4f d1 98 81 75 3c 01 cd be", test);
+ AES_Poly1305(key, iv, input, sp, output);
+ check("Poly-1305 mac.", output, test, 16);
+ sp = 63;
+ hex2bytes("ab 08 12 72 4a 7f 1e 34 27 42 cb ed 37 4d 94 d1\
36 c6 b8 79 5d 45 b3 81 98 30 f2 c0 44 91 fa f0\
99 0c 62 e4 8b 80 18 b2 c3 e4 a0 fa 31 34 cb 67\
fa 83 e1 58 c9 94 d9 61 c4 cb 21 09 5c 1b f9", input);
- str2bytes("e1 a5 66 8a 4d 5b 66 a5 f6 8c c5 42 4e d5 98 2d\
+ hex2bytes("e1 a5 66 8a 4d 5b 66 a5 f6 8c c5 42 4e d5 98 2d\
12 97 6a 08 c4 42 6d 0c e8 a8 24 07 c4 f4 82 07", key);
- str2bytes("9a e8 31 e7 43 97 8d 3a 23 52 7c 71 28 14 9e 3a", iv);
- str2bytes("51 54 ad 0d 2c b2 6e 01 27 4f c5 11 48 49 1f 1b", test);
- AES_Poly1305(key, iv, input, st, output);
- check("Poly-1305 mac ", output, test, 16);
+ hex2bytes("9a e8 31 e7 43 97 8d 3a 23 52 7c 71 28 14 9e 3a", iv);
+ hex2bytes("51 54 ad 0d 2c b2 6e 01 27 4f c5 11 48 49 1f 1b", test);
+ AES_Poly1305(key, iv, input, sp, output);
+ check("Poly-1305 mac.", output, test, 16);
#endif
return 0;
}
diff --git a/micro_aes.c b/micro_aes.c
index 66ce76c..4fe580c 100644
--- a/micro_aes.c
+++ b/micro_aes.c
@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.c
Author : polfosol
- Version : 9.8.1.0
+ Version : 10
Copyright : copyright © 2022 - polfosol
Description : ANSI-C compatible implementation of µAES ™ library.
==============================================================================
@@ -14,138 +14,120 @@
Global constants, data types, and important / useful MACROs
\*----------------------------------------------------------------------------*/
-#define KEYSIZE AES_KEY_LENGTH
-#define BLOCKSIZE (128/8) /* Block length in AES is 'always' 128-bits. */
-#define Nb (BLOCKSIZE/4) /* The number of columns comprising a AES state. */
-#define Nk (KEYSIZE/4) /* The number of 32 bit words in a key. */
-#define LAST (BLOCKSIZE-1) /* The index at the end of block, or last index */
-#define ROUNDS (Nk+6) /* The number of rounds in AES Cipher. */
+#define KEYSIZE AES_KEY_SIZE
+#define BLOCKSIZE (128 / 8) /* Block length in AES is 'always' 128-bits. */
+#define Nb (BLOCKSIZE / 4) /* The number of columns comprising a AES state */
+#define Nk (KEYSIZE / 4) /* The number of 32 bit words in a key. */
+#define ROUNDS (Nk + 6) /* The number of rounds in AES Cipher. */
-#define IMPLEMENT(x) (x) > 0
+#define IMPLEMENT(x) (x) > 0
-#define INCREASE_SECURITY 0 /* refer to the bottom of the header file for */
-#define SMALL_CIPHER 0 /* ... some explanations and the rationale of */
-#define REDUCE_CODE_SIZE 1 /* ... these three macros */
+#define INCREASE_SECURITY 0
+#define DONT_USE_FUNCTIONS 0
+#define SMALL_CIPHER 0 /* for more info, see the bottom of header file */
-/** state_t represents rijndael state matrix. fixed-size memory blocks have an
- * essential role in all algorithms. so it may be a good aide for readability to
- * define a specific type and a function pointer that applies to these blocks */
-typedef uint8_t state_t[Nb][4];
+/** block_t indicates fixed-size memory blocks, and state_t represents the state
+ * matrix. note that state[i][j] means the i-th COLUMN and j-th ROW of matrix */
typedef uint8_t block_t[BLOCKSIZE];
-typedef void (*fmix_t)(const block_t, block_t);
-
-#if SMALL_CIPHER
-typedef unsigned char count_t;
-#else
-typedef size_t count_t;
-#endif
+typedef uint8_t state_t[Nb][4];
/*----------------------------------------------------------------------------*\
Private variables:
\*----------------------------------------------------------------------------*/
-/** The array that stores the round keys during AES key-expansion process ... */
+/** The array that stores all round keys during the AES key-expansion process */
static uint8_t RoundKey[BLOCKSIZE * ROUNDS + KEYSIZE];
/** Lookup-tables are static constant, so that they can be placed in read-only
* storage instead of RAM. They can be computed dynamically trading ROM for RAM.
* This may be useful in (embedded) bootloader applications, where ROM is often
- * limited. Please refer to: https://en.wikipedia.org/wiki/Rijndael_S-box */
-static const uint8_t sbox[256] =
-{
- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
-};
+ * limited. Note that sbox[y] = x, if and only if rsbox[x] = y. You may read the
+ * wikipedia article for more info: https://en.wikipedia.org/wiki/Rijndael_S-box
+ */
+static const char sbox[256] =
+ "c|w{\362ko\3050\01g+\376\327\253v\312\202\311}""\372YG\360\255\324\242\257"
+ "\234\244r\300\267\375\223&6\?\367\3144\245\345\361q\3301\25\4\307#\303\030"
+ "\226\5\232\a\22\200\342\353\'\262u\t\203,\32\33nZ\240R;\326\263)\343/\204S"
+ "\321\0\355 \374\261[j\313\2769JLX\317\320\357\252\373CM3\205E\371\02\177P<"
+ "\237\250Q\243@\217\222\2358\365\274\266\332!\20\377\363\322\315\f\023\354_"
+ "\227D\27\304\247~=d]\31s`\201O\334\"*\220\210F\356\270\24\336^\v\333\3402:"
+ "\nI\06$\\\302\323\254b\221\225\344y\347\3107m\215\325N\251lV\364\352ez\256"
+ "\b\272x%.\034\246\264\306\350\335t\37K\275\213\212p>\265fH\3\366\16a5W\271"
+ "\206\301\035\236\341\370\230\21i\331\216\224\233\036\207\351\316U(\337\214"
+ "\241\211\r\277\346BhA\231-\17\260T\273\26";
#if DECRYPTION
-static const uint8_t rsbox[256] =
-{
- 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
- 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
- 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
- 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
- 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
- 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
- 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
- 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
- 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
- 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
- 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
- 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
- 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
- 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
- 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
-};
+static const char rsbox[256] =
+ "R\tj\32506\2458\277@\243\236\201\363\327\373|\3439\202\233/\377\2074\216CD"
+ "\304\336\351\313T{\2242\246\302#=\356L\225\vB\372\303N\b.\241f(\331$\262v["
+ "\242Im\213\321%r\370\366d\206h\230\026\324\244\\\314]e\266\222lpHP\375\355"
+ "\271\332^\25FW\247\215\235\204\220\330\253\0\214\274\323\n\367\344X\05\270"
+ "\263E\6\320,\036\217\312?\17\2\301\257\275\3\1\023\212k:\221\21AOg\334\352"
+ "\227\362\317\316\360\264\346s\226\254t\"\347\2555\205\342\3717\350\34u\337"
+ "nG\361\32q\35)\305\211o\267b\16\252\30\276\33\374V>K\306\322y \232\333\300"
+ "\376x\315Z\364\037\335\2503\210\a\3071\261\22\20Y\'\200\354_`Q\177\251\031"
+ "\265J\r-\345z\237\223\311\234\357\240\340;M\256*\365\260\310\353\273<\203S"
+ "\231a\27+\4~\272w\326&\341i\24cU!\f}";
#endif
/*----------------------------------------------------------------------------*\
Auxiliary functions for the Rijndael algorithm
\*----------------------------------------------------------------------------*/
-#define getSBoxValue(num) (sbox[(num)])
-#define getSBoxInvert(num) (rsbox[num])
+#define SBoxValue(x) ( sbox[x])
+#define InvSBoxValue(x) (rsbox[x]) /* omitted dynamic s-box calculation */
-#if REDUCE_CODE_SIZE
+#define COPY32BIT(x, y) *(int32_t*) &y = *(int32_t*) &x
+#define XOR32BITS(x, y) *(int32_t*) &y ^= *(int32_t*) &x
-/** this function carries out XOR operation on two 128-bit blocks ........... */
+#if DONT_USE_FUNCTIONS
+
+/** note: 'long long' type is NOT supported in C89. so this may throw errors: */
+#define xorBlock(x, y) \
+{ \
+ *(long long*) &(y)[0] ^= *(long long const*) &(x)[0]; \
+ *(long long*) &(y)[8] ^= *(long long const*) &(x)[8]; \
+}
+
+#define xtime(x) (x < 0x80 ? x * 2 : x * 2 ^ 0x11b)
+
+#define InvGM(a, b, c, d) d ^ c ^ b ^ xtime(b) ^ \
+ xtime(a) ^ (xtime(xtime(a))) ^ (xtime(xtime(c))) \
+ ^ xtime(xtime(xtime(a))) ^ xtime(xtime(xtime(b))) \
+ ^ xtime(xtime(xtime(c))) ^ xtime(xtime(xtime(d)))
+#else
+
+/** XOR two 128bit numbers (blocks) called src and dest, so that: dest ^= src */
static void xorBlock( const block_t src, block_t dest )
{
uint8_t i;
- for (i = 0; i < BLOCKSIZE; ++i) dest[i] ^= src[i];
+ for (i = 0; i < BLOCKSIZE; ++i) /* many CPUs have single instruction */
+ { /* such as XORPS for 128-bit-xor. */
+ dest[i] ^= src[i]; /* see the file: x86-improvements */
+ }
}
/** doubling in GF(2^8): left-shift and if carry bit is set, xor it with 0x1b */
static uint8_t xtime( uint8_t x )
{
- return (x > 0x7F) * 0x1b ^ (x << 1);
+ return (x > 0x7f) * 0x1b ^ (x << 1);
}
#if DECRYPTION
+#define InvGM(a, b, c, d) gmul(a, 14) ^ gmul(b, 11) ^ gmul(c, 13) ^ gmul(d, 9)
-/** This function multiplies two numbers in the Galois field GF(2^8) ........ */
-static uint8_t mulGF8( uint8_t x, uint8_t y )
+/** This function multiplies two numbers in the Galois bit field of GF(2^8).. */
+static uint8_t gmul( uint8_t x, uint8_t y )
{
uint8_t m;
- for (m = 0; x > 1; x >>= 1) /* optimized algorithm for nonzero x */
+ for (m = 0; y > 1; y >>= 1) /* optimized algorithm for nonzero y */
{
- m ^= (x & 1) * y;
- y = xtime( y );
+ if (y & 01) m ^= x;
+ x = xtime( x );
}
- return m ^ y; /* or use (9 11 13 14) lookup tables */
+ return m ^ x; /* or use (9 11 13 14) lookup tables */
}
#endif
-
-#else
-#define xtime(x) ((x & 0x80 ? 0x1b : 0x00) ^ (x << 1))
-
-#define mulGF8(x, y) \
- ( ((x & 1) * y) ^ \
- ((x >> 1 & 1) * xtime(y)) ^ \
- ((x >> 2 & 1) * xtime(xtime(y))) ^ \
- ((x >> 3 & 1) * xtime(xtime(xtime(y)))) )
-
-static void xorBlock( const block_t src, block_t dest )
-{
- long long *d = (void*) dest; /* not supported in ANSI-C / ISO-C90 */
- long long const *s = (const void*) src;
- d[0] ^= s[0];
- d[1] ^= s[1];
-}
#endif
/*----------------------------------------------------------------------------*\
@@ -160,41 +142,37 @@ static void KeyExpansion( const uint8_t* key )
uint8_t rcon = 1, i;
memcpy( RoundKey, key, KEYSIZE );
- for (i = KEYSIZE; i < (ROUNDS + 1) * BLOCKSIZE; ++i)
+ for (i = KEYSIZE; i < BLOCKSIZE * (ROUNDS + 1); i += 4)
{
switch (i % KEYSIZE)
{
case 0:
memcpy( &RoundKey[i], &RoundKey[i - KEYSIZE], KEYSIZE );
#if Nk == 4
- if (rcon == 0) rcon = 0x1b; /* RCON may reach 0 only in AES-128. */
+ if (!rcon) rcon = 0x1b; /* RCON may reach 0 only in AES-128. */
#endif
- RoundKey[i] ^= getSBoxValue( RoundKey[i - 3] ) ^ rcon;
+ RoundKey[i ] ^= SBoxValue( RoundKey[i - 3] ) ^ rcon;
+ RoundKey[i + 1] ^= SBoxValue( RoundKey[i - 2] );
+ RoundKey[i + 2] ^= SBoxValue( RoundKey[i - 1] );
+ RoundKey[i + 3] ^= SBoxValue( RoundKey[i - 4] );
rcon <<= 1;
break;
- case 1:
- case 2:
- RoundKey[i] ^= getSBoxValue( RoundKey[i - 3] );
- break;
- case 3:
- RoundKey[i] ^= getSBoxValue( RoundKey[i - 7] );
- break;
#if Nk == 8 /* additional round only for AES-256 */
- case 16: /* 0 <= i % KEYSIZE - BLOCKSIZE < 4 */
- case 17:
- case 18:
- case 19:
- RoundKey[i] ^= getSBoxValue( RoundKey[i - 4] );
+ case 16:
+ RoundKey[i ] ^= SBoxValue( RoundKey[i - 4] );
+ RoundKey[i + 1] ^= SBoxValue( RoundKey[i - 3] );
+ RoundKey[i + 2] ^= SBoxValue( RoundKey[i - 2] );
+ RoundKey[i + 3] ^= SBoxValue( RoundKey[i - 1] );
break;
#endif
default:
- RoundKey[i] ^= RoundKey[i - 4];
+ XOR32BITS( RoundKey[(i - 4)], RoundKey[i] );
break;
}
}
}
-/** This function adds the round key to the state matrix via an XOR function. */
+/** Add the round keys to the rijndael state matrix (adding in GF means XOR). */
static void AddRoundKey( const uint8_t round, block_t state )
{
xorBlock( RoundKey + BLOCKSIZE * round, state );
@@ -206,12 +184,12 @@ static void SubBytes( block_t state )
uint8_t i;
for (i = 0; i < BLOCKSIZE; ++i)
{
- state[i] = getSBoxValue( state[i] );
+ state[i] = SBoxValue( state[i] );
}
}
/** Shift/rotate the rows of the state matrix to the left. Each row is shifted
- * with a different offset (= Row number). So the first row is not shifted .. */
+ * with a different offset (= Row number). So the first row won't be shifted. */
static void ShiftRows( state_t *state )
{
uint8_t temp = (*state)[0][1];
@@ -234,7 +212,7 @@ static void ShiftRows( state_t *state )
(*state)[1][3] = temp; /* Rotated the 3rd row 3 columns to left */
}
-/** This function mixes the columns of the state matrix in a rotational way.. */
+/** Mix the columns of the state matrix. See: crypto.stackexchange.com/q/2402 */
static void MixColumns( state_t *state )
{
uint8_t a, b, c, d, i;
@@ -244,7 +222,7 @@ static void MixColumns( state_t *state )
b = (*state)[i][1] ^ (*state)[i][2];
c = (*state)[i][2] ^ (*state)[i][3];
- d = a ^ c; /* d is XOR of all the elements in a row */
+ d = a ^ c; /* d is XOR of all elements in a column */
(*state)[i][0] ^= d ^ xtime( a );
(*state)[i][1] ^= d ^ xtime( b );
@@ -254,24 +232,23 @@ static void MixColumns( state_t *state )
}
}
-/** Encrypts a plain-text input block, into a cipher text block as output ... */
+/** Encrypt a plaintext input block and save the result/ciphertext as output. */
static void rijndaelEncrypt( const block_t input, block_t output )
{
- uint8_t round = ROUNDS;
+ uint8_t r;
+ state_t *state = (void*) output;
/* copy the input to the state matrix, and beware of undefined behavior.. */
- if (input != output) memcpy( output, input, BLOCKSIZE );
-
- AddRoundKey( 0, output ); /* Add the first round key to the state */
+ if (input != output) memcpy( state, input, BLOCKSIZE );
/* The encryption is carried out in #ROUNDS iterations, of which the first
* #ROUNDS-1 are identical. The last round doesn't involve mixing columns */
- while (round)
+ for (r = 0; r != ROUNDS; )
{
+ AddRoundKey( r, output );
SubBytes( output );
- ShiftRows( (state_t*) output );
- if (--round) MixColumns( (state_t*) output );
- AddRoundKey( ROUNDS - round, output );
+ ShiftRows( state );
+ ++r != ROUNDS ? MixColumns( state ) : AddRoundKey( ROUNDS, output );
}
}
@@ -281,17 +258,17 @@ static void rijndaelEncrypt( const block_t input, block_t output )
#if IMPLEMENT(DECRYPTION)
-/** Substitutes the values in the state matrix with values of inverted S-box. */
+/** Substitutes the values in state matrix with values of the inverted S-box. */
static void InvSubBytes( block_t state )
{
uint8_t i;
for (i = 0; i < BLOCKSIZE; ++i)
{
- state[i] = getSBoxInvert( state[i] );
+ state[i] = InvSBoxValue( state[i] );
}
}
-/** This function shifts/rotates the rows of the state matrix to right ...... */
+/** This function shifts (i.e rotates) the rows of the state matrix to right. */
static void InvShiftRows( state_t *state )
{
uint8_t temp = (*state)[3][1];
@@ -317,39 +294,34 @@ static void InvShiftRows( state_t *state )
/** Mixes the columns of (already-mixed) state matrix to reverse the process. */
static void InvMixColumns( state_t *state )
{
- uint8_t a, b, c, d, i;
- for (i = 0; i < Nb; ++i)
- { /* see: crypto.stackexchange.com/q/48872 */
- a = (*state)[i][0];
- b = (*state)[i][1];
- c = (*state)[i][2];
- d = (*state)[i][3];
-
- (*state)[i][0] = mulGF8( 14, a ) ^ mulGF8( 11, b ) ^ mulGF8( 13, c ) ^ mulGF8( 9, d );
- (*state)[i][1] = mulGF8( 14, b ) ^ mulGF8( 11, c ) ^ mulGF8( 13, d ) ^ mulGF8( 9, a );
- (*state)[i][2] = mulGF8( 14, c ) ^ mulGF8( 11, d ) ^ mulGF8( 13, a ) ^ mulGF8( 9, b );
- (*state)[i][3] = mulGF8( 14, d ) ^ mulGF8( 11, a ) ^ mulGF8( 13, b ) ^ mulGF8( 9, c );
+ uint8_t i, c[4];
+ for (i = 0; i < Nb; ++i) /* see: crypto.stackexchange.com/q/2569 */
+ {
+ COPY32BIT( (*state)[i], c[0] );
+ (*state)[i][0] = InvGM( c[0], c[1], c[2], c[3] );
+ (*state)[i][1] = InvGM( c[1], c[2], c[3], c[0] );
+ (*state)[i][2] = InvGM( c[2], c[3], c[0], c[1] );
+ (*state)[i][3] = InvGM( c[3], c[0], c[1], c[2] );
}
}
-/** Decrypts a cipher-text input block, into a 128-bit plain text as output.. */
+/** Decrypt a ciphertext input block and save the result/plaintext to output. */
static void rijndaelDecrypt( const block_t input, block_t output )
{
- uint8_t round = ROUNDS;
+ uint8_t r;
+ state_t *state = (void*) output;
- /* copy the input into state matrix, i.e. state is initialized by input.. */
- if (input != output) memcpy( output, input, BLOCKSIZE );
+ /* copy input to the state matrix, i.e initialize the state by ciphertext */
+ if (input != output) memcpy( state, input, BLOCKSIZE );
- AddRoundKey( ROUNDS, output ); /* First, add the last round key to state */
-
- /* The decryption completes after #ROUNDS iterations, of which the first
- * #ROUNDS-1 are identical. The last round doesn't involve mixing columns */
- while (round)
+ /* Decryption completes after #ROUNDS iterations. All rounds except the 1st
+ * one are identical. The first round doesn't involve [inv]mixing columns */
+ for (r = ROUNDS; r != 0; )
{
- InvShiftRows( (state_t*) output );
+ r-- != ROUNDS ? InvMixColumns( state ) : AddRoundKey( ROUNDS, output );
+ InvShiftRows( state );
InvSubBytes( output );
- AddRoundKey( --round, output );
- if (round) InvMixColumns( (state_t*) output );
+ AddRoundKey( r, output );
}
}
#endif /* DECRYPTION */
@@ -358,200 +330,165 @@ static void rijndaelDecrypt( const block_t input, block_t output )
#if M_RIJNDAEL
/**
* @brief encrypt or decrypt a single block with a given key
- * @param key a byte array with a fixed size specified by KEYSIZE
+ * @param key a byte array with a fixed size of KEYSIZE
* @param mode mode of operation: 'E' (1) to encrypt, 'D' (0) to decrypt
* @param x input byte array with BLOCKSIZE bytes
* @param y output byte array with BLOCKSIZE bytes
*/
void AES_Cipher( const uint8_t* key, const char mode, const block_t x, block_t y )
{
- fmix_t cipher = mode & 1 ? &rijndaelEncrypt : &rijndaelDecrypt;
KeyExpansion( key );
- cipher( x, y );
+ mode & 1 ? rijndaelEncrypt( x, y ) : rijndaelDecrypt( x, y );
}
#endif
/*----------------------------------------------------------------------------*\
* Implementation of different block ciphers modes *
- * Auxiliary Functions *
+ * Definitions & Auxiliary Functions *
\*----------------------------------------------------------------------------*/
#define AES_SetKey(key) KeyExpansion( key )
+/** function-pointer types, indicating functions that take fixed-size blocks: */
+typedef void (*fdouble_t)( block_t );
+typedef void (*fmix_t)( const block_t, block_t );
+
+#define LAST (BLOCKSIZE - 1) /* last index in a block */
+
#if INCREASE_SECURITY
#define BURN(key) memset( key, 0, sizeof key )
#define SABOTAGE(buf, len) memset( buf, 0, len )
-#define MISMATCH constmemcmp /* constant-time comparison */
+#define MISMATCH constmemcmp /* a.k.a secure memcmp */
#else
#define MISMATCH memcmp
#define SABOTAGE(buf, len) (void) buf
-#define BURN(key) (void) key
+#define BURN(key) (void) key /* the line is ignored. */
+#endif
+
+#if INCREASE_SECURITY && 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 )
+{
+ uint8_t cmp = 0;
+ while (n--)
+ {
+ cmp |= src[n] ^ dst[n];
+ }
+ return cmp;
+}
#endif
#if SMALL_CIPHER
-#define putValueB(block, pos, val) block[pos - 1] = val >> 8; block[pos] = val
-#define putValueL(block, pos, val) block[pos + 1] = val >> 8; block[pos] = val
-#define xorWith(block, pos, val) block[pos] ^= (val)
-#define incBlock(block, big) ++block[big ? LAST : 0]
+typedef uint8_t count_t;
+
+#define incBlock(block, big) ++block[big ? LAST : 0]
+#define xorBENum(buf, num, pos) buf[pos - 1] ^= (num) >> 8; buf[pos] ^= num
+#define copyLNum(buf, num, pos) buf[pos + 1] = (num) >> 8; buf[pos] = num
+
#else
+typedef size_t count_t;
-#if CTR
+#if CTR || KWA || FPE
-/** increment the value of a counter block, regarding its endian-ness ....... */
-static void incBlock( block_t block, const char big )
-{
- uint8_t i;
- if (big) /* big-endian counter */
- {
- for (i = LAST; !++block[i] && i--; ); /* (inc until no overflow) */
- }
- else
- {
- for (i = 0; !++block[i] && i < 4; ++i);
- }
-}
-
-/** copy big endian value to the block, starting at the specified position... */
-static void putValueB( block_t block, uint8_t pos, size_t val )
+/** xor a byte array with a big-endian integer, whose LSB is at specified pos */
+static void xorBENum( uint8_t* buff, size_t num, uint8_t pos )
{
do
- block[pos--] = (uint8_t) val;
- while (val >>= 8);
+ buff[pos--] ^= (uint8_t) num;
+ while (num >>= 8);
}
#endif
#if XTS || GCM_SIV
-/** copy little endian value to the block, starting at the specified position */
-static void putValueL( block_t block, uint8_t pos, size_t val )
+/** copy a little endian integer to the block, with LSB at specified position */
+static void copyLNum( block_t block, size_t num, uint8_t pos )
{
do
- block[pos++] = (uint8_t) val;
- while (val >>= 8);
+ block[pos++] = (uint8_t) num;
+ while (num >>= 8);
}
#endif
-#if KWA
+#if CTR
-/** xor a big endian value with a half-block. */
-static void xorWith( uint8_t* block, uint8_t pos, size_t val )
+/** increment the value of a 128-bit counter block, regarding its endian-ness */
+static void incBlock( block_t block, uint8_t b )
{
- do
- block[pos--] ^= (uint8_t) val;
- while (val >>= 8);
+ if (b) /* big-endian: inc the LSB, */
+ { /* ..until no overflow */
+ for (b = LAST; !++block[b]; ) --b;
+ return;
+ }
+ while (!++block[b]) /* little-endian counter */
+ {
+ if (++b == 4) return;
+ }
}
#endif
#endif /* SMALL CIPHER */
-
-#ifdef AES_PADDING
-
-/** in ECB or CBC without CTS, the last (partial) block has to be padded .... */
-static char padBlock( const uint8_t* input, const uint8_t len, block_t output )
-{
-#if AES_PADDING == 2
- memset( output + len, 0, BLOCKSIZE - len ); /* ISO/IEC 7816-4 padding */
- output[len] = 0x80;
-#elif AES_PADDING
- uint8_t p = BLOCKSIZE - len; /* PKCS#7 padding */
- memset( output + len, p, p );
-#else
- if (len == 0) return 0; /* default padding */
- memset( output + len, 0, BLOCKSIZE - len );
-#endif
-
- memcpy( output, input, len );
- return 1;
-}
-#endif /* PADDING */
-
-#if CTS || AEAD_MODES
-
-/** The input block `y` is xor-ed with `x` and then mixed with block `src`... */
-static void xorThenMix( const uint8_t* x, const uint8_t len,
- const block_t src, fmix_t mix, block_t y )
-{
- uint8_t i;
- for (i = 0; i < len; ++i) y[i] ^= x[i];
-
- mix( src, y ); /* Y = mix( S, Y ^ X ) */
-}
-#endif
-
-#if CBC || CFB || OFB || CTR || OCB
-
-/** Result of applying a function to block `b` is xor-ed with `x` to get `y`. */
-static void mixThenXor( const block_t b, fmix_t mix, block_t tmp,
- const uint8_t* x, const uint8_t len, uint8_t* y )
-{
- uint8_t i;
- if (len == 0) return; /* f(B) = temp; Y = temp ^ X */
-
- mix( b, tmp );
- for (i = 0; i < len; ++i) y[i] = tmp[i] ^ x[i];
-}
-#endif
-
#if EAX && !EAXP || SIV || OCB || CMAC
/** Multiply a block by two in Galois bit field GF(2^128): big-endian version */
-static void doubleGF128B( block_t block )
+static void doubleBGF128( block_t block )
{
- int i, s = 0;
- for (i = BLOCKSIZE; i--; s >>= 8) /* loop from last to first, */
- { /* left-shift each byte and */
- s |= block[i] << 1; /* ..add the previous MSB. */
- block[i] = (uint8_t) s;
- } /* if first MSB is carried: */
- if (s) block[LAST] ^= 0x87; /* B ^= 10000111b (B.E.) */
+ int i, c = 0;
+ for (i = BLOCKSIZE; i > 0; c >>= 8) /* from last byte (LSB) to */
+ { /* first: left-shift, then */
+ c |= block[--i] << 1; /* append the previous MSBit */
+ block[i] = (uint8_t) c;
+ } /* if first MSBit is carried */
+ block[LAST] ^= c * 0x87; /* .. B ^= 10000111b (B.E.) */
}
#endif
#if XTS || EAXP
-/** Multiply a block by two in GF(2^128) field: this is little-endian version */
-static void doubleGF128L( block_t block )
+/** Multiply a block by two in the GF(2^128) field: the little-endian version */
+static void doubleLGF128( block_t block )
{
- int s = 0, i;
- for (i = 0; i < BLOCKSIZE; s >>= 8) /* the same as doubleGF128B */
+ int c = 0, i;
+ for (i = 0; i < BLOCKSIZE; c >>= 8) /* the same as doubleBGF128 */
{ /* ..but with reversed bytes */
- s |= block[i] << 1;
- block[i++] = (uint8_t) s;
+ c |= block[i] << 1;
+ block[i++] = (uint8_t) c;
}
- if (s) block[0] ^= 0x87; /* B ^= 10000111b (L.E.) */
+ block[0] ^= c * 0x87; /* B ^= 10000111b (L.E.) */
}
#endif
#if GCM
/** Divide a block by two in GF(2^128) field: used in big endian, 128bit mul. */
-static void halveGF128B( block_t block )
+static void halveBGF128( block_t block )
{
- unsigned i, t = 0;
- for (i = 0; i < BLOCKSIZE; t <<= 8) /* loop first to last byte, */
- { /* add the previous LSB then */
- t |= block[i]; /* ..shift it to the right. */
- block[i++] = (uint8_t) (t >> 1);
+ unsigned i, c = 0;
+ for (i = 0; i < BLOCKSIZE; c <<= 8) /* from first to last byte, */
+ { /* prepend the previous LSB */
+ c |= block[i]; /* then shift it to right. */
+ block[i++] = (uint8_t) (c >> 1);
} /* if block is odd (LSB = 1) */
- if (t & 0x100) block[0] ^= 0xe1; /* .. B ^= 11100001b << 120 */
+ if (c & 0x100) block[0] ^= 0xe1; /* .. B ^= 11100001b << 120 */
}
/** This function carries out multiplication in 128bit Galois field GF(2^128) */
static void mulGF128( const block_t x, block_t y )
{
- uint8_t i, j, result[BLOCKSIZE] = { 0 }; /* working memory */
-
- for (i = 0; i < BLOCKSIZE; ++i)
- {
- for (j = 0; j < 8; ++j) /* check all the bits of X, */
+ block_t result = { 0 }; /* working memory */
+ uint8_t b, i = 0;
+ do
+ for (b = 0x80; b; b >>= 1) /* check all the bits of X, */
{
- if (x[i] << j & 0x80) /* ..and if any bit is set */
+ if (x[i] & b) /* ..and if any bit is set, */
{
- xorBlock( y, result ); /* M ^= Y */
+ xorBlock( y, result ); /* ..add Y to the result */
}
- halveGF128B( y ); /* Y_next = (Y / 2) in GF */
+ halveBGF128( y ); /* Y_next = (Y / 2) in GF */
}
- }
+ while (i++ != LAST);
+
memcpy( y, result, sizeof result ); /* result is saved into y */
}
#endif /* GCM */
@@ -559,45 +496,61 @@ static void mulGF128( const block_t x, block_t y )
#if GCM_SIV
/** Divide a block by two in GF(2^128) field: the little-endian version (duh) */
-static void halveGF128L( block_t block )
+static void halveLGF128( block_t block )
{
- unsigned t = 0, i;
- for (i = BLOCKSIZE; i--; t <<= 8) /* the same as halveGF128B ↑ */
+ unsigned c = 0, i;
+ for (i = BLOCKSIZE; i > 0; c <<= 8) /* the same as halveBGF128 ↑ */
{ /* ..but with reversed bytes */
- t |= block[i];
- block[i] = (uint8_t) (t >> 1);
+ c |= block[--i];
+ block[i] = (uint8_t) (c >> 1);
}
- if (t & 0x100) block[LAST] ^= 0xe1; /* B ^= L.E 11100001b << 120 */
+ if (c & 0x100) block[LAST] ^= 0xe1; /* B ^= LE. 11100001b << 120 */
}
/** Dot multiplication in GF(2^128) field: used in POLYVAL hash for GCM-SIV.. */
static void dotGF128( const block_t x, block_t y )
{
- uint8_t i, j, result[BLOCKSIZE] = { 0 };
-
- for (i = BLOCKSIZE; i--; )
- {
- for (j = 8; j--; ) /* pretty much the same as */
+ block_t result = { 0 };
+ uint8_t b, i = LAST;
+ do
+ for (b = 0x80; b; b >>= 1) /* pretty much the same as */
{ /* ..(reversed) mulGF128 */
- halveGF128L( y );
- if (x[i] >> j & 1)
+ halveLGF128( y );
+ if (x[i] & b)
{
xorBlock( y, result );
}
}
- }
+ while (i-- != 0);
+
memcpy( y, result, sizeof result ); /* result is saved into y */
}
#endif /* GCM-SIV */
-#if AEAD_MODES
+#if CBC || CFB || OFB || CTR || OCB
-/** the overall scheme of CMAC or GMAC hash functions: divide data into 128-bit
- * blocks; then xor and apply the digest/mixing function to each xor-ed block */
-static void MAC( const void* data, const size_t dataSize,
- const block_t seed, fmix_t mix, block_t result )
+/** Result of applying a function to block `B` is xor-ed with `X` to get `Y`. */
+static void mixThenXor( fmix_t mix, const block_t B, block_t f,
+ const uint8_t* X, uint8_t n, uint8_t* Y )
{
- uint8_t const r = dataSize % BLOCKSIZE, *x;
+ if (n == 0) return;
+
+ mix( B, f ); /* Y = f(B) ^ X */
+ while (n--)
+ {
+ Y[n] = f[n] ^ X[n];
+ }
+}
+#endif
+
+#if AEAD_MODES || FPE
+
+/** xor the result with input data and then apply the digest/mixing function.
+ * repeat the process for each block of data until all blocks are digested... */
+static void xMac( const void* data, const size_t dataSize,
+ const block_t seed, fmix_t mix, block_t result )
+{
+ uint8_t const *x;
count_t n = dataSize / BLOCKSIZE; /* number of full blocks */
for (x = data; n--; x += BLOCKSIZE)
@@ -605,52 +558,68 @@ static void MAC( const void* data, const size_t dataSize,
xorBlock( x, result ); /* M_next = mix(seed, M ^ X) */
mix( seed, result );
}
- if (r == 0) return; /* do the same with the last */
- xorThenMix( x, r, seed, mix, result ); /* ..partial block (if any) */
+ for (n = dataSize % BLOCKSIZE; n--; )
+ {
+ result[n] ^= x[n];
+ if (!n)
+ {
+ mix( seed, result );
+ }
+ }
}
+#endif
-#if CMAC || SIV || EAX
+#if CMAC || SIV || EAX || OCB
-/** calculate the CMAC hash of input data using pre-calculated keys: D and Q. */
+/** calculate the CMAC of input data using pre-calculated keys: D (K1) and Q. */
static void cMac( const block_t D, const block_t Q,
const void* data, const size_t dataSize, block_t mac )
{
- block_t M = { 0 };
- uint8_t r = dataSize ? (dataSize - 1) % BLOCKSIZE + 1 : 0;
- const void* endblock = (const char*) data + dataSize - r;
+ const uint8_t s = dataSize ? (dataSize - 1) % BLOCKSIZE + 1 : 0;
+ const uint8_t *e = s ? (uint8_t const*) data + dataSize - s : &s;
- if (r < sizeof M) M[r] = 0x80;
- memcpy( M, endblock, r ); /* copy last block into M */
- xorBlock( r < sizeof M ? Q : D, M ); /* ..and pad( M; D, Q ) */
-
- MAC( data, dataSize - r, mac, &rijndaelEncrypt, mac );
- xorThenMix( M, sizeof M, mac, &rijndaelEncrypt, mac );
+ xMac( data, dataSize - s, mac, &rijndaelEncrypt, mac );
+ if (s < BLOCKSIZE)
+ {
+ mac[s] ^= 0x80;
+ }
+ xorBlock( s < BLOCKSIZE ? Q : D, mac ); /* pad( M; D, Q ) */
+ xMac( e, s + !s, mac, &rijndaelEncrypt, mac );
}
-typedef void (*fdouble_t)(block_t); /* block-double function ptr */
-
-/** calculate key-dependent constants D and Q for CMAC, regarding endianness: */
-static void getSubkeys( const uint8_t* key, fdouble_t dou, block_t D, block_t Q )
+/** calculate key-dependent constants D and Q using a given doubling function */
+static void getSubkeys( fdouble_t fdouble, const char quad,
+ const uint8_t* key, block_t D, block_t Q )
{
AES_SetKey( key );
rijndaelEncrypt( D, D ); /* H or L_* = Enc(zeros) */
- dou( D ); /* D or L_$ = double(L_*) */
+ if (quad)
+ {
+ fdouble( D ); /* D or L_$ = double(L_*) */
+ }
memcpy( Q, D, BLOCKSIZE );
- dou( Q ); /* Q or L_0 = double(L_$) */
+ fdouble( Q ); /* Q or L_0 = double(L_$) */
}
#endif
-#if INCREASE_SECURITY
+#ifdef AES_PADDING
-/** 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 len )
+/** in ECB mode & CBC without CTS, the last (partial) block has to be padded. */
+static char padBlock( const uint8_t len, block_t block )
{
- uint8_t i, cmp = 0;
- for (i = 0; i < len; ++i) cmp |= src[i] ^ dst[i];
- return cmp;
+#if AES_PADDING
+ uint8_t n = BLOCKSIZE - len, *p = &block[len];
+ memset( p, n * (AES_PADDING != 2), n );
+ *p ^= (0x80) * (AES_PADDING == 2); /* either PKCS#7 / IEC7816-4 */
+#else
+ if (len) /* default (zero) padding */
+ {
+ memset( block + len, 0, BLOCKSIZE - len );
+ }
+#endif
+ return len || AES_PADDING;
}
#endif
-#endif /* AEAD */
/*----------------------------------------------------------------------------*\
@@ -667,17 +636,16 @@ static uint8_t constmemcmp( const uint8_t* src, const uint8_t* dst, uint8_t len
void AES_ECB_encrypt( const uint8_t* key,
const uint8_t* pntxt, const size_t ptextLen, uint8_t* crtxt )
{
- uint8_t const *x;
- uint8_t *y = crtxt;
+ uint8_t *y;
count_t n = ptextLen / BLOCKSIZE; /* number of full blocks */
+ memcpy( crtxt, pntxt, ptextLen ); /* copy plaintext to output */
AES_SetKey( key );
- for (x = pntxt; n--; x += BLOCKSIZE)
+ for (y = crtxt; n--; y += BLOCKSIZE)
{
- rijndaelEncrypt( x, y ); /* C = Enc(P) */
- y += BLOCKSIZE;
+ rijndaelEncrypt( y, y ); /* C = Enc(P) */
}
- if (padBlock( x, ptextLen % BLOCKSIZE, y ))
+ if (padBlock( ptextLen % BLOCKSIZE, y ))
{
rijndaelEncrypt( y, y );
}
@@ -695,15 +663,14 @@ void AES_ECB_encrypt( const uint8_t* key,
char AES_ECB_decrypt( const uint8_t* key,
const uint8_t* crtxt, const size_t crtxtLen, uint8_t* pntxt )
{
- uint8_t const *x;
- uint8_t *y = pntxt;
+ uint8_t *y;
count_t n = crtxtLen / BLOCKSIZE;
+ memcpy( pntxt, crtxt, crtxtLen ); /* do in-place decryption */
AES_SetKey( key );
- for (x = crtxt; n--; x += BLOCKSIZE)
+ for (y = pntxt; n--; y += BLOCKSIZE)
{
- rijndaelDecrypt( x, y ); /* P = Dec(C) */
- y += BLOCKSIZE;
+ rijndaelDecrypt( y, y ); /* P = Dec(C) */
}
BURN( RoundKey );
@@ -730,37 +697,38 @@ char AES_ECB_decrypt( const uint8_t* key,
char AES_CBC_encrypt( const uint8_t* key, const block_t iVec,
const uint8_t* pntxt, const size_t ptextLen, uint8_t* crtxt )
{
- uint8_t const *x = pntxt, *iv = iVec;
+ uint8_t const *iv = iVec;
uint8_t r = ptextLen % BLOCKSIZE, *y;
count_t n = ptextLen / BLOCKSIZE;
-
#if CTS
- if (!n) return ENCRYPTION_FAILURE;
- r += (r == 0 && n > 1) * BLOCKSIZE;
- n -= (r == BLOCKSIZE); /* hold the last block */
+ if (n == 0) return ENCRYPTION_FAILURE; /* size of data >= BLOCKSIZE */
+
+ if (r == 0 && --n) r = BLOCKSIZE;
+ n += !n; /* if single block, set n=1 */
#endif
- x += ptextLen - r;
- memcpy( crtxt, pntxt, ptextLen - r ); /* copy plaintext to output */
+ memcpy( crtxt, pntxt, ptextLen ); /* do in-place encryption */
AES_SetKey( key );
for (y = crtxt; n--; y += BLOCKSIZE)
{
- xorBlock( iv, y ); /* Y = P because of memcpy */
- rijndaelEncrypt( y, y ); /* C = Enc(IV ^ P) */
- iv = y; /* IV_next = C */
+ xorBlock( iv, y ); /* C = Enc(IV ^ P) */
+ rijndaelEncrypt( y, y ); /* IV_next = C */
+ iv = y;
}
#if CTS /* cipher-text stealing CS3 */
if (r)
{
+ block_t yn = { 0 };
+ memcpy( yn, y, r ); /* backup the last chunk */
memcpy( y, y - BLOCKSIZE, r ); /* 'steal' the cipher-text */
- y -= BLOCKSIZE; /* ..to fill the last block */
- xorThenMix( x, r, y, &rijndaelEncrypt, y );
+ y -= BLOCKSIZE; /* ..to fill the last chunk */
+ iv = yn;
#else
- if (padBlock( x, r, y ))
+ if (padBlock( r, y ))
{
+#endif
xorBlock( iv, y );
rijndaelEncrypt( y, y );
-#endif
}
BURN( RoundKey );
return ENDED_IN_SUCCESS;
@@ -781,11 +749,11 @@ char AES_CBC_decrypt( const uint8_t* key, const block_t iVec,
uint8_t const *x = crtxt, *iv = iVec;
uint8_t r = crtxtLen % BLOCKSIZE, *y;
count_t n = crtxtLen / BLOCKSIZE;
-
#if CTS
- if (!n) return DECRYPTION_FAILURE;
- r += (r == 0 && n > 1) * BLOCKSIZE;
- n -= (r == BLOCKSIZE) + (r != 0); /* last two blocks swapped */
+ if (n == 0) return DECRYPTION_FAILURE;
+
+ if (r == 0 && --n) r = BLOCKSIZE;
+ n -= (r > 0) - !n; /* hold the last two blocks */
#else
if (r) return DECRYPTION_FAILURE;
#endif
@@ -797,13 +765,13 @@ char AES_CBC_decrypt( const uint8_t* key, const block_t iVec,
xorBlock( iv, y ); /* IV_next = C */
iv = x;
x += BLOCKSIZE;
- } /* #if !CTS, surely r = 0 */
+ } /* r = 0 unless CTS enabled */
if (r)
- { /* P2 = Dec(C1) ^ C2 */
- mixThenXor( x, &rijndaelDecrypt, y, x + BLOCKSIZE, r, y + BLOCKSIZE );
+ { /* P2 = Dec(C1) ^ C2 */
+ mixThenXor( &rijndaelDecrypt, x, y, x + BLOCKSIZE, r, y + BLOCKSIZE );
memcpy( y, x + BLOCKSIZE, r );
- rijndaelDecrypt( y, y ); /* copy C2 to Dec(C1): -> T */
- xorBlock( iv, y ); /* P1 = IV ^ Dec(T) */
+ rijndaelDecrypt( y, y ); /* P1 = Dec(T) ^ IV, where */
+ xorBlock( iv, y ); /* T = C2 padded by Dec(C1) */
}
BURN( RoundKey );
@@ -841,7 +809,7 @@ static void CFB_Cipher( const uint8_t* key, const block_t iVec, const char mode,
iv = mode ? y : x; /* IV_next = Ciphertext */
y += BLOCKSIZE;
}
- mixThenXor( iv, &rijndaelEncrypt, tmp, x, dataSize % BLOCKSIZE, y );
+ mixThenXor( &rijndaelEncrypt, iv, tmp, x, dataSize % BLOCKSIZE, y );
BURN( RoundKey );
}
@@ -890,20 +858,20 @@ void AES_CFB_decrypt( const uint8_t* key, const block_t iVec,
void AES_OFB_encrypt( const uint8_t* key, const block_t iVec,
const uint8_t* pntxt, const size_t ptextLen, uint8_t* crtxt )
{
- block_t iv;
+ count_t n = ptextLen / BLOCKSIZE;
uint8_t *y;
- count_t n = ptextLen / BLOCKSIZE; /* number of full blocks */
- memcpy( crtxt, pntxt, ptextLen ); /* copy plaintext to output */
+ block_t iv;
+
memcpy( iv, iVec, sizeof iv );
+ memcpy( crtxt, pntxt, ptextLen ); /* i.e. in-place encryption */
AES_SetKey( key );
for (y = crtxt; n--; y += BLOCKSIZE)
{
- rijndaelEncrypt( iv, iv ); /* C = Enc(IV) ^ P */
- xorBlock( iv, y ); /* IV_next = Enc(IV) */
+ rijndaelEncrypt( iv, iv ); /* IV_next = Enc(IV) */
+ xorBlock( iv, y ); /* C = IV_next ^ P */
}
-
- mixThenXor( iv, &rijndaelEncrypt, iv, y, ptextLen % BLOCKSIZE, y );
+ mixThenXor( &rijndaelEncrypt, iv, iv, y, ptextLen % BLOCKSIZE, y );
BURN( RoundKey );
}
@@ -929,7 +897,7 @@ void AES_OFB_decrypt( const uint8_t* key, const block_t iVec,
\*----------------------------------------------------------------------------*/
#if CTR
/**
- * @brief the overall scheme of operation in block-counter mode
+ * @brief the general scheme of operation in block-counter mode
* @param iCtr initialized counter block
* @param big big-endian block increment (1, 2) or little endian (0)
* @param input buffer of the input plain/cipher-text
@@ -941,19 +909,20 @@ static void CTR_Cipher( const block_t iCtr, const char big,
{
block_t c, enc;
count_t n = dataSize / BLOCKSIZE;
- uint8_t *y = output;
- if (input != output) memcpy( output, input, dataSize );
+ uint8_t *y;
+ memcpy( output, input, dataSize ); /* do in-place en/decryption */
memcpy( c, iCtr, sizeof c );
+
if (big > 1) incBlock( c, 1 ); /* pre-increment for CCM/GCM */
- for ( ; n--; y += BLOCKSIZE)
+ for (y = output; n--; y += BLOCKSIZE)
{
rijndaelEncrypt( c, enc ); /* both in en[de]cryption: */
xorBlock( enc, y ); /* Y = Enc(Ctr) ^ X */
incBlock( c, big ); /* Ctr_next = Ctr + 1 */
}
- mixThenXor( c, &rijndaelEncrypt, c, y, dataSize % BLOCKSIZE, y );
+ mixThenXor( &rijndaelEncrypt, c, c, y, dataSize % BLOCKSIZE, y );
}
#endif
@@ -974,7 +943,7 @@ void AES_CTR_encrypt( const uint8_t* key, const uint8_t* iv,
#else
block_t CTRBLOCK = { 0 };
memcpy( CTRBLOCK, iv, CTR_IV_LENGTH );
- putValueB( CTRBLOCK, LAST, CTR_STARTVALUE );
+ xorBENum( CTRBLOCK, CTR_STARTVALUE, LAST ); /* initialize the counter */
#endif
AES_SetKey( key );
CTR_Cipher( CTRBLOCK, 1, pntxt, ptextLen, crtxt );
@@ -999,32 +968,34 @@ void AES_CTR_decrypt( const uint8_t* key, const uint8_t* iv,
/*----------------------------------------------------------------------------*\
XEX-AES based modes (xor-encrypt-xor): demonstrating the main idea
+ + main functions of XTS-AES (XEX Tweaked-codebook with ciphertext Stealing)
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(XTS)
/**
* @brief encrypt or decrypt a data unit with given key-pair using XEX method
- * @param keypair pair of encryption keys, each one has KEYSIZE bytes
* @param cipher block cipher function: rijndaelEncrypt or rijndaelDecrypt
+ * @param keypair pair of encryption keys, each one has KEYSIZE bytes
+ * @param tweak data unit identifier block, similar to nonce in CTR mode
+ * @param sectid sector id: if the given value is -1, use tweak value
* @param dataSize size of input data, to be encrypted/decrypted
- * @param scid sector id: if the given value is -1, use tweak value
- * @param tweakid data unit identifier, similar to nonce in CTR mode
* @param T one-time pad which is xor-ed with both plain/cipher text
* @param storage working memory; result of encryption/decryption process
*/
-static void XEX_Cipher( const uint8_t* keypair, fmix_t cipher,
- const size_t dataSize, const size_t scid,
- const block_t tweakid, block_t T, void* storage )
+static void XEX_Cipher( fmix_t cipher, const uint8_t* keypair,
+ const block_t tweak, const size_t sectid,
+ const size_t dataSize, block_t T, void* storage )
{
uint8_t *y;
count_t n = dataSize / BLOCKSIZE;
- if (scid == (size_t) ~0)
+ if (sectid == ~(size_t) 0)
{ /* the `i` block is either */
- memcpy( T, tweakid, BLOCKSIZE ); /* ..a little-endian number */
+ memcpy( T, tweak, BLOCKSIZE ); /* ..a little-endian number */
} /* ..or a byte array. */
else
{
- putValueL( T, 0, scid );
+ memset( T, 0, BLOCKSIZE );
+ copyLNum( T, sectid, 0 );
}
AES_SetKey( keypair + KEYSIZE ); /* T = encrypt `i` with key2 */
rijndaelEncrypt( T, T );
@@ -1035,42 +1006,38 @@ static void XEX_Cipher( const uint8_t* keypair, fmix_t cipher,
xorBlock( T, y ); /* xor T with input */
cipher( y, y );
xorBlock( T, y ); /* Y = T ^ Cipher( T ^ X ) */
- doubleGF128L( T ); /* T_next = T * alpha */
+ doubleLGF128( T ); /* T_next = T * alpha */
}
}
-/*----------------------------------------------------------------------------*\
- XTS-AES (XEX Tweaked-codebook with ciphertext Stealing): main functions
-\*----------------------------------------------------------------------------*/
/**
* @brief encrypt the input plaintext using XTS-AES block-cipher method
* @param keys two-part encryption key with a fixed size of 2*KEYSIZE
- * @param twkId tweak value of data unit, a.k.a sector ID (little-endian)
+ * @param tweak tweak bytes of data unit, a.k.a sector ID (little-endian)
* @param pntxt input plaintext buffer
* @param ptextLen size of plaintext in bytes
* @param crtxt resulting cipher-text buffer
*/
-char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* twkId,
+char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* tweak,
const uint8_t* pntxt, const size_t ptextLen, uint8_t* crtxt )
{
- block_t T = { 0 };
uint8_t r = ptextLen % BLOCKSIZE, *c;
size_t len = ptextLen - r;
+ block_t T;
if (len == 0) return ENCRYPTION_FAILURE;
- memcpy( crtxt, pntxt, len ); /* copy input data to output */
- XEX_Cipher( keys, &rijndaelEncrypt, len, ~0, twkId, T, crtxt );
+ memcpy( crtxt, pntxt, len ); /* do in-place encryption */
+ c = crtxt + len - BLOCKSIZE;
+ XEX_Cipher( &rijndaelEncrypt, keys, tweak, ~0, len, T, crtxt );
if (r)
{ /* XTS for partial block */
- c = crtxt + len - BLOCKSIZE;
memcpy( crtxt + len, c, r ); /* 'steal' the cipher-text */
- memcpy( c, pntxt + len, r ); /* ..for the partial block */
+ memcpy( c, pntxt + len, r ); /* ..to fill the last chunk */
xorBlock( T, c );
rijndaelEncrypt( c, c );
xorBlock( T, c );
}
-
BURN( RoundKey );
return ENDED_IN_SUCCESS;
}
@@ -1078,27 +1045,27 @@ char AES_XTS_encrypt( const uint8_t* keys, const uint8_t* twkId,
/**
* @brief encrypt the input ciphertext using XTS-AES block-cipher method
* @param keys two-part encryption key with a fixed size of 2*KEYSIZE
- * @param twkId tweak value of data unit, a.k.a sector ID (little-endian)
+ * @param tweak tweak bytes of data unit, a.k.a sector ID (little-endian)
* @param crtxt input ciphertext buffer
* @param crtxtLen size of ciphertext in bytes
* @param pntxt resulting plaintext buffer
*/
-char AES_XTS_decrypt( const uint8_t* keys, const uint8_t* twkId,
+char AES_XTS_decrypt( const uint8_t* keys, const uint8_t* tweak,
const uint8_t* crtxt, const size_t crtxtLen, uint8_t* pntxt )
{
- block_t TT, T = { 0 };
uint8_t r = crtxtLen % BLOCKSIZE, *p;
size_t len = crtxtLen - r;
+ block_t TT, T;
if (len == 0) return DECRYPTION_FAILURE;
- memcpy( pntxt, crtxt, len ); /* copy input data to output */
- p = pntxt + len - BLOCKSIZE;
- XEX_Cipher( keys, &rijndaelDecrypt, len - BLOCKSIZE, ~0, twkId, T, pntxt );
+ memcpy( pntxt, crtxt, len ); /* in-place decryption */
+ p = pntxt + len - BLOCKSIZE;
+ XEX_Cipher( &rijndaelDecrypt, keys, tweak, ~0, len - BLOCKSIZE, T, pntxt );
if (r)
{
memcpy( TT, T, sizeof T );
- doubleGF128L( TT ); /* TT = T * alpha, */
+ doubleLGF128( TT ); /* TT = T * alpha, */
xorBlock( TT, p ); /* because the stolen */
rijndaelDecrypt( p, p ); /* ..ciphertext was xor-ed */
xorBlock( TT, p ); /* ..with TT in encryption */
@@ -1120,7 +1087,7 @@ char AES_XTS_decrypt( const uint8_t* keys, const uint8_t* twkId,
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(CMAC)
/**
- * @brief derive the AES-CMAC hash of input data using an encryption key
+ * @brief derive the AES-CMAC of input data using an encryption key
* @param key AES encryption key
* @param data buffer of input data
* @param dataSize size of data in bytes
@@ -1130,8 +1097,8 @@ void AES_CMAC( const uint8_t* key,
const void* data, const size_t dataSize, block_t mac )
{
block_t K1 = { 0 }, K2;
- memset( mac, 0, BLOCKSIZE );
- getSubkeys( key, &doubleGF128B, K1, K2 );
+ memcpy( mac, K1, sizeof K1 ); /* initialize mac */
+ getSubkeys( &doubleBGF128, 1, key, K1, K2 );
cMac( K1, K2, data, dataSize, mac );
BURN( RoundKey );
}
@@ -1143,22 +1110,22 @@ void AES_CMAC( const uint8_t* key,
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(GCM)
-/** calculates GMAC hash of ciphertext and AAD using authentication subkey H: */
+/** calculate the GMAC of ciphertext and AAD using an authentication subkey H */
static void GHash( const block_t H, const void* aData, const void* crtxt,
const size_t adataLen, const size_t crtxtLen, block_t gsh )
{
- block_t buf = { 0 }; /* save bit-sizes into buf */
- putValueB( buf, BLOCKSIZE - 9, adataLen * 8 );
- putValueB( buf, BLOCKSIZE - 1, crtxtLen * 8 );
+ block_t len = { 0 };
+ xorBENum( len, adataLen * 8, LAST / 2 );
+ xorBENum( len, crtxtLen * 8, LAST ); /* save bit-sizes into len */
- MAC( aData, adataLen, H, &mulGF128, gsh ); /* first digest AAD, then */
- MAC( crtxt, crtxtLen, H, &mulGF128, gsh ); /* ..ciphertext, and then */
- MAC( buf, sizeof buf, H, &mulGF128, gsh ); /* ..bit sizes into GHash */
+ xMac( aData, adataLen, H, &mulGF128, gsh ); /* first digest AAD, then */
+ xMac( crtxt, crtxtLen, H, &mulGF128, gsh ); /* ..ciphertext, and then */
+ xMac( len, sizeof len, H, &mulGF128, gsh ); /* ..bit sizes into GHash */
}
/** encrypt zeros to get authentication subkey H, and prepare the IV for GCM. */
-static void GInitialize( const uint8_t* key,
- const uint8_t* nonce, block_t authKey, block_t iv )
+static void GCM_Init( const uint8_t* key,
+ const uint8_t* nonce, block_t authKey, block_t iv )
{
AES_SetKey( key );
rijndaelEncrypt( authKey, authKey ); /* authKey = Enc(zero block) */
@@ -1187,7 +1154,7 @@ void AES_GCM_encrypt( const uint8_t* key, const uint8_t* nonce,
uint8_t* crtxt, block_t auTag )
{
block_t H = { 0 }, iv = { 0 }, gsh = { 0 };
- GInitialize( key, nonce, H, iv ); /* get IV & auth. subkey H */
+ GCM_Init( key, nonce, H, iv ); /* get IV & auth. subkey H */
CTR_Cipher( iv, 2, pntxt, ptextLen, crtxt );
rijndaelEncrypt( iv, auTag ); /* tag = Enc(iv) ^ GHASH */
@@ -1214,7 +1181,7 @@ char AES_GCM_decrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t tagLen, uint8_t* pntxt )
{
block_t H = { 0 }, iv = { 0 }, gsh = { 0 };
- GInitialize( key, nonce, H, iv );
+ GCM_Init( key, nonce, H, iv );
GHash( H, aData, crtxt, aDataLen, crtxtLen, gsh );
rijndaelEncrypt( iv, H );
@@ -1238,36 +1205,34 @@ char AES_GCM_decrypt( const uint8_t* key, const uint8_t* nonce,
/** this function calculates the CBC-MAC of plaintext and authentication data */
static void CBCMac( const block_t iv, const void* aData, const void* pntxt,
- const size_t aDataLen, const size_t ptextLen, block_t cm )
+ const size_t aDataLen, const size_t ptextLen, block_t M )
{
block_t A = { 0 };
- uint8_t p, s = BLOCKSIZE - 2;
- memcpy( cm, iv, BLOCKSIZE ); /* initialize CBC-MAC */
+ uint8_t s = aDataLen < LAST ? aDataLen : sizeof A - 2;
- cm[0] |= (CCM_TAG_LEN - 2) << 2; /* set some flags on M_0 */
- putValueB( cm, LAST, ptextLen ); /* copy data size into M_0 */
- if (aDataLen) /* <-- else: M_* = M_0 */
+ memcpy( M, iv, BLOCKSIZE ); /* initialize CBC-MAC */
+ M[0] |= (CCM_TAG_LEN - 2) << 2; /* set some flags on M_* */
+ xorBENum( M, ptextLen, LAST ); /* copy data size into M_* */
+
+ if (aDataLen) /* feed aData into CBC-MAC */
{
- if (aDataLen < s) s = aDataLen;
- p = aDataLen < 0xFF00 ? 1 : 5;
- putValueB( A, p, aDataLen ); /* len_id = aDataLen */
- if (p == 5)
- {
+ M[0] |= 0x40;
+ rijndaelEncrypt( M, M ); /* flag M_* and encrypt it */
+ if (aDataLen > 0xFEFF)
+ { /* assuming aDataLen < 2^32 */
s -= 4;
- putValueB( A, 1, 0xFFFE ); /* prepend FFFE to len_id */
+ A[0] = 0xFF; A[1] = 0xFE; /* prepend FFFE to aDataLen */
}
- memcpy( A + p + 1, aData, s ); /* A = len_id ~~ ADATA */
- cm[0] |= 0x40;
- rijndaelEncrypt( cm, cm ); /* M_* = Enc( flagged M_0 ) */
- xorBlock( A, cm );
+ xorBENum( A, aDataLen, LAST - s ); /* copy aDataLen into A, */
+ memcpy( A + sizeof A - s, aData, s ); /* ..and append aData */
}
- rijndaelEncrypt( cm, cm ); /* M_1 = Enc( M_* ^ A ), */
- if (aDataLen > s) /* CBC-MAC rest of adata */
+ xMac( A, sizeof A, M, &rijndaelEncrypt, M ); /* CBC-MAC start of aData, */
+ if (aDataLen > s) /* and then the rest of it */
{
- MAC( (char const*) aData + s, aDataLen - s, cm, &rijndaelEncrypt, cm );
+ xMac( (char const*) aData + s, aDataLen - s, M, &rijndaelEncrypt, M );
}
- MAC( pntxt, ptextLen, cm, &rijndaelEncrypt, cm );
+ xMac( pntxt, ptextLen, M, &rijndaelEncrypt, M );
}
/**
@@ -1316,6 +1281,7 @@ char AES_CCM_decrypt( const uint8_t* key, const uint8_t* nonce,
{
block_t iv = { 14 - CCM_NONCE_LEN, 0 }, cbc;
memcpy( iv + 1, nonce, CCM_NONCE_LEN );
+
if (tagLen && tagLen != CCM_TAG_LEN) return DECRYPTION_FAILURE;
AES_SetKey( key );
@@ -1343,30 +1309,42 @@ char AES_CCM_decrypt( const uint8_t* key, const uint8_t* nonce,
/** 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,
- const size_t aDataLen, const size_t ptextLen, block_t V )
+ const size_t aDataLen, const size_t ptextLen, block_t IV )
{
- block_t T = { 0 }, D = { 0 }, Q;
- uint8_t r = ptextLen >= BLOCKSIZE ? BLOCKSIZE : ptextLen % BLOCKSIZE;
- uint8_t const* x = (uint8_t const*) pntxt - r + ptextLen;
+ block_t K[2], Y;
+ uint8_t r = ptextLen % BLOCKSIZE, *D = K[0], *Q = K[1];
- getSubkeys( key, &doubleGF128B, D, Q );
- cMac( D, Q, T, sizeof T, T ); /* T_0 = CMAC(zero block) */
- if (aDataLen) /* process each ADATA unit */
- { /* ..the same way as this: */
- doubleGF128B( T );
- cMac( D, Q, aData, aDataLen, V ); /* C_A = CMAC(ADATA) */
- xorBlock( V, T ); /* T_1 = double(T_0) ^ C_A */
- memset( V, 0, BLOCKSIZE );
- }
- if (r < sizeof T)
+ memset( *K, 0, BLOCKSIZE );
+ memset( IV, 0, BLOCKSIZE ); /* initialize/clear IV */
+ getSubkeys( &doubleBGF128, 1, key, D, Q );
+ rijndaelEncrypt( D, Y ); /* Y_0 = CMAC(zero block) */
+
+ /* in case of multiple AAD units, each must be handled the same way as this.
+ * e.g. let aData be a 2D array and aDataLen a null-terminated one. then the
+ * following three lines starting with `if (aDataLen)` can be replaced by:
+ * for (i = 0; *aDataLen; ++i) { cMac( D, Q, aData[i], *aDataLen++, IV ); */
+ if (aDataLen)
{
- doubleGF128B( T );
- T[r] ^= 0x80; /* T = double(T_n) ^ pad(X) */
- while (r--) T[r] ^= x[r];
+ cMac( D, Q, aData, aDataLen, IV );
+ doubleBGF128( Y ); /* Y_$ = double( Y_{i-1} ) */
+ xorBlock( IV, Y ); /* Y_i = Y_$ ^ CMAC(AAD_i) */
+ memset( IV, 0, BLOCKSIZE );
+ }
+ if (ptextLen < sizeof Y)
+ { /* for short messages: */
+ doubleBGF128( Y ); /* Y = double( Y_n ) */
+ r = 0;
+ }
+ if (r)
+ {
+ memset( D, 0, BLOCKSIZE );
+ }
+ xorBlock( Y, D + r );
+ cMac( D, D, pntxt, ptextLen - r, IV ); /* CMAC*( Y xor_end M ) */
+ if (r)
+ {
+ cMac( NULL, Q, (const char*) pntxt + ptextLen - r, r, IV );
}
- else xorBlock( x, T ); /* T = T_n xor_end X */
-
- cMac( D, Q, T, sizeof T, V ); /* I.V = CMAC*(T) */
}
/**
@@ -1376,7 +1354,7 @@ static void S2V( const uint8_t* key,
* @param ptextLen size of plaintext in bytes
* @param aData additional authentication data
* @param aDataLen size of additional authentication data
- * @param iv synthesized I.V block, naturally prepended to ciphertext
+ * @param iv synthesized I.V block, typically prepended to ciphertext
* @param crtxt resulting cipher-text buffer
*/
void AES_SIV_encrypt( const uint8_t* keys,
@@ -1384,7 +1362,7 @@ void AES_SIV_encrypt( const uint8_t* keys,
const uint8_t* aData, const size_t aDataLen,
block_t iv, uint8_t* crtxt )
{
- block_t IV = { 0 };
+ block_t IV;
S2V( keys, aData, pntxt, aDataLen, ptextLen, IV );
memcpy( iv, IV, sizeof IV );
IV[8] &= 0x7F; IV[12] &= 0x7F; /* clear 2 bits for cipher */
@@ -1416,7 +1394,6 @@ char AES_SIV_decrypt( const uint8_t* keys, const block_t iv,
AES_SetKey( keys + KEYSIZE );
CTR_Cipher( IV, 1, crtxt, crtxtLen, pntxt );
- memset( IV, 0, sizeof IV );
S2V( keys, aData, pntxt, aDataLen, crtxtLen, IV );
BURN( RoundKey );
@@ -1439,30 +1416,30 @@ char AES_SIV_decrypt( const uint8_t* keys, const block_t iv,
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 buf = { 0 }; /* save bit-sizes into buf */
- putValueL( buf, 0, aDataLen * 8 );
- putValueL( buf, 8, ptextLen * 8 );
+ block_t len = { 0 }; /* save bit-sizes into len */
+ copyLNum( len, aDataLen * 8, 0 );
+ copyLNum( len, ptextLen * 8, 8 );
- MAC( aData, aDataLen, H, &dotGF128, pv ); /* first digest AAD, then */
- MAC( pntxt, ptextLen, H, &dotGF128, pv ); /* ..plaintext, and then */
- MAC( buf, sizeof buf, H, &dotGF128, pv ); /* ..bit sizes into POLYVAL */
+ xMac( aData, aDataLen, H, &dotGF128, pv ); /* first digest AAD, then */
+ xMac( pntxt, ptextLen, H, &dotGF128, pv ); /* ..plaintext, and then */
+ xMac( len, sizeof len, H, &dotGF128, pv ); /* ..bit sizes into POLYVAL */
}
/** derive the pair of authentication-encryption-keys from main key and nonce */
-static void DeriveGSKeys( const uint8_t* key, const uint8_t* nonce, block_t AK )
+static void GCMSIV_Init( const uint8_t* key, const uint8_t* nonce, block_t AK )
{
- uint8_t AEKeypair[KEYSIZE + 24];
- uint8_t iv[BLOCKSIZE], *k = AEKeypair;
+ uint8_t iv[10 * Nb + KEYSIZE], *h, *k;
+ k = h = iv + BLOCKSIZE;
memcpy( iv + 4, nonce, 12 );
AES_SetKey( key );
- for (*(int32_t*) iv = 0; *iv < KEYSIZE / 8 + 2; ++*iv)
+ for (*(int32_t*) iv = 0; *iv < 2 + Nk / 2; ++*iv)
{
rijndaelEncrypt( iv, k ); /* encrypt & take half, then */
k += 8; /* ..increment iv's LSB */
}
- AES_SetKey( AEKeypair + BLOCKSIZE ); /* set the main cipher-key */
- memcpy( AK, AEKeypair, BLOCKSIZE ); /* take authentication key */
+ AES_SetKey( k - KEYSIZE ); /* set the main cipher-key */
+ memcpy( AK, h, BLOCKSIZE ); /* take authentication key */
}
/**
@@ -1482,13 +1459,13 @@ void GCM_SIV_encrypt( const uint8_t* key, const uint8_t* nonce,
uint8_t* crtxt, block_t auTag )
{
block_t H, S = { 0 };
- DeriveGSKeys( key, nonce, H ); /* get authentication subkey */
+ GCMSIV_Init( key, nonce, H ); /* get authentication subkey */
Polyval( H, aData, pntxt, aDataLen, ptextLen, S );
- for (*H = 0; *H < 12; ++*H)
- { /* using H[0] as counter! */
- S[*H] ^= nonce[*H]; /* xor nonce with POLYVAL */
- }
+ XOR32BITS( nonce[0], S[0] );
+ XOR32BITS( nonce[4], S[4] );
+ XOR32BITS( nonce[8], S[8] ); /* xor POLYVAL with nonce */
+
S[LAST] &= 0x7F; /* clear one bit & encrypt, */
rijndaelEncrypt( S, S ); /* ..to get auth. tag */
memcpy( auTag, S, sizeof S );
@@ -1518,20 +1495,19 @@ char GCM_SIV_decrypt( const uint8_t* key, const uint8_t* nonce,
block_t H, S;
if (tagLen != sizeof S) return DECRYPTION_FAILURE;
- DeriveGSKeys( key, nonce, H ); /* get authentication subkey */
- memcpy( S, crtxt + crtxtLen, sizeof S ); /* tag is IV for CTR cipher */
- S[LAST] |= 0x80;
+ GCMSIV_Init( key, nonce, H ); /* get authentication subkey */
+ memcpy( S, crtxt + crtxtLen, tagLen );
+ S[LAST] |= 0x80; /* tag is IV for CTR cipher */
CTR_Cipher( S, 0, crtxt, crtxtLen, pntxt );
memset( S, 0, sizeof S );
Polyval( H, aData, pntxt, aDataLen, crtxtLen, S );
- for (*H = 0; *H < 12; ++*H)
- { /* using H[0] as counter! */
- S[*H] ^= nonce[*H]; /* xor nonce with POLYVAL */
- }
+ XOR32BITS( nonce[0], S[0] );
+ XOR32BITS( nonce[4], S[4] );
+ XOR32BITS( nonce[8], S[8] ); /* xor POLYVAL with nonce */
+
S[LAST] &= 0x7F; /* clear one bit & encrypt, */
rijndaelEncrypt( S, S ); /* ..to get tag & verify it */
-
BURN( RoundKey );
if (MISMATCH( S, crtxt + crtxtLen, sizeof S ))
{ /* tag verification failed */
@@ -1548,33 +1524,33 @@ char GCM_SIV_decrypt( const uint8_t* key, const uint8_t* nonce,
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(EAX)
-/** this function calculates the OMAC hash of a data array using D (K1) and Q */
+/** 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,
const void* data, const size_t dataSize, block_t mac )
{
- block_t M = { 0 };
+ int nodata = (!EAXP || t) && !dataSize;
#if EAXP
- memcpy( mac, t ? (dataSize ? Q : M) : D, sizeof M );
- if (dataSize || !t) /* ignore null ciphertext */
+ const uint8_t* K = t ? Q : D; /* ↓ ignore null ciphertext */
+
+ nodata ? memset( mac, 0, BLOCKSIZE ) : memcpy( mac, K, BLOCKSIZE );
#else
- if (dataSize == 0)
- {
- memcpy( M, D, sizeof M ); /* OMAC = Enc( D ^ [t]_n ) */
- }
- M[LAST] ^= t; /* else: C1 = Enc( [t]_n ) */
- rijndaelEncrypt( M, mac );
+ nodata ? memcpy( mac, D, BLOCKSIZE ) : memset( mac, 0, BLOCKSIZE );
+ mac[LAST] ^= t;
+ rijndaelEncrypt( mac, mac );
#endif
+ if (nodata) return; /* OMAC = CMAC( [t]_n ) */
+
cMac( D, Q, data, dataSize, mac );
}
/**
* @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 if not EAX'
+ * @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 nonceLen size of the nonce byte array; should be non-zero in EAX'
- * @param aData additional authentication data
+ * @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
@@ -1583,26 +1559,26 @@ void AES_EAX_encrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t* pntxt, const size_t ptextLen,
#if EAXP
const size_t nonceLen, uint8_t* crtxt )
-#define fDouble doubleGF128L
+#define F_DOUBLE doubleLGF128
#else
const uint8_t* aData, const size_t aDataLen,
- uint8_t* crtxt, uint8_t* auTag )
-#define fDouble doubleGF128B
+ uint8_t* crtxt, block_t auTag )
+#define F_DOUBLE doubleBGF128
#define nonceLen EAX_NONCE_LEN
#endif
{
block_t D = { 0 }, Q, mac;
- getSubkeys( key, &fDouble, D, Q );
+ getSubkeys( &F_DOUBLE, 1, key, D, Q );
OMac( 0, D, Q, nonce, nonceLen, mac ); /* N = OMAC(0; nonce) */
#if EAXP
- *(int32_t*) &crtxt[ptextLen] = *(int32_t*) &mac[12];
+ COPY32BIT( mac[12], crtxt[ptextLen] );
mac[12] &= 0x7F;
mac[14] &= 0x7F; /* clear 2 bits to get N' */
CTR_Cipher( mac, 1, pntxt, ptextLen, crtxt );
- OMac( 2, D, Q, crtxt, ptextLen, mac ); /* C' = CMAC'( ciphertext ) */
- *(int32_t*) &crtxt[ptextLen] ^= *(int32_t*) &mac[12];
+ OMac( 2, D, Q, crtxt, ptextLen, mac ); /* C' = CMAC'( ciphertext ) */
+ XOR32BITS( mac[12], crtxt[ptextLen] ); /* tag (i.e mac) = N ^ C' */
#else
OMac( 1, D, Q, aData, aDataLen, auTag ); /* H = OMAC(1; adata) */
xorBlock( mac, auTag );
@@ -1617,11 +1593,11 @@ 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 if not EAX'
+ * @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 nonceLen size of the nonce byte array; should be non-zero in EAX'
- * @param aData additional authentication data; ignored 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 pntxt resulting plaintext buffer
@@ -1638,16 +1614,16 @@ char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
uint8_t* pntxt )
{
block_t D = { 0 }, Q, mac, tag;
- getSubkeys( key, &fDouble, D, Q );
+ getSubkeys( &F_DOUBLE, 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 ) */
- *(int32_t*) &tag[12] ^= *(int32_t*) &mac[12];
- *(int32_t*) &tag[12] ^= *(int32_t*) &crtxt[crtxtLen];
+ XOR32BITS( crtxt[crtxtLen], tag[12] );
+ XOR32BITS( mac[12], tag[12] );
+ mac[12] &= 0x7F;
+ mac[14] &= 0x7F; /* clear 2 bits to get N' */
- mac[12] &= 0x7F; /* clear 2 bits to get N' */
- mac[14] &= 0x7F;
if (0 != *(int32_t*) &tag[12]) /* result of mac validation */
#else
OMac( 1, D, Q, aData, aDataLen, mac ); /* H = OMAC(1; adata) */
@@ -1670,132 +1646,109 @@ char AES_EAX_decrypt( const uint8_t* key, const uint8_t* nonce,
/*----------------------------------------------------------------------------*\
- OCB-AES (offset codebook mode): auxiliary functions
+ OCB-AES (offset codebook mode): how to parallelize the algorithm
+ by independent calculation of the offset values
+ + auxiliary functions along with the main API
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(OCB)
-/** Get the offset block (Δ_i) which is initialized by Δ_0, at the specified
- * index for a given L$. This method has minimum memory usage, but it is slow */
-static void OffsetB( const block_t Ld, const count_t index, block_t delta )
+static block_t OCBsubkeys[4]; /* [L_$] [L_*] [Ktop] [Δ_n] */
+
+/** Calculate the offset block (Δ_i) at a specified index, given the initial Δ_0
+ * and L$ blocks. This method has minimum memory usage, but it's clearly slow */
+static void getDelta( const count_t index, block_t delta )
{
size_t m, b = 1;
block_t L;
- memcpy( L, Ld, sizeof L ); /* initialize L_$ */
+ memcpy( L, *OCBsubkeys, sizeof L ); /* initialize L_$ */
while (b <= index && b) /* we can pre-calculate all */
- { /* ..L_{i}s to boost speed */
+ { /* .. L_{i}s to boost speed */
m = (4 * b - 1) & (index - b);
b <<= 1; /* L_0 = double( L_$ ) */
- doubleGF128B( L ); /* L_i = double( L_{i-1} ) */
- if (b > m) xorBlock( L, delta ); /* Δ_new = Δ ^ L_i */
+ doubleBGF128( L ); /* L_i = double( L_{i-1} ) */
+ if (b > m) xorBlock( L, delta ); /* Δ_i = Δ_{i-1} ^ L_ntz(i) */
}
}
-/**
- * @brief encrypt or decrypt a data unit using OCB-AES method
- * @param nonce a.k.a init-vector with a fixed size of 12 bytes
- * @param cipher block-cipher function: rijndaelEncrypt or rijndaelDecrypt
- * @param input input plain/cipher-text buffer
- * @param dataSize size of data
- * @param Ls L_* is the result of the encryption of a zero block
- * @param Ld L_$ = double(L_*) in GF(2^128)
- * @param Del Δ_m a.k.a last offset (sometimes Δ*, which is Δ_m ^ L_*)
- * @param output encrypted/decrypted data storage
- */
-static void OCB_Cipher( const uint8_t* nonce, fmix_t cipher,
- const void* input, const size_t dataSize,
- block_t Ls, block_t Ld, block_t Del, void* output )
+/** encrypt or decrypt the input data with OCB method. cipher function is either
+ * rijndaelEncrypt or rijndaelDecrypt, and nonce size must be = OCB_NONCE_LEN */
+static void OCB_Cipher( fmix_t cipher, const uint8_t* nonce,
+ const size_t dataSize, void* data )
{
- uint8_t kt[2 * BLOCKSIZE] = { OCB_TAG_LEN << 4 & 0xFF };
- count_t i, n = nonce[OCB_NONCE_LEN - 1] & 0x3F;
- uint8_t *y = output, r = n % 8;
-
- memcpy( output, input, dataSize ); /* copy input data to output */
+ uint8_t *Ls = OCBsubkeys[1], *kt = OCBsubkeys[2], *del = OCBsubkeys[3];
+ count_t i = 0, n = nonce[OCB_NONCE_LEN - 1] % 64;
+ uint8_t *y = data, r = n % 8; /* n = last 6 bits of nonce */
memcpy( kt + BLOCKSIZE - OCB_NONCE_LEN, nonce, OCB_NONCE_LEN );
+ kt[0] = OCB_TAG_LEN << 4 & 0xFF;
kt[LAST - OCB_NONCE_LEN] |= 1;
- kt[LAST] &= 0xC0; /* clear last 6 bits */
- n /= 8; /* copy last 6 bits to (n,r) */
+ kt[LAST] &= 0xC0; /* clear last 6 bits */
- rijndaelEncrypt( kt, kt ); /* construct K_top */
- memcpy( kt + BLOCKSIZE, kt + 1, 8 ); /* stretch K_top */
- xorBlock( kt, kt + BLOCKSIZE );
- for (i = 0; i < BLOCKSIZE; ++n) /* shift the stretched K_top */
+ rijndaelEncrypt( kt, kt ); /* construct K_top */
+ memcpy( del, kt + 1, 8 ); /* stretch K_top */
+ xorBlock( kt, del );
+
+ for (n /= 8; i < BLOCKSIZE; ++n) /* shift the stretched K_top */
{
kt[i++] = kt[n] << r | kt[n + 1] >> (8 - r);
}
- n = dataSize / BLOCKSIZE;
- r = dataSize % BLOCKSIZE;
+ if ((n = dataSize / BLOCKSIZE) == 0)
+ {
+ memcpy( del, kt, BLOCKSIZE ); /* initialize Δ_0 */
+ }
- rijndaelEncrypt( Ls, Ls ); /* L_* = Enc(zero block) */
- memcpy( Ld, Ls, BLOCKSIZE );
- doubleGF128B( Ld ); /* L_$ = double(L_*) */
- if (n == 0) /* processed nonce is Δ_0 */
+ for (i = 0; i++ < n; y += BLOCKSIZE)
{
- memcpy( Del, kt, BLOCKSIZE ); /* initialize Δ_0 */
+ memcpy( del, kt, BLOCKSIZE );
+ getDelta( i, del ); /* calculate Δ_i using my */
+ xorBlock( del, y ); /* .. 'magic' algorithm */
+ cipher( y, y );
+ xorBlock( del, y ); /* Y = Δ_i ^ Cipher(Δ_i ^ X) */
}
- for (i = 0; i < n; y += BLOCKSIZE)
- {
- memcpy( Del, kt, BLOCKSIZE ); /* calculate Δ_i using my */
- OffsetB( Ld, ++i, Del ); /* .. 'magic' algorithm */
- xorBlock( Del, y );
- cipher( y, y ); /* Y = Δ_i ^ Cipher(Δ_i ^ X) */
- xorBlock( Del, y );
- }
- if (r) /* Δ_* = Δ_n ^ L_* and then */
- { /* Y_* = Enc(Δ_*) ^ X */
- xorBlock( Ls, Del );
- mixThenXor( Del, &rijndaelEncrypt, kt, y, r, y );
- Del[r] ^= 0x80; /* pad it for checksum */
+ if ((r = dataSize % BLOCKSIZE) != 0)
+ { /* Y_* = Enc(L_* ^ Δ_n) ^ X */
+ xorBlock( Ls, del );
+ mixThenXor( &rijndaelEncrypt, del, kt, y, r, y );
+ del[r] ^= 0x80; /* pad Δ_* (i.e. tag) */
}
}
static void nop( const block_t x, block_t y ) {}
-/** derives OCB authentication tag. the first three arguments are pre-calculated
- * namely, Δ_* (or sometimes Δ_m), L_* = encrypt(zeros) and L_$ = double(L_*) */
-static void OCB_GetTag( const block_t Ds,
- const block_t Ls, const block_t Ld,
- const void* pntxt, const void* aData,
- const size_t ptextLen, const size_t aDataLen,
- block_t tag )
+/** calculate tag and save to Δ_*, using plaintext checksum and PMAC of aData */
+static void OCB_GetTag( const void* pntxt, const void* aData,
+ const size_t ptextLen, const size_t aDataLen )
{
- uint8_t const r = aDataLen % BLOCKSIZE, *x = aData;
- count_t i, n = aDataLen / BLOCKSIZE;
- block_t S = { 0 }; /* checksum, i.e. */
- MAC( pntxt, ptextLen, NULL, &nop, S ); /* ..xor of all plaintext */
+ block_t T = { 0 };
+ count_t n = aDataLen / BLOCKSIZE;
+ uint8_t r = aDataLen % BLOCKSIZE, *tag = OCBsubkeys[3];
+ uint8_t const *Ld = OCBsubkeys[0], *Ls = OCBsubkeys[1];
+ uint8_t const *xa = (uint8_t const *) aData + aDataLen - r;
- xorBlock( Ds, S );
- xorBlock( Ld, S );
- rijndaelEncrypt( S, tag ); /* Tag0 = Enc(L_$ ^ Δ_* ^ S) */
- if (aDataLen == 0) return;
+ xMac( pntxt, ptextLen, NULL, &nop, tag ); /* get plaintext checksum */
+ xorBlock( Ld, tag ); /* S = Δ_* ^ checksum ^ L_$ */
+ rijndaelEncrypt( tag, tag ); /* tag_0 = Enc( S ) */
- memset( S, 0, sizeof S ); /* PMAC authentication: */
- for (i = 0; i < n; x += BLOCKSIZE)
+ if (r) /* PMAC authentication: */
{
- OffsetB( Ld, ++i, S );
- xorBlock( x, S );
- rijndaelEncrypt( S, S ); /* S_i = Enc(A_i ^ Δ_i) */
- xorBlock( S, tag ); /* Tag_{i+1} = Tag_i ^ S_i */
- memset( S, 0, sizeof S );
+ getDelta( n, T );
+ cMac( NULL, Ls, xa, r, T ); /* T = Enc(A_* ^ L_* ^ Δ_n) */
+ xorBlock( T, tag ); /* add it to tag */
}
- if (r)
+ while (n)
{
- OffsetB( Ld, n, S ); /* S = calculated Δ_n */
- S[r] ^= 0x80; /* A_* = A || 1 (padded) */
- xorThenMix( x, r, Ls, &xorBlock, S ); /* S_* = A_* ^ L_* ^ Δ_n */
- rijndaelEncrypt( S, S );
- xorBlock( S, tag ); /* Tag = Enc(S_*) ^ Tag_n */
+ memcpy( T, xa -= sizeof T, sizeof T ); /* initialize Δ */
+ getDelta( n--, T );
+ rijndaelEncrypt( T, T ); /* T_i = Enc(A_i ^ Δ_i) */
+ xorBlock( T, tag ); /* add T_i to tag */
}
}
-/*----------------------------------------------------------------------------*\
- OCB-AES (offset codebook mode): main functions
-\*----------------------------------------------------------------------------*/
/**
* @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 init-vector with a fixed size of 12 bytes
+ * @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
@@ -1808,17 +1761,22 @@ void AES_OCB_encrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t* aData, const size_t aDataLen,
uint8_t* crtxt, block_t auTag )
{
- block_t Ls = { 0 }, Ld, delta;
- AES_SetKey( key );
- OCB_Cipher( nonce, &rijndaelEncrypt, pntxt, ptextLen, Ls, Ld, delta, crtxt );
- OCB_GetTag( delta, Ls, Ld, pntxt, aData, ptextLen, aDataLen, auTag );
+ uint8_t *Ld = OCBsubkeys[0], *Ls = OCBsubkeys[1], *tag = OCBsubkeys[3];
+
+ memcpy( crtxt, pntxt, ptextLen); /* doing in-place encryption */
+ memset( Ls, 0, 2 * BLOCKSIZE );
+ getSubkeys( &doubleBGF128, 0, key, Ls, Ld );
+ OCB_Cipher( &rijndaelEncrypt, nonce, ptextLen, crtxt );
+ OCB_GetTag( pntxt, aData, ptextLen, aDataLen );
+
+ memcpy( auTag, tag, OCB_TAG_LEN );
BURN( RoundKey );
}
/**
* @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 init-vector with a fixed size of 12 bytes
+ * @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
@@ -1832,17 +1790,21 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
const uint8_t* aData, const size_t aDataLen,
const uint8_t tagLen, uint8_t* pntxt )
{
- block_t Ls = { 0 }, Ld, delta;
+ uint8_t *Ld = OCBsubkeys[0], *Ls = OCBsubkeys[1], *tag = OCBsubkeys[3];
+
if (tagLen && tagLen != OCB_TAG_LEN) return DECRYPTION_FAILURE;
- AES_SetKey( key );
- OCB_Cipher( nonce, &rijndaelDecrypt, crtxt, crtxtLen, Ls, Ld, delta, pntxt );
- OCB_GetTag( delta, Ls, Ld, pntxt, aData, crtxtLen, aDataLen, delta );
- BURN( RoundKey ); /* tag was saved into delta */
+ memcpy( pntxt, crtxt, crtxtLen); /* in-place decryption */
+ memset( Ls, 0, 2 * BLOCKSIZE );
+ getSubkeys( &doubleBGF128, 0, key, Ls, Ld );
+ OCB_Cipher( &rijndaelDecrypt, nonce, crtxtLen, pntxt );
+ OCB_GetTag( pntxt, aData, crtxtLen, aDataLen );
- if (MISMATCH( delta, crtxt + crtxtLen, tagLen ))
+ BURN( RoundKey );
+ if (MISMATCH( tag, crtxt + crtxtLen, tagLen ))
{
SABOTAGE( pntxt, crtxtLen );
+ BURN( OCBsubkeys );
return AUTHENTICATION_FAILURE;
}
return ENDED_IN_SUCCESS;
@@ -1854,41 +1816,38 @@ char AES_OCB_decrypt( const uint8_t* key, const uint8_t* nonce,
KW-AES: Main functions for AES key-wrapping (RFC-3394)
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(KWA)
-#define Hb (BLOCKSIZE / 2) /* size of half-blocks */
+#define HB (BLOCKSIZE / 2) /* size of half-blocks */
/**
* @brief wrap the input secret whose size is a multiple of 8 and >= 16
* @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 wrapped wrapped secret. note: size of output = secretLen + Hb
- * @return error if # of half-blocks is less than 2 or needs padding
+ * @param secretLen size of input, must be a multiple of HB (half-block size)
+ * @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 uint8_t* secret, const size_t secretLen, uint8_t* wrapped )
{
- uint8_t A[BLOCKSIZE], *r, i;
- count_t n = secretLen / Hb, j; /* number of semi-blocks */
- if (n < 2 || secretLen % Hb) return ENCRYPTION_FAILURE;
+ size_t q, i = 0, n = secretLen / HB; /* number of semi-blocks */
+ block_t A;
- memset( A, 0xA6, Hb ); /* initialization vector */
- memcpy( wrapped + Hb, secret, secretLen ); /* copy input to the output */
+ if (n < 2 || secretLen % HB) return ENCRYPTION_FAILURE;
+
+ memset( A, 0xA6, HB ); /* initialization vector */
+ memcpy( wrapped + HB, secret, secretLen ); /* copy input to the output */
AES_SetKey( kek );
- for (i = 0; i < 6; ++i)
+ for (q = 6 * n; i < q; )
{
- r = wrapped;
- for (j = 0; j++ < n; )
- {
- r += Hb;
- memcpy( A + Hb, r, Hb ); /* B = Enc(A | R[j]) */
- rijndaelEncrypt( A, A ); /* R[j] = LSB(64, B) */
- memcpy( r, A + Hb, Hb ); /* A = MSB(64, B) ^ t */
- xorWith( A, Hb - 1, n * i + j );
- }
+ uint8_t *r = wrapped + (i++ % n + 1) * HB;
+ memcpy( A + HB, r, HB );
+ rijndaelEncrypt( A, A ); /* A = Enc( V | R_{k-1} ) */
+ memcpy( r, A + HB, HB ); /* R_{k} = LSB(64, A) */
+ xorBENum( A, i, HB - 1 ); /* V = MSB(64, A) ^ i */
}
- memcpy( wrapped, A, Hb );
-
BURN( RoundKey );
+
+ memcpy( wrapped, A, HB );
return ENDED_IN_SUCCESS;
}
@@ -1897,36 +1856,34 @@ char AES_KEY_wrap( const uint8_t* kek,
* @param kek key-encryption-key a.k.a master key
* @param wrapped cipher-text input, i.e. wrapped secret.
* @param wrapLen size of ciphertext/wrapped input in bytes
- * @param secret unwrapped secret whose size = wrapLen - Hb
+ * @param secret unwrapped secret whose size = wrapLen - HB
* @return a value indicating whether decryption was successful
*/
char AES_KEY_unwrap( const uint8_t* kek,
const uint8_t* wrapped, const size_t wrapLen, uint8_t* secret )
{
- uint8_t A[BLOCKSIZE], *r, i;
- count_t n = wrapLen / Hb - 1, j; /* number of semi-blocks */
- if (n < 2 || wrapLen % Hb) return DECRYPTION_FAILURE;
+ size_t i, n = wrapLen / HB; /* number of semi-blocks */
+ block_t A;
- memcpy( A, wrapped, Hb ); /* authentication vector */
- memcpy( secret, wrapped + Hb, wrapLen - Hb );
+ if (n-- < 3 || wrapLen % HB) return DECRYPTION_FAILURE;
+
+ memcpy( A, wrapped, HB ); /* authentication vector */
+ memcpy( secret, wrapped + HB, wrapLen - HB );
AES_SetKey( kek );
- for (i = 6; i--; )
+ for (i = 6 * n; i; --i)
{
- r = secret + n * Hb;
- for (j = n; j; --j)
- {
- r -= Hb;
- xorWith( A, Hb - 1, n * i + j );
- memcpy( A + Hb, r, Hb ); /* B = Dec(A ^ t | R[j]) */
- rijndaelDecrypt( A, A ); /* A = MSB(64, B) */
- memcpy( r, A + Hb, Hb ); /* R[j] = LSB(64, B) */
- }
+ uint8_t *r = secret + ((i - 1) % n) * HB;
+ xorBENum( A, i, HB - 1 );
+ memcpy( A + HB, r, HB ); /* V = MSB(64, A) ^ i */
+ rijndaelDecrypt( A, A ); /* A = Dec( V | R_{k} ) */
+ memcpy( r, A + HB, HB ); /* R_{k-1} = LSB(64, A) */
}
- while (++i != Hb) j |= A[i] ^ 0xA6; /* authenticate/error check */
-
BURN( RoundKey );
- return j ? AUTHENTICATION_FAILURE : ENDED_IN_SUCCESS;
+
+ for (n = 0; i < HB; ) n |= A[i++] ^ 0xA6; /* authenticate/error check */
+
+ return n ? AUTHENTICATION_FAILURE : ENDED_IN_SUCCESS;
}
#endif /* KWA */
@@ -1935,77 +1892,71 @@ char AES_KEY_unwrap( const uint8_t* kek,
Poly1305-AES message authentication: auxiliary functions and main API
\*----------------------------------------------------------------------------*/
#if IMPLEMENT(POLY1305)
-#define Sp (BLOCKSIZE + 1) /* size of poly1305 blocks */
+#define SP 17 /* size of poly1305 blocks */
/** derive modulo(2^130-5) for a little endian block, by repeated subtraction */
-static void modLPoly( uint8_t* block, const uint8_t ovrfl )
+static void modP1305( uint8_t* block, const int ovrfl )
{
- int i = BLOCKSIZE, n = 0x40 * ovrfl + block[Sp - 1] / 4;
- int32_t q = n - (block[Sp - 1] < 3);
- while (q == 0 && --i) /* n = B / (2 ^ 130) */
- { /* compare block to 2^130-5 */
- q -= 0xFF - block[i]; /* proceed if B >= (2^130-5) */
- }
- n += (i == 0 && block[0] >= 0xFB);
+ uint8_t* msb = block + SP - 1;
+ int32_t q = ovrfl << 6 | *msb >> 2; /* q = B / (2 ^ 130) */
- for ( ; n != 0; n = block[Sp - 1] > 3) /* mod = B - n * (2^130-5) */
- {
- for (q = 5 * n, i = 0; q && i < Sp; q >>= 8)
- {
- q += block[i]; /* to get mod, first derive */
- block[i++] = (uint8_t) q; /* .. B + (5 * n) and then */
- } /* .. subtract n * (2^130) */
- block[Sp - 1] -= 4 * (uint8_t) n;
+ if (!q) return;
+
+ *msb -= 4 * (uint8_t) q; /* first, subtract q * 2^130 */
+ for (q *= 5; q; q >>= 8) /* since most of the times: */
+ { /* mod = B - q * (2^130-5) */
+ q += *block; /* then add (q * 5) */
+ *block++ = (uint8_t) q;
}
}
/** add two little-endian poly1305 blocks. use modular addition if necessary. */
static void addLBlocks( const uint8_t* x, const uint8_t len, uint8_t* y )
{
- int s = 0, i;
- for (i = 0; i < len; s >>= 8)
+ int a, i;
+ for (i = a = 0; i < len; a >>= 8)
{
- s += x[i] + y[i];
- y[i++] = (uint8_t) s; /* s >> 8 is the overflow */
+ a += x[i] + y[i];
+ y[i++] = (uint8_t) a; /* a >> 8 is overflow/carry */
}
- if (len == Sp) modLPoly( y, (uint8_t) s );
+ if (i == SP) modP1305( y, a );
}
-/** modular multiplication of a block by 2^s, i.e. left shift block to s bits */
-static void shiftLBlock( uint8_t* block, const uint8_t shl )
-{
- unsigned i, t = 0;
- for (i = 0; i < Sp; t >>= 8) /* similar to doubleGF128L */
- {
- t |= block[i] << shl; /* shl may vary from 1 to 8 */
- block[i++] = (uint8_t) t;
- }
- modLPoly( block, (uint8_t) t );
-}
-
-/** modular multiplication of two little-endian poly1305 blocks. y *= x mod P */
+/** modular multiplication of two little-endian poly1305 blocks: y *= x mod P */
static void mulLBlocks( const uint8_t* x, uint8_t* y )
{
- uint8_t i, b, t, nz, result[Sp] = { 0 };
-
- for (i = 0; i < Sp; ++i)
- {
- for (t = x[i], b = 1; b != 0; ) /* check every bit of x[i] */
- { /* ..and if any bit was set */
- if (t & b) /* ..add y to the result. */
- { /* then, calculate the */
- addLBlocks( y, Sp, result ); /* ..distance to the next */
- t ^= b; /* ..set bit, i.e. nz */
- }
- for (nz = 0; !(t & b) && b; ++nz) b <<= 1;
- shiftLBlock( y, nz );
+ uint8_t i, sh, n = SP, prod[SP] = { 0 }; /* Y = [Y_0][Y_1]...[Y_n] */
+ int32_t m;
+ while (n--) /* multiply X by MSB of Y */
+ { /* ..and add to the result */
+ sh = n ? 8 : 0; /* ..shift the result if Y */
+ for (m = i = 0; i < SP; m >>= 8) /* ..has other byte in queue */
+ { /* ..but don't shift for Y_0 */
+ m += (prod[i] + x[i] * y[n]) << sh;
+ prod[i++] = (uint8_t) m;
}
+ modP1305( prod, m ); /* modular multiplication */
+ }
+ memcpy( y, prod, SP );
+}
+
+/** handle some special/rare cases that might be missed by modP1305 function. */
+static void cmpToP1305( uint8_t* block )
+{
+ int c = block[SP - 1] == 3 && *block >= 0xFB ? SP - 1 : block[SP - 1] / 4;
+ while (c > 1)
+ {
+ if (block[--c] < 0xFF) return; /* compare block to 2^130-5, */
+ }
+ for (c *= 5; c; c >>= 8)
+ { /* and if (block >= 2^130-5) */
+ c += *block; /* .. add it with 5 */
+ *block++ = (uint8_t) c;
}
- memcpy( y, result, sizeof result ); /* result is saved into y */
}
/**
- * @brief derive the Poly1305-AES hash of message using a nonce and key pair.
+ * @brief derive the Poly1305-AES mac of message using a nonce and key pair.
* @param keys pair of encryption/mixing keys (k, r); size = KEYSIZE + 16
* @param nonce a 128 bit string which is encrypted by AES_k
* @param data buffer of input data
@@ -2015,32 +1966,33 @@ 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], poly[Sp] = { 0 }, c[Sp] = { 0 }, rn[Sp] = { 1 };
- uint8_t i = (dataSize > 0);
- uint8_t m = (dataSize - i) % BLOCKSIZE + i;
- count_t q = (dataSize - i) / BLOCKSIZE + i;
- uint8_t const* x = (uint8_t const*) data;
-
- memcpy( r, keys + KEYSIZE, BLOCKSIZE ); /* extract r from (k,r) pair */
- for (i = 3; i < BLOCKSIZE; ++i)
- {
- if (i % 4 == 0) r[i] &= 0xFC; /* clear bottom 2 bits */
- if (i % 4 == 3) r[i] &= 0x0F; /* clear top 4 bits */
- }
- r[i] = 0;
- while (q--)
- {
- memcpy( c, x + q * BLOCKSIZE, m ); /* copy message to chunk */
- c[m] = 1; /* append 1 to each chunk */
- mulLBlocks( r, rn ); /* r^n = r^{n-1} * r */
- mulLBlocks( rn, c ); /* calculate c_{q-n} * r^n */
- addLBlocks( c, sizeof c, poly ); /* add to poly (mod 2^130-5) */
- m = BLOCKSIZE;
- }
+ uint8_t r[SP], rk[SP] = { 1 }, c[SP] = { 0 }, poly[SP] = { 0 }, s = SP - 1;
+ count_t q = (dataSize - 1) / BLOCKSIZE;
+ const char* pos = (const char*) data + dataSize;
AES_SetKey( keys );
rijndaelEncrypt( nonce, mac ); /* derive AES_k(nonce) */
BURN( RoundKey );
+
+ if (!dataSize) return;
+
+ memcpy( r, keys + KEYSIZE, s ); /* extract r from (k,r) pair */
+ for (r[s] = 0; s > 0; s -= 3)
+ {
+ r[s--] &= 0xFC; /* clear bottom 2 bits */
+ r[s ] &= 0x0F; /* clear top 4 bits */
+ }
+ s = dataSize - BLOCKSIZE * q++; /* size of last chunk */
+
+ for (pos -= s; q--; pos -= (s = BLOCKSIZE))
+ {
+ memcpy( c, pos, s ); /* copy message to chunk */
+ c[s] = 1; /* append 1 to each chunk */
+ mulLBlocks( r, rk ); /* r^k = r^{k-1} * r */
+ mulLBlocks( rk, c ); /* calculate c_{q-k} * r^k */
+ addLBlocks( c, sizeof c, poly ); /* add to poly (mod 2^130-5) */
+ }
+ cmpToP1305( poly );
addLBlocks( poly, BLOCKSIZE, mac ); /* mac = poly + AES_k(nonce) */
}
#endif /* POLY1305 */
@@ -2056,197 +2008,285 @@ void AES_Poly1305( const uint8_t* keys, const block_t nonce,
#else
#define ALPHABET "0123456789"
#define string_t char* /* string pointer type */
-#define RADIX 10 /* strlen( ALPHABET ) */
-#define LOGRDX 3.321928095 /* log2( RADIX ) */
-#define MINLEN 6 /* ceil(6 / log10( RADIX )) */
+#define RADIX 10 /* strlen (ALPHABET) */
+#define LOGRDX 3.321928095 /* log2 (RADIX) */
+#define MINLEN 6 /* ceil (6 / log10 (RADIX)) */
+#define MAXLEN 0x38 /* only if FF_X == 3 */
#endif
-#if RADIX <= 0xFF
-typedef uint8_t rbase_t; /* num type in base-radix */
+#if (RADIX - 1 > 0xFF)
+typedef unsigned short rbase_t; /* digit type in base-radix */
#else
-typedef unsigned short rbase_t;
+typedef uint8_t rbase_t;
#endif
-/** append a digit d in base-RADIX to a big-endian number, denoted by num */
-static void addRxdigit( uint8_t* num, size_t N, size_t d )
-{
- while (N--)
- {
- d += num[N] * RADIX;
- num[N] = (uint8_t) d; /* num = num * RADIX + d */
- d >>= 8;
- }
-}
+#if FF_X != 3 /* FF1 method: */
-/** convert a string in base-RADIX to a big-endian number, denoted by num */
+static size_t bb; /* the b constant in FF1 */
+
+/** 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 )
{
- size_t i;
memset( num, 0, bytes );
- for (i = 0; i < len; ++i) addRxdigit( num, bytes, s[i] );
-}
-
-/** append a byte to a big-endian number, represented as a base-RADIX string. */
-static void appendByte( rbase_t* str, size_t N, size_t b )
-{
- while (N--)
+ while (len--)
{
- b += str[N] << 8;
- str[N] = b % RADIX; /* num = num << 8 + b */
- b /= RADIX;
+ size_t i, y = *s++;
+ for (i = bytes; i; y >>= 8)
+ {
+ y += num[--i] * RADIX; /* num = num * RADIX + y */
+ num[i] = (uint8_t) y;
+ }
}
}
-/** convert a big-endian number to its base-RADIX representation string: s */
+/** 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 )
{
- size_t i;
memset( s, 0, sizeof (rbase_t) * len );
- for (i = 0; i < bytes; ++i) appendByte( s, len, num[i] );
+ while (bytes--)
+ {
+ size_t i, x = *num++;
+ for (i = len; i; x /= RADIX)
+ {
+ x += s[--i] << 8; /* numstr = numstr << 8 + x */
+ s[i] = x % RADIX;
+ }
+ }
}
-/** add two numbers in base-RADIX represented by q and p, so that p = p + q */
-static void numstrAdd( const rbase_t* q, size_t N, rbase_t* p )
+/** add two numbers in base-RADIX represented by q and p, so that: p = p + q */
+static void rbase_add( const rbase_t* q, const size_t len, rbase_t* p )
{
- size_t a, c;
- for (c = 0; N--; c = a >= RADIX)
+ size_t i, a = 0;
+ for (i = len; i--; a /= RADIX) /* big-endian addition */
{
- a = p[N] + q[N] + c;
- p[N] = a % RADIX;
+ a += p[i] + q[i]; /* a /= RADIX is equivalent */
+ p[i] = a % RADIX; /* ..to a = (a >= RADIX) */
}
}
/** subtract two numbers in base-RADIX represented by q and p, so that p -= q */
-static void numstrSub( const rbase_t* q, size_t N, rbase_t* p )
+static void rbase_sub( const rbase_t* q, const size_t len, rbase_t* p )
{
- size_t s, c;
- for (c = 0; N--; c = s < RADIX)
+ size_t i, s = 1;
+ for (i = len; i--; s /= RADIX) /* big-endian subtraction */
{
- s = RADIX + p[N] - q[N] - c;
- p[N] = s % RADIX;
+ s += RADIX - 1 + p[i] - q[i];
+ p[i] = s % RADIX;
}
}
+/** derive C at step i of FF1 rounds, given string size len, u and PRF_init P */
+static void FF1round( const uint8_t i, const block_t P, const size_t u,
+ const size_t len, rbase_t* C )
+{
+ size_t k = bb % BLOCKSIZE, d = (bb + 7) & ~3UL, a = i & 1 ? len : len - u;
+ block_t R = { 0 };
+ uint8_t* num = (void*) (C + u); /* use pre-allocated memory */
+
+ R[LAST - k] = i;
+ numRadix( C - a, len - u, num, bb ); /* get NUM_radix(B) and */
+ memcpy( R + sizeof R - k, num, k ); /* ..then feed it into PRF: */
+
+ xMac( P, BLOCKSIZE, R, &rijndaelEncrypt, R );
+ xMac( num + k, bb - k, R, &rijndaelEncrypt, R );
+
+ memcpy( num, R, sizeof R ); /* R = PRF(P || Q) */
+ k = (d - 0x1) / sizeof R; /* total additional blocks */
+ for (num += k * sizeof R; k; --k)
+ {
+ memcpy( num, R, sizeof R );
+ xorBENum( num, k, LAST ); /* num = R || R ^ [k] ||... */
+ rijndaelEncrypt( num, num ); /* S = R || Enc(R ^ [k])... */
+ num -= sizeof R;
+ }
+ strRadix( num, d, 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 )
+{
+ size_t u = (len + !mode) / 2, t = tweakLen;
+ rbase_t* Xc = X + len;
+ block_t P = { 1, 2, 1, RADIX >> 16, RADIX >> 8 & 0xFF, RADIX & 0xFF, 10 };
+ uint8_t i = tweakLen % BLOCKSIZE;
+
+ if (i > (uint8_t) ~bb % BLOCKSIZE) i = 0;
+
+ P[7] = len / 2 & 0xFF; /* P = [1,2,1][radix][10]... */
+ xorBENum( P, len, 11 );
+ xorBENum( P, t, LAST );
+
+ AES_SetKey( key );
+ rijndaelEncrypt( P, P ); /* P -> PRF(P || tweak) */
+ xMac( tweak, t - i, P, &rijndaelEncrypt, P );
+ while (i)
+ {
+ P[--i] ^= tweak[--t];
+ }
+ for ( ; i < 10 * mode; u = len - u) /* Feistel procedure */
+ {
+ FF1round( i++, P, u, len, Xc ); /* encryption rounds */
+ rbase_add( Xc, u, i & 1 ? X : Xc - u );
+ }
+ for (i ^= 10; i > (0); u = len - u) /* A → X, C → Xc, B → Xc - u */
+ {
+ FF1round( --i, P, u, len, Xc ); /* decryption rounds */
+ rbase_sub( Xc, u, i & 1 ? Xc - u : X );
+ }
+}
+#else /* FF3/FF3-1 */
+
+/** 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 )
+{
+ memset( num, 0, bytes );
+ while (len--)
+ {
+ size_t i, d = s[len];
+ for (i = 0; i < bytes; d >>= 8)
+ {
+ d += num[i] * RADIX; /* num = num * RADIX + d */
+ num[i++] = (uint8_t) d;
+ }
+ }
+}
+
+/** 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 )
+{
+ memset( s, 0, sizeof (rbase_t) * len );
+ while (bytes--)
+ {
+ size_t i, b = num[bytes];
+ for (i = 0; i < len; b /= RADIX)
+ {
+ b += s[i] << 8; /* numstr = numstr << 8 + b */
+ s[i++] = b % RADIX;
+ }
+ }
+}
+
+/** add two numbers in base-RADIX represented by q and p, so that: p = p + q */
+static void rbase_add( const rbase_t* q, const uint8_t len, rbase_t* p )
+{
+ size_t i, a = 0;
+ for (i = 0; i < len; a /= RADIX) /* little-endian addition */
+ {
+ a += p[i] + q[i];
+ p[i++] = a % RADIX;
+ }
+}
+
+/** subtract two numbers in base-RADIX represented by q and p, so that p -= q */
+static void rbase_sub( const rbase_t* q, const uint8_t len, rbase_t* p )
+{
+ 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;
+ }
+}
+
+/** calculate C at step i of FF3 rounds, given the string size len, u, and T. */
+static void FF3round( const uint8_t i, const uint8_t* T, const uint8_t u,
+ const uint8_t len, rbase_t* C )
+{
+ uint8_t w = (i & 1) * 4, a = i & 1 ? len : len - u;
+ block_t P;
+ COPY32BIT( T[w], P[12] ); /* W = (i is odd) ? TR : TL */
+ P[12] ^= i;
+
+ numRadix( C - a, len - u, P, 12 ); /* get REV. NUM_radix( B ) */
+ rijndaelEncrypt( P, P );
+ strRadix( P, sizeof P, C, u ); /* C = REV. STR_m( c ) */
+}
+
+/** 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 )
+{
+ rbase_t* Xc = X + len;
+ uint8_t T[8], u = (len + mode) / 2, *k = (void*) Xc, i;
+
+ memcpy( k, tweak, FF3_TWEAK_LEN );
+#if FF3_TWEAK_LEN == 7 /* old version of FF3 had a */
+ k[7] = (uint8_t) (k[3] << 4); /* ..64-bit tweak. but FF3-1 */
+ k[3] &= 0xF0; /* ..tweaks must be 56-bit */
+#endif
+
+ for (i = 8; i --> 0; ) T[i] = k[7 - i];
+ for (i = KEYSIZE; i; ) k[--i] = *key++; /* key/tweak are reversed */
+
+ AES_SetKey( k );
+ SABOTAGE( k, KEYSIZE );
+
+ for ( ; i < 8 * mode; u = len - u) /* Feistel procedure */
+ {
+ FF3round( i++, T, u, len, Xc ); /* encryption rounds */
+ rbase_add( Xc, u, i & 1 ? X : Xc - u );
+ }
+ for (i ^= (8); i > 0; u = len - u) /* A → X, C → Xc, B → Xc - u */
+ {
+ FF3round( --i, T, u, len, Xc ); /* decryption rounds */
+ rbase_sub( Xc, u, i & 1 ? Xc - u : X );
+ }
+}
+#endif /* FF_X */
+
/*----------------------------------------------------------------------------*\
FPE-AES: main functions
\*----------------------------------------------------------------------------*/
#include
-#if FF_X == 3
-
-static void FF3round()
-{
-}
-
-static void FF3_Cipher()
-{
- memcpy( P, tweak, 4 );
- memcpy( P + 8, tweak + 4, 3 );
- P[11] = P[3] << 4 & 0xF0;
- P[3] &= 0xF0; /* P[0..3]=TL, P[8..11]=TR */
-}
-#else
-
-static size_t bf1, df1; /* b and d constants in FF1 */
-
-/** apply the FF1 round at step i to the input string X with length `len` */
-static void FF1round( const uint8_t i, const block_t P, const size_t u,
- const size_t len, rbase_t* X )
-{
- block_t R = { 0 };
- uint8_t *num = (void*) (X + (len + 1) / 2); /* use pre-allocated memory */
- size_t t = len - (~i & 1) * u;
-
- numRadix( X - t, len - u, num, bf1 ); /* get NUM_radix(B) */
- t = bf1 % BLOCKSIZE;
- R[LAST - t] = i;
- memcpy( R + BLOCKSIZE - t, num, t ); /* feed NUMradix(B) into PRF */
- MAC( P, BLOCKSIZE, R, &rijndaelEncrypt, R );
- MAC( num + t, bf1 - t, R, &rijndaelEncrypt, R );
-
- t = (df1 - 1) / BLOCKSIZE;
- memcpy( num, R, sizeof R ); /* R = PRF(P || Q) */
- for (num += t * BLOCKSIZE; t; num -= BLOCKSIZE)
- {
- memcpy( num, R, sizeof R ); /* num = R || R || R || ... */
- xorWith( num, LAST, t-- ); /* num = R || R ^ [i] ||... */
- rijndaelEncrypt( num, num ); /* S = R || Enc(R ^ [i])... */
- }
- strRadix( num, df1, X, 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 char mode, const uint8_t* key, const size_t len,
- const uint8_t* tweak, const size_t tweakLen, rbase_t* X )
-{
- block_t P = { 1, 2, 1 };
- uint8_t i = tweakLen % BLOCKSIZE, r = mode ? 0 : 10;
- size_t u = (len + 1 - mode) >> 1, t = tweakLen - i;
-
- X += len; /* go to end of the input */
- putValueB( P, 5, RADIX );
- putValueB( P, 7, (len / 2 & 0xFF) + 0xA00 );
- putValueB( P, 11, len );
- putValueB( P, 15, tweakLen ); /* P=[1][2][1][radix][10]... */
-
- AES_SetKey( key );
- rijndaelEncrypt( P, P );
- MAC( tweak, t, P, &rijndaelEncrypt, P ); /* P = PRF(P || tweak) */
- if (i < BLOCKSIZE - bf1 % BLOCKSIZE)
- {
- for (t = tweakLen; i; ) P[--i] ^= tweak[--t];
- }
- else /* zero pad and feed to PRF */
- {
- xorThenMix( &tweak[t], i, P, &rijndaelEncrypt, P );
- }
- for (i = r; i < 10; ++i, u = len - u)
- {
- FF1round( i, P, u, len, X ); /* encryption rounds */
- numstrAdd( X, u, X - (i & 1 ? u : len) );
- }
- for (i = r; i--; u = len - u)
- {
- FF1round( i, P, u, len, X ); /* decryption rounds */
- numstrSub( X, u, X - (i & 1 ? u : len) );
- }
-}
-#endif /* FF_X */
/** allocate the required memory and validate the input string in FPE mode... */
-static char FPEsetup( const string_t str, const size_t len, rbase_t** indices )
+static char FPEinit( const string_t str, const size_t len, rbase_t** indices )
{
- string_t alpha = ALPHABET;
+ const string_t alpha = ALPHABET;
size_t i = (len + 1) / 2;
- size_t j = (len + i) * sizeof (rbase_t);
+ size_t n = (len + i) * sizeof (rbase_t);
-#if FF_X != 3 /* extra memory is required */
- bf1 = (size_t) (LOGRDX * i + 8 - 1e-10) >> 3;
- df1 = (bf1 + 7) & ~3UL; /* ..whose size is at least */
- j += (df1 + LAST) & ~LAST; /* ..ceil(d/16) blocks */
+#if FF_X != 3 /* extra memory is needed.. */
+ bb = (size_t) (LOGRDX * i + 8 - 1e-10) / 8; /* to store NUM_radix and.. */
+ n += (bb + 3 + BLOCKSIZE) & ~15UL; /* mix it in Feistel rounds */
+#else
+ i *= len > MAXLEN ? 0 : sizeof (rbase_t);
+ n += i >= KEYSIZE ? 0 : KEYSIZE - i;
#endif
- if (len < MINLEN || (*indices = malloc( j )) == NULL)
+
+ if (len < MINLEN || i == 0) return 'L'; /* invalid string-length */
+
+ *indices = malloc( n );
+ if (*indices == NULL) return 'M'; /* memory allocation failed */
+
+ for (n = 0; n < len; ++n)
{
- return 'M'; /* memory allocation failed */
- }
- for (i = 0; i < len; ++i, ++str)
- {
- for (j = RADIX; --j && alpha[j] != *str; ) {}
- if (*str != alpha[j])
+ for (i = 0; alpha[i] != str[n]; )
{
- free( *indices ); /* invalid character found */
- return 'I';
+ if (++i == RADIX)
+ {
+ free( *indices ); /* invalid character found */
+ return 'C';
+ }
}
- (*indices)[i] = (rbase_t) j;
+ (*indices)[n] = (rbase_t) i;
}
return 0;
}
/** make the output string after completing FPE encrypt/decryption procedures */
-static void FPEfinalize( const rbase_t* index, const size_t len, void** output )
+static void FPEfinalize( const rbase_t* index, const size_t len, void* output )
{
- string_t alpha = ALPHABET, *s = *output;
+ const string_t abc = ALPHABET;
+ string_t str = output;
size_t i;
- for (i = 0; i < len; ++i) s[i] = alpha[*index++];
+ BURN( RoundKey );
+
+ str[len] = 0; /* null-terminated strings? */
+ for (i = len; i--; ) str[i] = abc[index[i]];
}
/**
@@ -2265,16 +2305,15 @@ char AES_FPE_encrypt( const uint8_t* key, const uint8_t* tweak,
#endif
const void* pntxt, const size_t ptextLen, void* crtxt )
{
- rbase_t *index = NULL;
- if (FPEsetup( pntxt, ptextLen, &index ) != 0) return ENCRYPTION_FAILURE;
+ rbase_t* index = NULL;
+ if (FPEinit( pntxt, ptextLen, &index ) != 0) return ENCRYPTION_FAILURE;
#if FF_X == 3
- FF3_Cipher( 1, key, ptextLen, tweak, index );
+ FF3_Cipher( key, 1, ptextLen, tweak, index );
#else
- FF1_Cipher( 1, key, ptextLen, tweak, tweakLen, index );
+ FF1_Cipher( key, 1, ptextLen, tweak, tweakLen, index );
#endif
- BURN( RoundKey );
- FPEfinalize( index, ptextLen, &crtxt );
+ FPEfinalize( index, ptextLen, crtxt );
free( index );
return ENDED_IN_SUCCESS;
}
@@ -2295,16 +2334,15 @@ char AES_FPE_decrypt( const uint8_t* key, const uint8_t* tweak,
#endif
const void* crtxt, const size_t crtxtLen, void* pntxt )
{
- rbase_t *index = NULL;
- if (FPEsetup( crtxt, crtxtLen, &index ) != 0) return DECRYPTION_FAILURE;
+ rbase_t* index = NULL;
+ if (FPEinit( crtxt, crtxtLen, &index ) != 0) return DECRYPTION_FAILURE;
#if FF_X == 3
- FF3_Cipher( 0, key, crtxtLen, tweak, index );
+ FF3_Cipher( key, 0, crtxtLen, tweak, index );
#else
- FF1_Cipher( 0, key, crtxtLen, tweak, tweakLen, index );
+ FF1_Cipher( key, 0, crtxtLen, tweak, tweakLen, index );
#endif
- BURN( RoundKey );
- FPEfinalize( index, crtxtLen, &pntxt );
+ FPEfinalize( index, crtxtLen, pntxt );
free( index );
return ENDED_IN_SUCCESS;
}
diff --git a/micro_aes.h b/micro_aes.h
index ddba7fa..2806bd0 100644
--- a/micro_aes.h
+++ b/micro_aes.h
@@ -2,7 +2,7 @@
==============================================================================
Name : micro_aes.h
Author : polfosol
- Version : 9.8.1.0
+ Version : 9.9.8.4
Copyright : copyright © 2022 - polfosol
Description : μAES ™ is a minimalist all-in-one library for AES encryption
==============================================================================
@@ -38,7 +38,7 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
#define CMAC 1 /* message authentication code (NIST SP 800-38B) */
#if CTR
-#define CCM 1 /* counter with CBC-MAC (RFC-3610 & SP 800-38C) */
+#define CCM 1 /* counter with CBC-MAC (RFC-3610/NIST SP 800-38C) */
#define GCM 1 /* Galois/counter mode with GMAC (NIST SP 800-38D) */
#define EAX 1 /* encrypt-authenticate-translate (ANSI C12.22) */
#define SIV 1 /* synthetic initialization vector (RFC-5297) */
@@ -68,19 +68,19 @@ AES block-cipher modes of operation. The following modes can be enabled/disabled
#define EAXP 1 /* EAX-prime, as specified by IEEE Std 1703 */
#endif
-#define WTF ! (POLY1305 || CMAC || BLOCKCIPHERS)
-#define M_RIJNDAEL WTF /* none of above; just rijndael API. dude.., why? */
+#define WTF ! (BLOCKCIPHERS | AEAD_MODES)
+#define M_RIJNDAEL WTF /* none of above; just rijndael API. dude.., why? */
/**----------------------------------------------------------------------------
Refer to the BOTTOM OF THIS DOCUMENT for some explanations about these macros:
-----------------------------------------------------------------------------*/
-#if ECB || CBC || XEX || KWA || M_RIJNDAEL
-#define DECRYPTION 1
+#if ECB || (CBC && !CTS) || (XEX && !XTS)
+#define AES_PADDING 0 /* standard values: (1) PKCS#7 (2) ISO/IEC7816-4 */
#endif
-#if ECB || (CBC && !CTS) || (XEX && !XTS)
-#define AES_PADDING 0 /* other valid values: (1) PKCS#7 (2) IEC7816-4 */
+#if ECB || CBC || XEX || KWA || M_RIJNDAEL
+#define DECRYPTION 1 /* rijndael decryption is NOT required otherwise. */
#endif
#if FPE
@@ -103,7 +103,7 @@ Refer to the BOTTOM OF THIS DOCUMENT for some explanations about these macros:
#endif
#if EAX && !EAXP
-#define EAX_NONCE_LEN 16 /* practically no limit; can be arbitrarily large */
+#define EAX_NONCE_LEN 16 /* no specified limit; can be arbitrarily large. */
#endif
#if OCB
@@ -112,15 +112,17 @@ Refer to the BOTTOM OF THIS DOCUMENT for some explanations about these macros:
#endif
/**----------------------------------------------------------------------------
-Since stdint.h is not a part of ANSI-C, we may need a 'trick' to use uint8_t
+Since is not a part of ANSI-C, we may need a 'trick' to use uint8_t
-----------------------------------------------------------------------------*/
#include
#if __STDC_VERSION__ > 199900L || __cplusplus > 201100L || defined(_MSC_VER)
#include
#else
#include
+#if CHAR_BIT == 8
typedef unsigned char uint8_t;
-#if INT_MAX > 100000L
+#endif
+#if INT_MAX > 200000L
typedef int int32_t;
#else
typedef long int32_t;
@@ -137,8 +139,8 @@ Encryption/decryption of a single block with Rijndael
#if M_RIJNDAEL
void AES_Cipher( const uint8_t* key, /* encryption/decryption key */
const char mode, /* encrypt: 'E', decrypt: 'D' */
- const uint8_t* x, /* input block byte array */
- uint8_t* y ); /* output block byte array */
+ const uint8_t x[16], /* input bytes (or input block) */
+ uint8_t y[16] ); /* output block */
#endif
/**----------------------------------------------------------------------------
@@ -161,13 +163,13 @@ Main functions for CBC-AES block ciphering
-----------------------------------------------------------------------------*/
#if CBC
char AES_CBC_encrypt( const uint8_t* key, /* encryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* pntxt, /* plaintext buffer */
const size_t ptextLen, /* length of input plain text */
uint8_t* crtxt ); /* cipher-text result */
char AES_CBC_decrypt( const uint8_t* key, /* decryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* crtxt, /* cipher-text buffer */
const size_t crtxtLen, /* length of input cipher text */
uint8_t* pntxt ); /* plaintext result */
@@ -178,13 +180,13 @@ Main functions for CFB-AES block ciphering
-----------------------------------------------------------------------------*/
#if CFB
void AES_CFB_encrypt( const uint8_t* key, /* encryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* pntxt, /* plaintext buffer */
const size_t ptextLen, /* length of input plain text */
uint8_t* crtxt ); /* cipher-text result */
void AES_CFB_decrypt( const uint8_t* key, /* decryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* crtxt, /* cipher-text buffer */
const size_t crtxtLen, /* length of input cipher text */
uint8_t* pntxt ); /* plaintext result */
@@ -195,13 +197,13 @@ Main functions for OFB-AES block ciphering
-----------------------------------------------------------------------------*/
#if OFB
void AES_OFB_encrypt( const uint8_t* key, /* encryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* pntxt, /* plaintext buffer */
const size_t ptextLen, /* length of input plain text */
uint8_t* crtxt ); /* cipher-text result */
void AES_OFB_decrypt( const uint8_t* key, /* decryption key */
- const uint8_t* iVec, /* initialization vector */
+ const uint8_t iVec[16], /* initialization vector */
const uint8_t* crtxt, /* cipher-text buffer */
const size_t crtxtLen, /* length of input cipher text */
uint8_t* pntxt ); /* plaintext result */
@@ -212,13 +214,13 @@ Main functions for XTS-AES block ciphering
-----------------------------------------------------------------------------*/
#if XTS
char AES_XTS_encrypt( const uint8_t* keys, /* encryption key pair */
- const uint8_t* unitId, /* tweak value (sector ID) */
+ const uint8_t* tweak, /* tweak value (unit/sector ID) */
const uint8_t* pntxt, /* plaintext buffer */
const size_t ptextLen, /* length of input plain text */
uint8_t* crtxt ); /* cipher-text result */
char AES_XTS_decrypt( const uint8_t* keys, /* decryption key pair */
- const uint8_t* unitId, /* tweak value (sector ID) */
+ const uint8_t* tweak, /* tweak value (unit/sector ID) */
const uint8_t* crtxt, /* cipher-text buffer */
const size_t crtxtLen, /* length of input cipher text */
uint8_t* pntxt ); /* plaintext result */
@@ -250,11 +252,11 @@ void AES_SIV_encrypt( const uint8_t* keys, /* encryption key pair */
const size_t ptextLen, /* length of input plain text */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
- uint8_t* iv, /* synthesized initial-vector */
+ uint8_t iv[16], /* synthesized initial-vector */
uint8_t* crtxt ); /* cipher-text result */
char AES_SIV_decrypt( const uint8_t* keys, /* decryption key pair */
- const uint8_t* iv, /* provided initial-vector */
+ const uint8_t iv[16], /* provided initial-vector */
const uint8_t* crtxt, /* cipher text */
const size_t crtxtLen, /* length of input cipher-text */
const uint8_t* aData, /* added authentication data */
@@ -273,7 +275,7 @@ void AES_GCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* crtxt, /* cipher-text result */
- uint8_t* auTag ); /* message authentication tag */
+ uint8_t auTag[16] ); /* message authentication tag */
char AES_GCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* a.k.a initialization vector */
@@ -296,7 +298,7 @@ void AES_CCM_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* crtxt, /* cipher-text result */
- uint8_t* auTag ); /* message authentication tag */
+ uint8_t auTag[16] ); /* message authentication tag */
char AES_CCM_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* a.k.a initialization vector */
@@ -319,7 +321,7 @@ void AES_OCB_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* crtxt, /* cipher-text result */
- uint8_t* auTag ); /* message authentication tag */
+ uint8_t auTag[16] ); /* message authentication tag */
char AES_OCB_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* a.k.a initialization vector */
@@ -346,7 +348,7 @@ void AES_EAX_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* crtxt, /* cipher-text result */
- uint8_t* auTag ); /* message authentication tag */
+ uint8_t auTag[16] ); /* message authentication tag */
#endif
char AES_EAX_decrypt( const uint8_t* key, /* decryption key */
@@ -374,7 +376,7 @@ void GCM_SIV_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* aData, /* added authentication data */
const size_t aDataLen, /* size of authentication data */
uint8_t* crtxt, /* cipher-text result */
- uint8_t* auTag ); /* 16-bytes mandatory tag */
+ uint8_t auTag[16] ); /* 16-bytes mandatory tag */
char GCM_SIV_decrypt( const uint8_t* key, /* decryption key */
const uint8_t* nonce, /* provided 96-bit nonce */
@@ -407,7 +409,9 @@ Main functions for FPE-AES; more info at the bottom of this page.
#if FPE
char AES_FPE_encrypt( const uint8_t* key, /* encryption key */
const uint8_t* tweak, /* tweak bytes */
-#if FF_X != 3
+#if FF_X == 3
+#define FF3_TWEAK_LEN 7 /* either 8 (FF3), or 7 (FF3-1) */
+#else
const size_t tweakLen, /* size of tweak array */
#endif
const void* pntxt, /* input plaintext string */
@@ -429,10 +433,10 @@ Main function for Poly1305-AES message authentication code
-----------------------------------------------------------------------------*/
#if POLY1305
void AES_Poly1305( const uint8_t* keys, /* encryption/mixing key pair */
- const uint8_t* nonce, /* the 128-bit nonce */
+ const uint8_t nonce[16], /* the 128-bit nonce */
const void* data, /* input data buffer */
const size_t dataSize, /* size of data in bytes */
- uint8_t* mac ); /* calculated poly1305-AES mac */
+ uint8_t mac[16] ); /* poly1305-AES mac of data */
#endif
/**----------------------------------------------------------------------------
@@ -442,7 +446,7 @@ Main function for AES Cipher-based Message Authentication Code
void AES_CMAC( const uint8_t* key, /* encryption/cipher key */
const void* data, /* input data buffer */
const size_t dataSize, /* size of data in bytes */
- uint8_t* mac ); /* calculated CMAC hash */
+ uint8_t mac[16] ); /* CMAC result of input data */
#endif
#ifdef __cplusplus
@@ -457,26 +461,22 @@ The error codes and key length should be defined here for external references:
#define AUTHENTICATION_FAILURE 0x1A
#define ENDED_IN_SUCCESS 0x00
-#if (AES___ == 256) || (AES___ == 192)
-#define AES_KEY_LENGTH (AES___/8)
+#if (AES___ != 256) && (AES___ != 192)
+#define AES_KEY_SIZE 16
#else
-#define AES_KEY_LENGTH 16
+#define AES_KEY_SIZE (AES___ / 8)
#endif
#endif /* header guard */
-/**¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯**\
+/******************************************************************************\
¦ Notes and remarks about the above-defined macros ¦
--------------------------------------------------------------------------------
-* Some AES modes just use the 'encryption' part of the Rijndael algorithm. So if
- you are NOT using the decryption functions of ECB/CBC/KWA/XEX modes, you can
- safely disable DECRYPTION macro and save a few kilobytes in compiled code.
-
* In EBC/CBC/XEX modes, the size of input must be a multiple of block-size.
Otherwise it needs to be padded. The simplest (default) padding mode is to
fill the rest of block by zeros. Supported standard padding methods are
- PKCS#7 and ISO/IEC 7816-4, which can be enabled by AES_PADDING macro.
+ PKCS#7 and ISO/IEC 7816-4, which can be enabled by the AES_PADDING macro.
* In many texts, you may see that the words 'nonce' and 'initialization vector'
are used interchangeably. But they have a subtle difference. Sometimes nonce
@@ -486,7 +486,7 @@ The error codes and key length should be defined here for external references:
start at CTR_STARTVALUE, or use a full block IV.
* In AEAD modes, the size of nonce and tag might be a parameter of the algorithm
- such that changing them affect the results. The GCM/EAX modes support
+ 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
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-
@@ -508,28 +508,27 @@ The error codes and key length should be defined here for external references:
called 'the alphabet'. The default alphabet is the set of digits {'0'..'9'}.
If you want to use a different alphabet, set the CUSTOM_ALPHABET macro and
refer to the "micro_fpe.h" header. This file is needed only when a custom
- alphabet has to be defined, and contains some illustrative examples and
- clear guidelines on how to do so.
+ alphabet has to be defined. It contains some illustrative examples and clear
+ guidelines on how to do so.
* The key wrapping mode is also denoted by KW. In this mode, the input secret is
divided into 64bit blocks. Number of blocks is at least 2, and it is assumed
- that no padding is required. For padding, the KWP mode is used which is
- easily implementable, but left as an exercise! In the NIST document you may
- find some mentions of TKW which is for 3DES and irrelevant here. Anyway, the
- wrapped output has an additional block, i.e. wrappedSize = secretSize + 8.
+ that no padding is required. For padding, the KWP mode must be used which is
+ easily implementable, but left as an exercise! The key-wrapped output is an
+ extra block (8 bytes) longer than the secret. In the NIST SP800-38F document
+ you may find some mentions of TKW which is for 3DES and irrelevant here.
* Let me explain three extra options that are defined in the source file. If the
length of the input cipher/plain text is 'always' less than 4KB, you can
- enable the SMALL_CIPHER macro to save a few bytes in the compiled code. Note
- that for key-wrapping, this limit is 42 blocks (336 bytes) of secret key.
- These assumptions are likely to be valid for some embedded systems and small
- applications. Furthermore, enabling that other macro, REDUCE_CODE_SIZE had a
- considerable effect on the size of the compiled code in my own tests.
- Nonetheless, others might get a different result from them.
+ 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 by enabling the DONT_USE_FUNCTIONS macro, you may
+ witness a positive effect on the speed while increasing the size of compiled
+ code. Nonetheless, others might get a different result from them.
The INCREASE_SECURITY macro, as its name suggests, is dealing with security
- considerations. For example, since the RoundKey is declared as static array,
- it might be exposed to some attacks. By enabling this macro, round-keys are
+ considerations. For example, since the RoundKey is declared as static array
+ it might get exposed to some attacks. By enabling this macro, round-keys are
wiped out at the end of ciphering operations. However, please keep in mind
that this is NOT A GUARANTEE against side-channel attacks.
diff --git a/micro_fpe.h b/micro_fpe.h
new file mode 100644
index 0000000..993af29
--- /dev/null
+++ b/micro_fpe.h
@@ -0,0 +1,168 @@
+/*
+ ==============================================================================
+ Name : micro_fpe.h
+ Author : polfosol
+ Version : 2.1.1.2
+ Copyright : copyright © 2022 - polfosol
+ Description : demonstrating some sample alphabets for the FPE mode of μAES ™
+ ==============================================================================
+ */
+
+#ifndef MICRO_FPE_H_
+#define MICRO_FPE_H_
+
+/******************************************************************************
+ * If your desired alphabet contains non-ASCII characters, the CUSTOM_ALPHABET
+ * macro 'must be' set to a double-digit number, e.g 21. In what follows, there
+ * are some sample alphabets along with their corresponding macro definitions.
+ * It is straightforward to define another alphabet according to these samples.
+ */
+#define NON_ASCII_CHARACTER_SET (CUSTOM_ALPHABET >= 10)
+
+
+/******************************************************************************
+ * These strings are commonly used in ASCII-based alphabets. The declaration of
+ * an alphabet must be followed by its number of characters (RADIX).
+ */
+#define DECDIGIT "0123456789"
+#define LCLETTER "abcdefghijklmnopqrstuvwxyz"
+#define UCLETTER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define HEXDIGIT DECDIGIT "ABCDEFabcdef"
+
+/**
+ numbers
+ */
+#if CUSTOM_ALPHABET == 0
+#define ALPHABET DECDIGIT
+#define RADIX 10
+#endif
+
+/**
+ binary numbers
+ */
+#if CUSTOM_ALPHABET == 1
+#define ALPHABET "01"
+#define RADIX 2
+#endif
+
+/**
+ lowercase english words
+ */
+#if CUSTOM_ALPHABET == 2
+#define ALPHABET LCLETTER
+#define RADIX 26
+#endif
+
+/**
+ lowercase alphanumeric strings
+ */
+#if CUSTOM_ALPHABET == 3
+#define ALPHABET DECDIGIT LCLETTER
+#define RADIX 36
+#endif
+
+/**
+ the English alphabet
+ */
+#if CUSTOM_ALPHABET == 4
+#define ALPHABET UCLETTER LCLETTER
+#define RADIX 52
+#endif
+
+/**
+ base-64 encoded strings (RFC-4648), with no padding character
+ */
+#if CUSTOM_ALPHABET == 5
+#define ALPHABET UCLETTER LCLETTER DECDIGIT "+/"
+#define RADIX 64
+#endif
+
+/**
+ base-85 encoded strings (RFC-1924)
+ */
+#if CUSTOM_ALPHABET == 6
+#define ALPHABET DECDIGIT UCLETTER LCLETTER "!#$%&()*+-;<=>?@^_`{|}~"
+#define RADIX 85
+#endif
+
+/**
+ a character set with length 26, used by some test vectors
+ */
+#if CUSTOM_ALPHABET == 7
+#define ALPHABET DECDIGIT "abcdefghijklmnop"
+#define RADIX 26
+#endif
+
+/**
+ base-64 character set with DIFFERENT ORDERING, used by some test vectors
+ */
+#if CUSTOM_ALPHABET == 8
+#define ALPHABET DECDIGIT UCLETTER LCLETTER "+/"
+#define RADIX 64
+#endif
+
+/**
+ all printable ascii characters
+ */
+#if CUSTOM_ALPHABET == 9
+#define ALPHABET " !\"#$%&\'()*+,-./"DECDIGIT":;<=>?@"UCLETTER"[\\]^_`"LCLETTER"{|}~"
+#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
+
+/**
+ Greek alphabet (LTR)
+ */
+#if CUSTOM_ALPHABET == 10
+#define ALPHABET L"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφϕχψω"
+#define RADIX 50
+#endif
+
+/**
+ Persian alphabet (RTL)
+ */
+#if 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 10 significant digits) and
+ * set it as a constant, or let it be calculated dynamically like this:
+ */
+#include
+#define LOGRDX (log( RADIX ) / log( 2 )) /* log2( RADIX ) if std=C99 */
+#if FF_X == 3
+#define MAXLEN (2 * (int) (96.000001 / LOGRDX))
+#endif
+#define MINLEN ((int) (19.931568 / LOGRDX + 1))
+
+
+/******************************************************************************
+ * or we can do something like this to set MINLEN:
+ *
+#if RADIX >= 32
+#define MINLEN (2 + (RADIX < 1000) + (RADIX < 100))
+#elif RADIX > 5
+#define MINLEN (5 + (RADIX < 16) + (RADIX < 10) + (RADIX < 8))
+#else
+#define MINLEN (40 / RADIX + RADIX / 5)
+#endif
+ */
+
+#endif /* header guard */
diff --git a/prj_codeblocks.cbp b/prj_codeblocks.cbp
index 70465a9..c8d8144 100644
--- a/prj_codeblocks.cbp
+++ b/prj_codeblocks.cbp
@@ -2,40 +2,38 @@
-
+
-
+
-
+
-
+
-
-
-
+
+
+
-
+
-
+
-
-
+
+
+
-
-
-
@@ -43,6 +41,9 @@
-
+
+
+
+
diff --git a/prj_codelite.project b/prj_codelite.project
deleted file mode 100644
index 53ae444..0000000
--- a/prj_codelite.project
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- None
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- None
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/prj_vc++.vcxproj b/prj_vc++.vcxproj
index 098d21b..3d292fd 100644
--- a/prj_vc++.vcxproj
+++ b/prj_vc++.vcxproj
@@ -81,6 +81,7 @@
+
diff --git a/testvectors/CCMtest.c b/testvectors/CCMtest.c
index 18fec9f..aa0e445 100644
--- a/testvectors/CCMtest.c
+++ b/testvectors/CCMtest.c
@@ -2,9 +2,9 @@
==============================================================================
Name : CCMtest.c
Author : polfosol
- Version : 1.6.0.0
+ Version : 1.6.1.2
Copyright : copyright © 2022 - polfosol
- Description : illustrating how the NIST's vectors for AES-CCM mode are used
+ Description : illustrating how to validate NIST's vectors for AES-CCM mode
==============================================================================
*/
@@ -13,35 +13,34 @@
#define TESTFILEPATH "CCM_VNT128.rsp"
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void str2bytes(const char* hex, uint8_t* bytes)
{
- size_t i, j;
- for (i = 0, j = ~0; str[i]; ++i)
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
{
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
}
}
-static void bytes2str(const uint8_t* bytes, char* str, size_t len)
-#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
{
- size_t i, j;
- for (i = 0, j = 0; i < len; ++i)
+ 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[j++] = num2char(bytes[i] >> 4);
- str[j++] = num2char(bytes[i] & 15);
+ str[i] = bytes[i / 2] >> shr & 0xF | '0';
+ if (str[i] > '9') str[i] += offset;
}
- str[j] = 0;
}
-static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t* c, uint8_t np, uint8_t na, char* r)
+static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t* c,
+ size_t np, size_t na, char* r)
{
- char sk[70], si[40], sp[80], sc[96], sa[80], msg[30];
+ char sk[2*AES_KEY_SIZE + 1], si[33], sp[80], sc[96], sa[80], msg[30];
uint8_t tmp[64], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_CCM_encrypt(key, iv, p, np, a, na, tmp, tmp + np);
if (memcmp(c, tmp, np + CCM_TAG_LEN))
@@ -55,7 +54,7 @@ static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t
{
sprintf(msg, "%sdecrypt failure", t & 1 ? "encrypt & " : "");
}
- bytes2str(key, sk, AES_KEY_LENGTH);
+ bytes2str(key, sk, AES_KEY_SIZE);
bytes2str(iv, si, CCM_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
@@ -69,7 +68,7 @@ int main()
const char *linehdr[] = { "Key = ", "Nonce = ", "Adata = ", "Payload = ", "CT = " };
char buffer[0x800], *value = "";
size_t pass = 0, df = 0, ef = 0, sk = 0, sn = 0, sp = 0, sc = 0, sa = 0;
- uint8_t i, n = 0, key[AES_KEY_LENGTH], iv[16], p[64], c[80], a[64];
+ uint8_t i, n = 0, key[AES_KEY_SIZE], iv[16], p[64], c[80], a[64];
FILE *fp, *fs, *ferr;
fp = fopen(TESTFILEPATH, "r");
@@ -99,7 +98,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == AES_KEY_LENGTH) str2bytes(value, key);
+ if (sk == AES_KEY_SIZE) str2bytes(value, key);
break;
case 1:
sn = strlen(value) / 2;
@@ -122,7 +121,7 @@ int main()
}
if (n == 2)
{
- if (sk == AES_KEY_LENGTH && sn == CCM_NONCE_LEN && sp == sc)
+ if (sk == AES_KEY_SIZE && sn == CCM_NONCE_LEN && sp == sc)
{
n = ciphertest(key, iv, p, a, c, sp, sa, buffer);
fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
@@ -137,7 +136,7 @@ int main()
}
}
printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
- pass + ef + df, pass, ef, df);
+ pass + (ef > df ? ef : df), pass, ef, df);
fclose(fp); fclose(fs); fclose(ferr);
if (ef + df == 0)
diff --git a/testvectors/CMACtest.c b/testvectors/CMACtest.c
index b4235f5..9b4bc33 100644
--- a/testvectors/CMACtest.c
+++ b/testvectors/CMACtest.c
@@ -2,9 +2,9 @@
==============================================================================
Name : CMACtest.c
Author : polfosol
- Version : 1.5.0.0
+ Version : 1.5.1.1
Copyright : copyright © 2022 - polfosol
- Description : illustrating how the NIST's vectors for AES-CMAC are used
+ Description : illustrating how to validate NIST's vectors for AES-CMAC
==============================================================================
*/
@@ -13,41 +13,39 @@
#define TESTFILEPATH "CMACGenAES128.rsp"
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void str2bytes(const char* hex, uint8_t* bytes)
{
- size_t i, j;
- for (i = 0, j = ~0; str[i]; ++i)
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
{
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
}
}
-static void bytes2str(const uint8_t* bytes, char* str, size_t len)
-#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
{
- size_t i, j;
- for (i = 0, j = 0; i < len; ++i)
+ 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[j++] = num2char(bytes[i] >> 4);
- str[j++] = num2char(bytes[i] & 15);
+ str[i] = bytes[i / 2] >> shr & 0xF | '0';
+ if (str[i] > '9') str[i] += offset;
}
- str[j] = 0;
}
static int ciphertest(uint8_t* key, uint8_t* d, uint8_t* m, size_t ds, size_t ms, char* r)
{
- char sk[2*AES_KEY_LENGTH + 8], smac[40], msg[30];
+ char sk[2*AES_KEY_SIZE + 1], smac[33], msg[30];
uint8_t tmp[32], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_CMAC(key, d, ds, tmp);
t = memcmp(m, tmp, ms);
if (t) sprintf(msg, "%s", "failed");
- bytes2str(key, sk, AES_KEY_LENGTH);
+ bytes2str(key, sk, AES_KEY_SIZE);
bytes2str(m, smac, ms);
sprintf(r, "%s\nK: %s\nmac: %s\n", msg, sk, smac);
return t;
@@ -88,7 +86,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == AES_KEY_LENGTH) str2bytes(value, key);
+ if (sk == AES_KEY_SIZE) str2bytes(value, key);
break;
case 1:
sd = strlen(value) / 2;
@@ -104,7 +102,7 @@ int main()
}
if (n == 2)
{
- if (sk == AES_KEY_LENGTH)
+ if (sk == AES_KEY_SIZE)
{
n = ciphertest(key, d, m, sd, sm, buffer);
fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
diff --git a/testvectors/FPE_FF1&FF3&FF3-1.tv b/testvectors/FPE_FF1&FF3&FF3-1.tv
new file mode 100644
index 0000000..fe2f598
--- /dev/null
+++ b/testvectors/FPE_FF1&FF3&FF3-1.tv
@@ -0,0 +1,563 @@
+# NIST Test Vectors for FPE-AES
+# IMPORTANT NOTE:
+# Some FF3 test vectors are for the old version of FF3, which was based on 64-bit tweaks.
+# The last revision of "NIST SP 800-38G" demands using 56-bit tweaks in FF3-1.
+#
+# Extracted from PDF files in
+# https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values
+# Also a bunch of vectors are taken from:
+# https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html
+# https://github.com/mysto/python-fpe/blob/main/ff3/ff3_test.py
+# https://github.com/ubiqsecurity/ubiq-fpe-c/tree/master/src/test
+#
+
+
+Count = 1
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Tweak =
+PT = 0123456789
+CT = 2433477484
+
+
+Count = 2
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Tweak = 39383736353433323130
+PT = 0123456789
+CT = 6124200773
+
+
+Count = 3
+Method = FF1
+Alphabet = 0123456789abcdefghijklmnopqrstuvwxyz
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3C
+Tweak = 3737373770717273373737
+PT = 0123456789abcdefghi
+CT = a9tv40mll9kdu509eum
+
+
+Count = 4
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F
+Tweak =
+PT = 0123456789
+CT = 2830668132
+
+
+Count = 5
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F
+Tweak = 39383736353433323130
+PT = 0123456789
+CT = 2496655549
+
+
+Count = 6
+Method = FF1
+Alphabet = 0123456789abcdefghijklmnopqrstuvwxyz
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F
+Tweak = 3737373770717273373737
+PT = 0123456789abcdefghi
+CT = xbj3kv35jrawxv32ysr
+
+
+Count = 7
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94
+Tweak =
+PT = 0123456789
+CT = 6657667009
+
+
+Count = 8
+Method = FF1
+Alphabet = 0123456789
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = 39383736353433323130
+PT = 0123456789
+CT = 1001623463
+
+
+Count = 9
+Method = FF1
+Alphabet = 0123456789abcdefghijklmnopqrstuvwxyz
+
+Key = 2B7E151628AED2A6ABF7158809CF4F3CEF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = 3737373770717273373737
+PT = 0123456789abcdefghi
+CT = xs8a0azh2avyalyzuwd
+
+
+Count = 10
+Method = FF1
+Alphabet = 0123456789
+
+Key = FA407521178EDB931997C9EF5FF4F8BB
+Tweak =
+PT = 5989891000
+CT = 4896500946
+
+
+Count = 11
+Method = FF1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = D263686051802ECAE0217F4123000376
+Tweak =
+PT = zlwagydvpt
+CT = odmrhltvlj
+
+
+Count = 12
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 00000101011011011101001001010011100111100011001
+CT = 10110101001110101101110000011000000011111100111
+
+
+Count = 13
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 000010101100011111010000111001100001011010011110100100110010010000000101000011000000001111110101111100111001001001100100100110101111110000011101010111001111010000010010111110101100001001100011
+CT = 111110001101110010010110001010100001101011001010011010111001001101101000011110000110110000001101011110101100001101000011101110110101001111100001011010010000010111001110010011001100001111100101
+
+
+Count = 14
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 00000111011010010101111110011110001011111000110100000101001010001100001101111000010000101011100100010111011101001010010100101010100011010101010000101111111001111100110100001100011001011010010000110
+CT = 00110011001000111100010111110001000110110110010010101101001011101001101010010001111001010100100001110101010101101110110010100110101110111011111010110010101110000001101000101010100011010100111011000
+
+
+Count = 15
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 00001100010001110001000111100100001111110110000000001010000001111100000111100101110111101100101011001010010010001011100000100100011100010111111000111101010111010110011001000010000101000100000111011001000010000111001010100101111011111100111111101010001111101111101000101111101100101001000010110101011100011011001110101101001100100101101000000111100100110000001111011000110011110000011011101111001110101101111001001111010101011001100011001111001110
+CT = 10101101001111110110110001010101110111011010101001110011111101101101000001110010100110110011011101000101010001111101100000110000101110000000110001011000100000111001111011101011100011100010100001010011110100010001001000001101110010110111100010101001000100100000010111100000101000010100011001100011111110011100111110011100111111011001101011100010100110001100111000100000101011111110100011110011101001010110001000011010011011101001101000001100110100
+
+
+Count = 16
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 0000100001110000110111000100110011101011100100100000011011100101010101010100111000001001001010110110101100010001111111101001100100001110000001101100101000110000001101100100110101101101111011010100010100110101110011101101001000010100110111101111000100001011010011000000000011001010110000110111110010111110001010111000011100010010100111011110010100110101000100101010010100001110010101001100010001111000011110001101011010001010110110010000111001110110101
+CT = 0101111000110110000111000111011100110111101000100000100010100110100010001101000101111000100000111000000011110111001001101010100001111100100101100100000000000011100011110010100010000010001001101100011100111110101110000101111010100111100000111000000111011011010101111100110101000110001110110001110011111000111110010000100010000101010110000010010100001111011010110111011111101000100000010111101010000011011110001000000011111010110010100101001000111101110
+
+
+Count = 17
+Method = FF1
+Alphabet = 01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 0000100001110000110111000100110011101011100100100000011011100101010101010100111000001001001010110110101100010001111111101001100100001110000001101100101000110000001101100100110101101101111011010100010100110101110011101101001000010100110111101111000100001011010011000000000011001010110000110111110010111110001010111000011100010010100111011110010100110101000100101010010100001110010101001100010001111000011110001101011010001010110110010000111001110110101000010000111000011011100010011001110101110010010000001101110010101010101010011100000100100101011011010110001000111111110100110010000111000000110110010100011000000110110010011010110110111101101010001010011010111001110110100100001010011011110111100010000101101001100000000001100101011000011011111001011111000101011100001110001001010011101111001010011010100010010101001010000111001010100110001000111100001111000110101101000101011011001000011100111011010100001000011100001101110001001100111010111001001000000110111001010101010101001110000010010010101101101011000100011111111010011001000011100000011011001010001100000011011001001101011011011110110101000101001101011100111011010010000101001101111011110001000010110100110000000000110010101100001101111100101111100010101110000111000100101001110111100101001101010001001010100101000011100101010011000100011110000111100011010110100010101101100100001110011101101010000100001110000110111000100110011101011100100100000011011100101010101010100111000001001001010110110101100010001111111101001100100001110000001101100101000110000001101100100110101101101111011010100010100110101110011101101001000010100110111101111000100001011010011000000000011001010110000110111110010111110001010111000011100010010100111011110010100110101000100101010010100001110010101001100010001111000011110001101011010001010110110010000111001110110101
+CT = 0000010100010011101101101111101011010101110011111000100110100110001101001001111110001100001010111011001001101100011110010111111111100011111111111011100000101000000101101100011001110110011011110111011101101111110110000101000011111101100100100101010110111010101111001011000001100000100000110110110111001101010101001111101111010111010111001101101000000101100001000100100001111001001001001000001010010000101000110111010010000010010101000000111111101001011101111111000100101001100110001111001101110001010110011000000000101011001010110110011101100111001110010111011010101110100100111010111000010011010000001001001111110110001110010110111101101000001100101101100010101101010110010001001110010001100110101100011001010010011001100101010001111010100000101010011111010001110110000111101010111111101101001001110001110110111111100101001010110010011000011111110111110000010010110110111100110101000111000011010100100001101001010001110000011110001110101001010110011111100010001011001110110100000001010001010101001000011000001010010001110110001011000010010011111011101001110010100101001000011111100011111111110000110111001101101001111111010011011110101101011111010010101000100011010011111010100101011001100110110101011110110000010110111101001100000001011000010000110111100111110001101011011000010010011111101010001100010010001100111111110011101000111110101001100011010100100110110111010010010001100001101000111000000010000111101010001011111100011111001111000111001110100110010110000101000100001000001100100000100101011001000001011010000000000011100110001001011111001011101010100001101101000111101010111000101001000001100011110000101111100110110100001111001110011111111000100011000010000000110110101011101001010000001011010010101111101100100011110101110101110101010110001110100000000010100011000111011011110100111111111100
+
+
+Count = 18
+Method = FF1
+Alphabet = 0123456789
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 0000100001110000110111000100110011101011100100100000011011100101010101010100111000001001001010110110101100010001111111101001100100001110000001101100101000110000001101100100110101101101111011010100010100110101110011101101001000010100110111101111000100001011010011000000000011001010110000110111110010111110001010111000011100010010100111011110010100110101000100101010010100001110010101001100010001111000011110001101011010001010110110010000111001110110101000010000111000011011100010011001110101110010010000001101110010101010101010011100000100100101011011010110001000111111110100110010000111000000110110010100011000000110110010011010110110111101101010001010011010111001110110100100001010011011110111100010000101101001100000000001100101011000011011111001011111000101011100001110001001010011101111001010011010100010010101001010000111001010100110001000111100001111000110101101000101011011001000011100111011010100001000011100001101110001001100111010111001001000000110111001010101010101001110000010010010101101101011000100011111111010011001000011100000011011001010001100000011011001001101011011011110110101000101001101011100111011010010000101001101111011110001000010110100110000000000110010101100001101111100101111100010101110000111000100101001110111100101001101010001001010100101000011100101010011000100011110000111100011010110100010101101100100001110011101101010000100001110000110111000100110011101011100100100000011011100101010101010100111000001001001010110110101100010001111111101001100100001110000001101100101000110000001101100100110101101101111011010100010100110101110011101101001000010100110111101111000100001011010011000000000011001010110000110111110010111110001010111000011100010010100111011110010100110101000100101010010100001110010101001100010001111000011110001101011010001010110110010000111001110110101
+CT = 3553494089916656541184478908087049735544912674297349664796606620188730753059002844128234255625871546044854395209962926784724128560713512248808687211149744598195412712940468163774096628350620951413711803950518594617373351544393856373450320087523262022383945648127372062478231148038471844014871132794421592688429360388632538622007325709023114489620502858661369331722385345630805557726657301103731476891939356540625190861223831202018869059523597995303290074121079428721457071756416572728029177746810900307020259537765410201929963086982307837186509364236956511999350147323721010332857847774386067644233703989840323109138134072973241903156111826976160812600185129257000146824574348291127595725594892501619634508128488731892352987207154538043275865206720407431701986579498575764625682405793438116486315329904924734993624192175538907728005546006779836347751281158514862256352526481718064122564580367217956237464358103196538875291283690155429858297253893898279060676625001618108275714219171491371113956773762844941034947472026591341252339034136627998253233817606250024841230463067533567089935603756301565820369079927700758805948772321763265628871349903204249162513281402250087834393259987925784678440411900598614732588243252529912937631866659880744158524571625718103685314053287308120410823249151599910726383359255592539946379861183034458490744302067049236667020141763610651851768955009732517336400650838408764716423829225801720580144333813816604222676507183341558005308742505170406478517237115923457992442034329915124651627732600793249273733794088807416454414747271994796609670521986503851051553369292884493564374526214897996510458573439669519885826154261070811550077849422033063494354368756584234578197857360235955389059655914778268996127569020343877063422715737926819877510937231474460324658469989214234346399
+
+
+Count = 19
+Method = FF1
+Alphabet = 23456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 3456789AB2CDEFGHcdefgh
+CT = 8MPH0buu9UDS9y9wfWyuxA
+
+
+Count = 20
+Method = FF1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()
+
+Key = f4a116d6ee406a53a56cbe0f4aa7b1001cdc0a55cac963cf5ace390488b3477a
+Tweak = fd7f4b9945a3c535adb4720027116ca0f4987d7f3fdba9bbc40e75375feaa63c
+PT = 1234567890ABCDEFabcdef
+CT = x%$lEuv$QuA5HykL#2WZW0
+
+
+###############################################################
+# FF3 test vectors
+###############################################################
+
+
+Count = 21
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = D8E7920AFA330A73
+PT = 890121234567890000
+CT = 750918814058654607
+
+
+Count = 22
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = 9A768A92F60E12D8
+PT = 890121234567890000
+CT = 018989839189395384
+
+
+Count = 23
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = D8E7920AFA330A73
+PT = 89012123456789000000789000000
+CT = 48598367162252569629397416226
+
+
+Count = 24
+Method = FF3
+Alphabet = 0123456789abcdefghijklmnop
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = 9A768A92F60E12D8
+PT = 0123456789abcdefghi
+CT = g2pk40i992fn20cjakb
+
+
+Count = 25
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6
+Tweak = D8E7920AFA330A73
+PT = 890121234567890000
+CT = 646965393875028755
+
+
+Count = 26
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6
+Tweak = 9A768A92F60E12D8
+PT = 890121234567890000
+CT = 961610514491424446
+
+
+Count = 27
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6
+Tweak = D8E7920AFA330A73
+PT = 89012123456789000000789000000
+CT = 53048884065350204541786380807
+
+
+Count = 28
+Method = FF3
+Alphabet = 0123456789abcdefghijklmnop
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6
+Tweak = 9A768A92F60E12D8
+PT = 0123456789abcdefghi
+CT = i0ihe2jfj7a9opf9p88
+
+
+Count = 29
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C
+Tweak = D8E7920AFA330A73
+PT = 890121234567890000
+CT = 922011205562777495
+
+
+Count = 30
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C
+Tweak = 9A768A92F60E12D8
+PT = 890121234567890000
+CT = 504149865578056140
+
+
+Count = 31
+Method = FF3
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C
+Tweak = D8E7920AFA330A73
+PT = 89012123456789000000789000000
+CT = 04344343235792599165734622699
+
+
+Count = 32
+Method = FF3
+Alphabet = 0123456789abcdefghijklmnop
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C
+Tweak = 9A768A92F60E12D8
+PT = 0123456789abcdefghi
+CT = p0b2godfja9bhb7bk38
+
+
+###############################################################
+# FF3-1 test vectors
+###############################################################
+
+
+Count = 33
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A94
+Tweak = 0000000000000000
+PT = 89012123456789000000789000000
+CT = 34695224821734535122613701434
+
+
+Count = 34
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6
+Tweak = 0000000000000000
+PT = 89012123456789000000789000000
+CT = 98083802678820389295041483512
+
+
+Count = 35
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = EF4359D8D580AA4F7F036D6F04FC6A942B7E151628AED2A6ABF7158809CF4F3C
+Tweak = 0000000000000000
+PT = 89012123456789000000789000000
+CT = 30859239999374053872365555822
+
+
+Count = 36
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = 2DE79D232DF5585D68CE47882AE256D6
+Tweak = CBD09280979564
+PT = 3992520240
+CT = 8901801106
+
+
+Count = 37
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = 01C63017111438F7FC8E24EB16C71AB5
+Tweak = C4E822DCD09F27
+PT = 60761757463116869318437658042297305934914824457484538562
+CT = 35637144092473838892796702739628394376915177448290847293
+
+
+Count = 38
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = 718385E6542534604419E83CE387A437
+Tweak = B6F35084FA90E1
+PT = wfmwlrorcd
+CT = ywowehycyd
+
+
+Count = 39
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = DB602DFF22ED7E84C8D8C865A941A238
+Tweak = EBEFD63BCC2083
+PT = kkuomenbzqvggfbteqdyanwpmhzdmoicekiihkrm
+CT = belcfahcwwytwrckieymthabgjjfkxtxauipmjja
+
+
+Count = 40
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = AEE87D0D485B3AFD12BD1E0B9D03D50D
+Tweak = 5F9140601D224B
+PT = ixvuuIHr0e
+CT = GR90R1q838
+
+
+Count = 41
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = 7B6C88324732F7F4AD435DA9AD77F917
+Tweak = 3F42102C0BAB39
+PT = 21q1kbbIVSrAFtdFWzdMeIDpRqpo
+CT = cvQ/4aGUV4wRnyO3CHmgEKW5hk8H
+
+
+Count = 42
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = F62EDB777A671075D47563F3A1E9AC797AA706A2D8E02FC8
+Tweak = 493B8451BF6716
+PT = 4406616808
+CT = 1807744762
+
+
+Count = 43
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = 0951B475D1A327C52756F2624AF224C80E9BE85F09B2D44F
+Tweak = D679E2EA3054E1
+PT = 99980459818278359406199791971849884432821321826358606310
+CT = 84359031857952748660483617398396641079558152339419110919
+
+
+Count = 44
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = 49CCB8F62D941E5684599ECA0300937B5C766D053E109777
+Tweak = 0BFCF75CDC2FC1
+PT = jaxlrchjjx
+CT = kjdbfqyahd
+
+
+Count = 45
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = 03D253674A9309FF07ED0E71B24CBFE769025E09FCE544D7
+Tweak = B33176B1DA0F6C
+PT = tafzrybuvhiqvcyztuxfnwfprmqlwpayphxbawpl
+CT = loaemzbgqkywkdhmncrijzildzleoqibtthdiliv
+
+
+Count = 46
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = 1C24B74B7C1B9969314CB53E92F98EFD620D5520017FB076
+Tweak = 0380341C425A6F
+PT = 6np8r2t8zo
+CT = HgpCXoA1Rt
+
+
+Count = 47
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = C0ABADFC071379824A070E8C3FD40DD9BFD7A3C99A0D5FE3
+Tweak = 6C2926C705DDAF
+PT = GKB6sa9g56BSJ09iJ4dsaxRdsMvo
+CT = gC0tTSdDPxM79QOWi+z+SNL9C4V+
+
+
+Count = 48
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = 1FAA03EFF55A06F8FAB3F1DC57127D493E2F8F5C365540467A3A055BDBE6481D
+Tweak = 4D67130C030445
+PT = 3679409436
+CT = 1735794859
+
+
+Count = 49
+Method = FF3-1
+Alphabet = 0123456789
+
+Key = 9CE16E125BD422A011408EB083355E7089E70A4CD2F59E141D0B94A74BCC5967
+Tweak = 4684635BD2C821
+PT = 85783290820098255530464619643265070052870796363685134012
+CT = 75104723514036464144839960480545848044718729603261409917
+
+
+Count = 50
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = 6187F8BDE99F7DAF9E3EE8A8654308E7E51D31FA88AFFAEB5592041C033B736B
+Tweak = 5820812B3D5DD1
+PT = mkblaoiyfd
+CT = ifpyiihvvq
+
+
+Count = 51
+Method = FF3-1
+Alphabet = abcdefghijklmnopqrstuvwxyz
+
+Key = F6807FB9688937E4D4956006C8F0CB2394148A5F4B14666CF353F4941428FFD7
+Tweak = 30C87B99890096
+PT = wrammvhudopmaazlsxevzwzwpezzmghwfnmkitnk
+CT = nzftnfkliuctlmtdfrxfhwgevrbcbgljurnytxkj
+
+
+Count = 52
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = 9C2B69F7DDF181C54398E345BE04C2F6B00B9DD1679200E1E04C4FF961AE0F09
+Tweak = 103C238B4B1E44
+PT = H2/c6FblSA
+CT = EOg4H1bE+8
+
+
+Count = 53
+Method = FF3-1
+Alphabet = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
+
+Key = C58BCBD08B90006CEC7E82B2D987D79F6A21111DEF0CEBB273CBAEB2D6CD4044
+Tweak = 7036604882667B
+PT = bz5TcS1krnD8IOLdrQeKzXkLAa6h
+CT = Z6x3/9LPW8SZunRezRM8J68Q4J03
+
+
+Count = 54
+Method = FF3-1
+Alphabet = 0123456789abcdefghijklmnopqrstuvwxyz
+
+Key = ef4359d8d580aa4f7f036d6f04fc6a943b806aeb6308271f65cf33c7391b27f7
+Tweak = 37373737707172
+PT = 89012123456789abcde
+CT = 0sxaooj0jjj5qqfomh8
+
diff --git a/testvectors/FPEtest.c b/testvectors/FPEtest.c
new file mode 100644
index 0000000..2f5c5ce
--- /dev/null
+++ b/testvectors/FPEtest.c
@@ -0,0 +1,167 @@
+/*
+ ==============================================================================
+ Name : FPEtest.c
+ Author : polfosol
+ Version : 1.4.1.0
+ Copyright : copyright © 2022 - polfosol
+ Description : illustrating how to validate NIST's vectors for AES-FPE mode
+ ==============================================================================
+ */
+
+#include
+#include "../micro_aes.h"
+
+#define TESTFILEPATH "FPE_FF1&FF3&FF3-1.tv"
+
+static void str2bytes(const char* hex, uint8_t* bytes)
+{
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
+ {
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
+ }
+}
+
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
+{
+ 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;
+ }
+}
+
+static int ciphertest(uint8_t* key, uint8_t* tk, char* a, char* p, char* c,
+ size_t n, size_t nt, char* r)
+{
+ char sk[2*AES_KEY_SIZE + 1], st[65], msg[30], tmp[0x800], t = 0;
+ sprintf(msg, "%s", "passed the test");
+#if FF_X == 3
+ AES_FPE_encrypt(key, tk, p, n, tmp);
+#else
+ AES_FPE_encrypt(key, tk, nt, p, n, tmp);
+#endif
+ if (memcmp(c, tmp, n))
+ {
+ sprintf(msg, "%s", "encrypt failure");
+ t = 1;
+ }
+ memset(tmp, 0xcc , sizeof tmp);
+#if FF_X == 3
+ AES_FPE_decrypt(key, tk, c, n, tmp);
+#else
+ AES_FPE_decrypt(key, tk, nt, c, n, tmp);
+#endif
+ if (memcmp(p, tmp, n))
+ {
+ sprintf(msg, "%sdecrypt failure", t ? "encrypt & " : "");
+ t |= 2;
+ }
+ bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(tk, st, nt);
+ sprintf(r, "%s\nA: %s\nK: %s\nT: %s\nP: %s\nC: %s", msg, a, sk, st, p, c);
+ return t;
+}
+
+int main()
+{
+ const char *linehdr[] =
+ {
+ "Method = ", "Alphabet = ", "Key = ", "Tweak = ", "PT = ", "CT = "
+ }, *alphabets[] =
+ {
+ "0123456789", "01", "abcdefghijklmnopqrstuvwxyz",
+ "0123456789abcdefghijklmnopqrstuvwxyz", "*", "*", "*", "0123456789abcdefghijklmnop",
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"
+ };
+ char buffer[0x1000], alpha[90], p[0x800], c[0x800], m[6], a = 0, *value = "";
+ size_t pass = 0, df = 0, ef = 0, sp = 0, st = 0;
+ uint8_t i, key[2*AES_KEY_SIZE], twk[32], sk = 0, n = 0;
+ FILE *fp, *fs, *ferr;
+
+ fp = fopen(TESTFILEPATH, "r");
+ fs = fopen("passed.log", "w");
+ ferr = fopen("failed.log", "w");
+
+ if (fp == NULL)
+ {
+ printf("File not found: %s\n", TESTFILEPATH);
+ return 1;
+ }
+ if (!fs || !ferr) return 1;
+
+ while (fgets(buffer, sizeof buffer, fp) != NULL)
+ {
+ buffer[strcspn(buffer, "\n")] = 0;
+ if (strlen(buffer) < 4) continue;
+ for (i = 0; i < 6; i++)
+ {
+ if (strncmp(buffer, linehdr[i], strlen(linehdr[i])) == 0)
+ {
+ value = strrchr(buffer, ' ') + 1;
+ break;
+ }
+ }
+ switch (i)
+ {
+ case 0:
+ strcpy(m, value);
+ break;
+ case 1:
+ for (i = 0; i < 9; i++)
+ {
+ if ((a = strlen(alphabets[i])) != strlen(value)) continue;
+ if (strncmp(value, alphabets[i], a) == 0) break;
+ }
+ strcpy(alpha, value); a = i;
+ break;
+ case 2:
+ sk = strlen(value) / 2;
+ str2bytes(value, key);
+ break;
+ case 3:
+ st = strlen(value) / 2; ++n;
+ str2bytes(value, twk);
+ break;
+ case 4:
+ sp = strlen(value);
+ strcpy(p, value);
+ break;
+ case 5:
+ ++n;
+ strcpy(c, value);
+ break;
+ }
+ if (n == 2)
+ {
+ n = (FF_X == 3) ^ (m[2] != '3');
+#if FF3_TWEAK_LEN == 8
+ n &= (st == 8); /* old FF3 with 8-byte tweak */
+#else
+ n &= FF_X != 3 || !(st == 8 && twk[7]); /* FF3-1 */
+#endif
+ if (n && a == CUSTOM_ALPHABET && sk == AES_KEY_SIZE)
+ {
+ n = ciphertest(key, twk, alpha, p, c, sp, st, buffer);
+ fprintf(n ? ferr : fs, "%s\n\n", buffer); /* save the log */
+ if (n == 0) ++pass;
+ if (n & 1) ++ef;
+ if (n & 2) ++df;
+ }
+ n = 0;
+ }
+ }
+ printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
+ pass + (ef > df ? ef : df), pass, ef, df);
+
+ fclose(fp); fclose(fs); fclose(ferr);
+ if (ef + df == 0)
+ {
+ remove("passed.log"); remove("failed.log");
+ }
+ return 0;
+}
diff --git a/testvectors/FPEtest.cbp b/testvectors/FPEtest.cbp
new file mode 100644
index 0000000..69ca338
--- /dev/null
+++ b/testvectors/FPEtest.cbp
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testvectors/GCMtest.c b/testvectors/GCMtest.c
index f943b51..75830bd 100644
--- a/testvectors/GCMtest.c
+++ b/testvectors/GCMtest.c
@@ -2,9 +2,9 @@
==============================================================================
Name : GCMtest.c
Author : polfosol
- Version : 2.0.0.0
+ Version : 2.0.1.1
Copyright : copyright © 2022 - polfosol
- Description : illustrating how the NIST's vectors for AES-GCM mode are used
+ Description : illustrating how to validate NIST's vectors for AES-GCM mode
==============================================================================
*/
@@ -13,36 +13,34 @@
#define TESTFILEPATH "GCM_EncryptExtIV128.rsp"
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void str2bytes(const char* hex, uint8_t* bytes)
{
- size_t i, j;
- for (i = 0, j = ~0; str[i]; ++i)
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
{
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
}
}
-static void bytes2str(const uint8_t* bytes, char* str, size_t len)
-#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
{
- size_t i, j;
- for (i = 0, j = 0; i < len; ++i)
+ 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[j++] = num2char(bytes[i] >> 4);
- str[j++] = num2char(bytes[i] & 15);
+ str[i] = bytes[i / 2] >> shr & 0xF | '0';
+ if (str[i] > '9') str[i] += offset;
}
- str[j] = 0;
}
static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t* c,
- uint8_t np, uint8_t na, uint8_t nt, char* r)
+ size_t np, size_t na, uint8_t nt, char* r)
{
- char sk[70], si[GCM_NONCE_LEN*2+6], sp[0x100], sc[0x100], sa[0x100], msg[30];
+ char sk[65], si[2*GCM_NONCE_LEN + 1], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[0x80], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_GCM_encrypt(key, iv, p, np, a, na, tmp, tmp + np);
if (memcmp(c, tmp, np + nt))
@@ -56,7 +54,7 @@ static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t
{
sprintf(msg, "%sdecrypt failure", t & 1 ? "encrypt & " : "");
}
- bytes2str(key, sk, AES_KEY_LENGTH);
+ bytes2str(key, sk, AES_KEY_SIZE);
bytes2str(iv, si, GCM_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
@@ -70,7 +68,7 @@ int main()
const char *linehdr[] = { "Key = ", "IV = ", "AAD = ", "PT = ", "CT = ", "Tag = " };
char buffer[0x800], *value = "", *line = "";
size_t pass = 0, df = 0, ef = 0, sk = 0, sn = 0, sp = 0, sa = 0, st = 0;
- uint8_t key[AES_KEY_LENGTH], tmp[AES_KEY_LENGTH], iv[GCM_NONCE_LEN];
+ uint8_t key[AES_KEY_SIZE], tmp[AES_KEY_SIZE], iv[GCM_NONCE_LEN];
uint8_t i, p[96], c[112], a[96], t[16], rc = 1;
FILE *fp, *fs, *ferr;
@@ -104,7 +102,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == AES_KEY_LENGTH) str2bytes(value, tmp);
+ if (sk == AES_KEY_SIZE) str2bytes(value, tmp);
break;
case 1:
sn = strlen(value) / 2;
@@ -128,7 +126,7 @@ int main()
}
if (i == 0 || line == NULL)
{
- if (!rc && sn == GCM_NONCE_LEN && sk == AES_KEY_LENGTH)
+ if (!rc && sn == GCM_NONCE_LEN && sk == AES_KEY_SIZE)
{
memcpy(c + sp, t, st); /* put tag at the end */
rc = ciphertest(key, iv, p, a, c, sp, sa, st, buffer);
@@ -145,7 +143,7 @@ int main()
}
} while (line != NULL);
printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
- pass + ef + df, pass, ef, df);
+ pass + (ef > df ? ef : df), pass, ef, df);
fclose(fp); fclose(fs); fclose(ferr);
if (ef + df == 0)
diff --git a/testvectors/OCBtest.c b/testvectors/OCBtest.c
index 3ca1353..bba7af5 100644
--- a/testvectors/OCBtest.c
+++ b/testvectors/OCBtest.c
@@ -2,9 +2,9 @@
==============================================================================
Name : OCBtest.c
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.1.1.1
Copyright : copyright © 2022 - polfosol
- Description : illustrating how the OpenSSL's vectors for AES-OCB mode are used
+ Description : illustrating how to validate OpenSSL's vectors for AES-OCB mode
==============================================================================
*/
@@ -13,36 +13,34 @@
#define TESTFILEPATH "OCB_AES128.tv"
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void str2bytes(const char* hex, uint8_t* bytes)
{
- size_t i, j;
- for (i = 0, j = ~0; str[i]; ++i)
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
{
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
}
}
-static void bytes2str(const uint8_t* bytes, char* str, size_t len)
-#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
{
- size_t i, j;
- for (i = 0, j = 0; i < len; ++i)
+ 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[j++] = num2char(bytes[i] >> 4);
- str[j++] = num2char(bytes[i] & 15);
+ str[i] = bytes[i / 2] >> shr & 0xF | '0';
+ if (str[i] > '9') str[i] += offset;
}
- str[j] = 0;
}
static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t* c,
- uint8_t np, uint8_t na, uint8_t err, char* r)
+ size_t np, size_t na, uint8_t err, char* r)
{
- char sk[70], si[30], sp[0x100], sc[0x100], sa[0x100], msg[30];
+ char sk[2*AES_KEY_SIZE + 1], si[31], sp[0x100], sc[0x100], sa[0x100], msg[30];
uint8_t tmp[0x90], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_OCB_encrypt(key, iv, p, np, a, na, tmp, tmp + np);
if (memcmp(c, tmp, np + OCB_TAG_LEN) && !err)
@@ -56,7 +54,7 @@ static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* a, uint8_t
{
sprintf(msg, "%sdecrypt failure", t & 1 ? "encrypt & " : "");
}
- bytes2str(key, sk, AES_KEY_LENGTH);
+ bytes2str(key, sk, AES_KEY_SIZE);
bytes2str(iv, si, OCB_NONCE_LEN);
bytes2str(p, sp, np);
bytes2str(a, sa, na);
@@ -71,7 +69,7 @@ int main()
{ "Key = ", "IV = ", "AAD = ", "Plaintext = ", "Ciphertext = ", "Tag = ", "Result = " };
char buffer[0x800], *value = "";
size_t pass = 0, df = 0, ef = 0, sk = 0, sn = 0, sp = 0, sa = 0, st = 0;
- uint8_t key[AES_KEY_LENGTH], tmp[AES_KEY_LENGTH], iv[OCB_NONCE_LEN];
+ uint8_t key[AES_KEY_SIZE], tmp[AES_KEY_SIZE], iv[OCB_NONCE_LEN];
uint8_t i, p[0x80], c[0x90], a[0x80], t[16], rc = 1;
FILE *fp, *fs, *ferr;
@@ -102,7 +100,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == AES_KEY_LENGTH) str2bytes(value, tmp);
+ if (sk == AES_KEY_SIZE) str2bytes(value, tmp);
break;
case 1:
sn = strlen(value) / 2;
@@ -130,7 +128,7 @@ int main()
}
if (i == 0 || i > 7)
{
- if (!rc && sk == AES_KEY_LENGTH && sn == OCB_NONCE_LEN && st == OCB_TAG_LEN)
+ if (!rc && sk == AES_KEY_SIZE && sn == OCB_NONCE_LEN && st == OCB_TAG_LEN)
{
memcpy(c + sp, t, st); /* put tag at the end */
rc = ciphertest(key, iv, p, a, c, sp, sa, i, buffer);
@@ -147,7 +145,7 @@ int main()
}
}
printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
- pass + ef + df, pass, ef, df);
+ pass + (ef > df ? ef : df), pass, ef, df);
fclose(fp); fclose(fs); fclose(ferr);
if (ef + df == 0)
diff --git a/testvectors/Poly1305test.c b/testvectors/Poly1305test.c
index 0c83f75..920fa20 100644
--- a/testvectors/Poly1305test.c
+++ b/testvectors/Poly1305test.c
@@ -2,7 +2,7 @@
==============================================================================
Name : Poly1305test.c
Author : polfosol
- Version : 1.1.0.0
+ Version : 1.1.1.1
Copyright : copyright © 2022 - polfosol
Description : illustrating how the test vectors of Poly1305-AES are processed
==============================================================================
@@ -13,41 +13,39 @@
#define TESTFILEPATH "Poly1305AES128.tv"
-static void str2bytes(const char* str, uint8_t* bytes)
-#define char2num(c) (c > '9' ? (c & 7) + 9 : c & 0xF)
+static void str2bytes(const char* hex, uint8_t* bytes)
{
- size_t i, j;
- for (i = 0, j = ~0; str[i]; ++i)
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
{
- if (str[i] < '0' || str[i] > 'f') continue;
- if (j++ & 1) bytes[j / 2] = char2num(str[i]) << 4;
- else bytes[j / 2] |= char2num(str[i]);
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
}
}
-static void bytes2str(const uint8_t* bytes, char* str, size_t len)
-#define num2char(x) ((x) > 9 ? 'a' - 10 + (x) : '0' + (x))
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
{
- size_t i, j;
- for (i = 0, j = 0; i < len; ++i)
+ 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[j++] = num2char(bytes[i] >> 4);
- str[j++] = num2char(bytes[i] & 15);
+ str[i] = bytes[i / 2] >> shr & 0xF | '0';
+ if (str[i] > '9') str[i] += offset;
}
- str[j] = 0;
}
static int ciphertest(uint8_t* key, uint8_t* nnc, uint8_t* d, uint8_t* m, size_t ds, char* r)
{
- char sk[2*AES_KEY_LENGTH + 40], smac[40], msg[30];
+ char sk[2*AES_KEY_SIZE + 33], smac[33], msg[30];
uint8_t tmp[32], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_Poly1305(key, nnc, d, ds, tmp);
t = memcmp(m, tmp, 16);
if (t) sprintf(msg, "%s", "failed");
- bytes2str(key, sk, AES_KEY_LENGTH + 16);
+ bytes2str(key, sk, AES_KEY_SIZE + 16);
bytes2str(m, smac, 16);
sprintf(r, "%s\nK: %s\npoly: %s\n", msg, sk, smac);
return t;
@@ -58,7 +56,7 @@ int main()
const char *linehdr[] = { "Keys = ", "Nonce = ", "Msg = ", "PolyMac = " };
char buffer[0x20100], *value = "";
size_t pass = 0, nf = 0, sk = 0, sd = 0;
- uint8_t i, n = 0, key[AES_KEY_LENGTH + 16], nc[16], d[0x10100], m[16];
+ uint8_t i, n = 0, key[AES_KEY_SIZE + 16], nc[16], d[0x10100], m[16];
FILE *fp, *fs, *ferr;
fp = fopen(TESTFILEPATH, "r");
@@ -88,7 +86,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == AES_KEY_LENGTH + 16) str2bytes(value, key);
+ if (sk == AES_KEY_SIZE + 16) str2bytes(value, key);
break;
case 1:
str2bytes(value, nc);
@@ -105,7 +103,7 @@ int main()
}
if (n == 2)
{
- if (sk == AES_KEY_LENGTH + 16)
+ if (sk == AES_KEY_SIZE + 16)
{
n = ciphertest(key, nc, d, m, sd, buffer);
fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
diff --git a/testvectors/README.md b/testvectors/README.md
index 4757103..dbd9728 100644
--- a/testvectors/README.md
+++ b/testvectors/README.md
@@ -1,6 +1,8 @@
### Testing µAES
---
-This folder contains some of the NIST's official [CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes) test vectors. The `*.rsp` files are courtesy of the NIST. Some sample codes are provided alongside them to illustrate how they are used. The test vectors of OCB mode are borrowed from [OpenSSL](https://github.com/openssl/openssl/blob/5a7bc0be97dee9ac715897fe8180a08e211bc6ea/test/evpciph.txt).
+This folder contains some of the NIST's official [CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/cavp-testing-block-cipher-modes) test vectors. The `*.rsp` files are courtesy of the NIST. Some sample codes are provided alongside them to demonstrate how they are used. As of late 2022, they have set up an [official repository](https://github.com/usnistgov/ACVP-Server) for cryptographic algorithm validation.
+
+To do some extra tests, a bunch of additional FPE test vectors are taken from [[1](https://github.com/ubiqsecurity/ubiq-fpe-c/tree/master/src/test), [2](https://github.com/mysto/python-fpe/tree/main/ff3), [3](https://github.com/0NG/Format-Preserving-Encryption)], and the OCB test vectors are borrowed from [OpenSSL](https://github.com/openssl/openssl/blob/5a7bc0be97dee9ac715897fe8180a08e211bc6ea/test/evpciph.txt).
Also in the `main.c` file of parent directory, you will find some other test vectors that are either generated by the [Crypto++®](https://www.cryptopp.com) library or taken from various online documents. Please let me know if you faced any issues in verifying them.
diff --git a/testvectors/SIV_GCM_ACVP.tv b/testvectors/SIV_GCM_ACVP.tv
new file mode 100644
index 0000000..8e022ee
--- /dev/null
+++ b/testvectors/SIV_GCM_ACVP.tv
@@ -0,0 +1,821 @@
+# ACVP-AES-GCM-SIV-1.0
+# Borrowed from ACVP-Server:
+# https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/ACVP-AES-GCM-SIV-1.0
+#
+
+
+Count = 1
+pt =
+key = 312E9DD81301647F47FA2E5281233EF1
+aad =
+iv = 9CA3721AAF612D03100095DC
+ct = 26CA12DDBCDE0D8AF9B0393EE8253392
+
+
+Count = 2
+pt =
+key = 5190547597E652810E047148EB0F83EA
+aad =
+iv = 795BC62FD83633F9FBDDD4EC
+ct = 5328711791D48874940B59E1C197F8AF
+
+
+Count = 3
+pt =
+key = E008596478366607798935C2B80C6251
+aad =
+iv = A6D4E66FFD4EAEC1D5BEB5A4
+ct = 733C162B9CDADFB41CF2E2F32D65B1A8
+
+
+Count = 4
+pt =
+key = 7651C6896ED51904583B2F146DCB425D
+aad =
+iv = F40FE960F35227B9620DA9E7
+ct = 6D9D69D2C64FF1BBA9CFFBFDB31CA254
+
+
+Count = 5
+pt =
+key = 7646382F186BC2CCA9808F28FAFD0FAD
+aad =
+iv = 1E4D23775A86FD8A7944FF09
+ct = 06382CF4365CAD7B06C629774124B5CA
+
+
+Count = 6
+pt =
+key = 00657B00613A2B6F7E0F29574F56035A
+aad =
+iv = BF7F42F9CACA0818D0E7DF29
+ct = 777BD4E3AF363DD94F4CBA0AF5CB60F7
+
+
+Count = 7
+pt =
+key = D0601288F6A219C5100951A9DD56424B
+aad =
+iv = 566667C37FF9591A07AE4445
+ct = 0BDE05F1B8BA4999B24F1B708F8B671F
+
+
+Count = 8
+pt =
+key = 54975987BD75990BDC81D74501E0E126
+aad =
+iv = 1869A0843830CFF0A0F4B6E3
+ct = F3EF2451336613F513E8E60A4DFB0E05
+
+
+Count = 9
+pt =
+key = 983985090BB929ECC2BE53A67E3F9B3C
+aad =
+iv = E2A2F703C37D0BDFCBE3DD67
+ct = 2F12D3EAB58F5B5C1FEABF60409CD51D
+
+
+Count = 10
+pt =
+key = 178C0842E749EF27B6644DF3415A508A
+aad =
+iv = 7C549CD9A5CB3E1040FAE641
+ct = 6D43942D85530602FB39E8CD1324D9B1
+
+
+Count = 11
+pt =
+key = 6D1BC37659AB04D77712899E5F3F87BE
+aad =
+iv = C95D8CE586387845A779CD4D
+ct = 0828C0296B2CB13C6E8ECAD60F4F287C
+
+
+Count = 12
+pt =
+key = 1B508785F2FEF4EFED4438F613827D7F
+aad =
+iv = C3CF0C1D9C598A2B682307B1
+ct = EC439F858169CAC36687FECC48756AB6
+
+
+Count = 13
+pt =
+key = 285F84901D011EA314A97937CD9481FC
+aad =
+iv = 8E4AE113E8AC08B4353A54CE
+ct = A71E479E751BBAF9A31278E3A3E4B7F6
+
+
+Count = 14
+pt =
+key = D7EB662EB29335E546DCB46F39C8D1E9
+aad =
+iv = 588B88F22BD213CEE3B21D50
+ct = 37ABA8E7CAAD44EB300A5B75BCE2E28E
+
+
+Count = 15
+pt =
+key = CF5EE8E7C7435AD05E6D264A2C507F62
+aad =
+iv = FD2CFA086E55499F8DECEB1F
+ct = 6DBA7D89D0E90163C09F5646D724C6C7
+
+
+Count = 16
+pt =
+key = 10C975B5BC0E62B93526BC81D348A533
+aad = C78763F666B789C626E3A7F34169E4
+iv = 29CE94A5F4A1C66059E93F1C
+ct = AF003692B8011D318C9AC4D5E3EE4958
+
+
+Count = 17
+pt =
+key = 5C13D25E6A588563E8718A4E118C171E
+aad = DDECE7EE7E28B90E8FD33D1D8E3A04
+iv = 6C8A666E5D2B3892383E7068
+ct = F78C376229C9D6FBF665D037000AB762
+
+
+Count = 18
+pt =
+key = 20C377120156198290930CCBD51D9AE6
+aad = DF8886FF4322EAB106F7270D85767E
+iv = 3799082343F6354D27D34094
+ct = AFAAE0FD0811DEAE234347E14D656831
+
+
+Count = 19
+pt =
+key = F9122C9A4D24B1C172CC3B3BAA834F76
+aad = 2633193282F1D8C1B68620EFA6AE40
+iv = 188800B4D9E041E69A025272
+ct = C1F0CF22A644A50C28C0F0859661AB4D
+
+
+Count = 20
+pt =
+key = 68662C5029454E7F7E9760082FBEECD4
+aad = 80CAFA5F9D22EE99F20A0397F1690C
+iv = 2264527E5AA1F3EBBAA0717B
+ct = B438173C7A1EDDB726351DBCE04F1B36
+
+
+Count = 21
+pt =
+key = A6317EDAD141FD8F682261B5C238BC83
+aad = C31E9A48215018E69DC7E894F5DB32
+iv = E80CE799D938F333071363AD
+ct = B2D51B5988532F960FEED61F238AFB38
+
+
+Count = 22
+pt =
+key = CC99D350B5EE4F15F13D1EFFC42442B4
+aad = D666592131A4A1E14A891104CC39D1
+iv = ECCC9687F82D38812C371C55
+ct = 2D517FDE4C35357529A5BB26A976524D
+
+
+Count = 23
+pt =
+key = DA9A2403052A6E1C2C7F477EA0694A8D
+aad = B332699F49A2F085D16FF95024E12A
+iv = 18A22FAE6084A7ED2E2B95AF
+ct = 8DA6230D1D2A83D9D702F70DE5CB05E5
+
+
+Count = 24
+pt =
+key = 06E169444D159001471D9DF841EF0E17
+aad = 74FE1B912029D3BD9162410483A388
+iv = B05A8FBAEE6EEC0CFAF3B6BB
+ct = 06714F9637CC64868E757AB442A4C908
+
+
+Count = 25
+pt =
+key = CD1DD32692EA23BFB53D20CB12192B28
+aad = C207F92CEBB62445C1D5EFC90BCDEE
+iv = 4282487F569B29C9F37F7273
+ct = 062351873C3B3A6ECC3B08C934D73109
+
+
+Count = 26
+pt =
+key = 382B1E3A6B8D24D9C3774DBE92BDD2EE
+aad = 15BA92D5A6A84C5E88B3735FEB5797
+iv = 3F3169C623FE9ECB97A1DF79
+ct = D2AC5BF3077FE6AA19BC955AA443BA33
+
+
+Count = 27
+pt =
+key = 2D54036DD744A19A3A45B8F3B21D7485
+aad = A72F9E70DAE2877F1CFED9F6F3D864
+iv = 86034FD2141B204F51FCEEEC
+ct = F09BAFD78883F4C7A5BA6FFCB4F636CF
+
+
+Count = 28
+pt =
+key = A21FA9FBAC7C58C9D58AE44E80F4658F
+aad = C8C57C4D21C5EEDB94EBC7CE605F7D
+iv = 20314BA58B8494EA2B2BFCBB
+ct = DD014E782EEF03FB56FFC5F160149226
+
+
+Count = 29
+pt =
+key = A14615E136702686335D6B018660CD06
+aad = 1FB46FEAF2628115C93CABEC929B07
+iv = 326F45E341240B7C3D4A52DF
+ct = 5F001BEDDCCCD304DD6FEF2B32242AE1
+
+
+Count = 30
+pt =
+key = 3D2C147B938E5AB851DCB28A38FD8410
+aad = 13E8F439415D89731D621BD216EAB0
+iv = 2AB889C6A4E983DB20515169
+ct = 0354282E336D8974654A50135F01FAB9
+
+
+Count = 31
+pt = AE69B95B1CAF65F1ABD0A8CEB43D10
+key = 37204932035A61997A9AF1F4E1825084
+aad =
+iv = 734AA6722506BB50DDD3D5E4
+ct = 9DBA45471EF43DC292185089653BBA3870EDC07971B04B9615EA3D5860A59A
+
+
+Count = 32
+pt = 1BCE62672D91B3130634B8E25EBBB8
+key = C549658540F30B1852D874E767BFFC12
+aad =
+iv = D65063721BE490551C06B3AC
+ct = 79900966E3987337A6A34BABF23032CC10417D036E7471DF2E3170EE5BE4C0
+
+
+Count = 33
+pt = 16C7CB49E57CED7D53816AC375F804
+key = 7C1F59EB0E5CF52E93305D3D844E9684
+aad =
+iv = 845214D1E0459257AE3ECBF5
+ct = 581603997A475AD5A54059C59EE0A21B733650C4D8DCABE473B8CD8CC5AB8A
+
+
+Count = 34
+pt = DBD1EA273AB50A339F0C83D46C22D3
+key = 53F2648A1F8F10992CBA536254F5FB18
+aad =
+iv = F0DB358FC2B636BB24F7F3EE
+ct = CF0C845CAD06E3DA1700624A13352C03D8663A3DEEA0B93BFD5265E1DA79AE
+
+
+Count = 35
+pt = CAD687F39A3CDFAAC39FFDFA89882F
+key = 6CEE09CEE81AA6F22FA8B0968D1EF9C9
+aad =
+iv = 5707B836DCAEB1603502BA69
+ct = 93EC3E489719355A7C4710372A3ABB940260FD01C7640C2A697AE787B0F8E2
+
+
+Count = 36
+pt = A96F3462E2FDD39121E652445AD3E3
+key = CFCF80205076132C350B1331B4B33BF6
+aad =
+iv = D31D1E3135BB5906FC1AB280
+ct = C94D093A91E38D5C2ADD44EE9BE74BA780EBCC6233C935BC340CC91D503E29
+
+
+Count = 37
+pt = 07DF5CD2752A8B8071100E55225969
+key = E8A5E66EBE9C5B102DCF9DEFCBB15B10
+aad =
+iv = 487C0025031BF87FDEA8F895
+ct = 7D930FE2A18C858DC926DCC149885D8D7EF4A1A5FC8E96C9690625CD2CBBA9
+
+
+Count = 38
+pt = D9A3B1D5CDA49A6101C3CB2BE027EF
+key = D4FD713511701AD948930C125C73C3B1
+aad =
+iv = EB147D73CDDD431B0755C4A0
+ct = 1DAABE15498C48E981B859BFCBA0BD7D6300CD3B424D41283E569B590A2D4C
+
+
+Count = 39
+pt = 14C6BB12C0DD74C035B4B2399C458D
+key = 7A7B1E31027541E21ABA3DA4C45E2307
+aad =
+iv = 23784F5459808DA635DBB0AE
+ct = D39FBD45D310EBB7771A5412AF04C6E359BC3138AD2EDF3EE6E60F64772DD3
+
+
+Count = 40
+pt = 0AA63037DFE7C1A00436289A5F5E31
+key = E61969501C05819082444C7D3E373DBC
+aad =
+iv = 0C3B31FBC102BEA968D66F4D
+ct = E8660D107C6826A7C36ED08526F3629306E60C1048F3FB1C17DD343075C453
+
+
+Count = 41
+pt = C38FFF9C3245BAC5BD3BC0F8D4A0F3
+key = 5286BDA9D71251A32118F1C6FB9D8293
+aad =
+iv = 50083106C250AAB6A866C2FA
+ct = 400325C371D1C97DF46176A787C50FB52C70297CE4BFEFD9AC7CD005DFBE7A
+
+
+Count = 42
+pt = 51EAD86C1740AF4EB7A1D21D6650EE
+key = B4D6080CC4FBABB30374CD2A0C4BF848
+aad =
+iv = 2F13DEEF600572921D3B4A59
+ct = EB95C4710A2182BCFC99FEF7DE044374E69C5BED8801F51F8215DF68646D65
+
+
+Count = 43
+pt = EB5FDA504097C5B2C97920B28C130A
+key = 480E13A3E65ADFBB36017E26B886A28F
+aad =
+iv = 1A5690EA5884DAF36FE361DC
+ct = FAE5559764C88BFDEFE09CC65C0D331AE84E5B139071663C51D7BCCBB9214F
+
+
+Count = 44
+pt = D0DD0927AE2EE95BBEC261FA6E750D
+key = CD2D1EB5F7F0F7EF644EB79E2592C5D2
+aad =
+iv = 5FB355E18460714629E62896
+ct = F211B200512AA3B3B42732A5F6FF01EE46D91312299CAE0A4C9090CF762816
+
+
+Count = 45
+pt = 634BE17EEB796791B83CA2A23A80BC
+key = 40D45979CC394526AD5D167174FCB5B1
+aad =
+iv = 89D854E5C2B044D9E47320BF
+ct = 673FC112E62EA83E43FA6057183DA21803C099AF11123A1CFA752F220D51C3
+
+
+Count = 46
+pt = D2F619F7AB5C934D12DD99C89CF07B
+key = C53245E21FACF3334B6117CE14ECF4C3
+aad = 69A519D90D20A2CEF263C50B004891
+iv = C0A552AC86C773A8B1CA772C
+ct = DE0CB428F324355C014DF626F1DE65B29FB6CAAE4E2CE208306837E5C250D1
+
+
+Count = 47
+pt = 65DE049BD1019D26E9B0A97ACB27B6
+key = 894F6757F3D78C49A1C544B4435D966F
+aad = 8186F1F46B76491EFE90CFD8EE7E09
+iv = 23643B0A317734F950E0C20E
+ct = 3625F5FBC5B8DA8192EFBA5EEF670B4E62698893CD5F4FAF3ACCA19A7E459F
+
+
+Count = 48
+pt = B92AD2A4FE33A4A075F7190FD01C89
+key = 7005A27A6D91DF621162F9A204B23CF7
+aad = 6E0B262AD64AA11C88D47B6237B17B
+iv = D5DAA93AE86570C69096C554
+ct = 8BFB347853CE25818C419ED3A5E854D715A0F4951C1831803155E8877489BC
+
+
+Count = 49
+pt = 589A8CFA4508CFC86774CCCFF582AA
+key = 180F0CB3B8F61878BB44CEA0B1F90172
+aad = 7DC7654547433F3FEA30D89068D5CA
+iv = 462248B6ECB9D0213F6FF32B
+ct = 3DD2CE9B4172AA2335B6443D1E5B327CC65B34026E1BDE5162F0794BA8CD31
+
+
+Count = 50
+pt = D8548D45C0C4CA8DCD60DD047D5084
+key = 294F1B11A8322F7EFE3FB08776C977B2
+aad = FE5244CD4381404A8BAF1B92893EE8
+iv = 202A9E1BADBD13FFD9848970
+ct = 045FF919DE8CF74E6A73349AF92BD600C0DFC9C1E98F20404B003CCD420DFF
+
+
+Count = 51
+pt = B24D790797F8BD9CF10AD92C8860CD
+key = 1CEBF2D5BFCC9C22BD8BD846AADDD772
+aad = 65A24157CD33128992C044A434B261
+iv = F73A1602EBCE22533545BA4C
+ct = 8B6F77842F85C90BBA577C7CC70F2B06386C8CF01F54C76CFD6D8E7C9A7863
+
+
+Count = 52
+pt = B956716E6EEAC8C374A28AEE15D851
+key = 552F0BC063ACB738588D992ED58939F6
+aad = DD7FC42F4BF87BBD231633B979E38A
+iv = 98EF0240CF3CF6566C72AC7A
+ct = 3B9F9DFC85122CC77319D2D81A559B7477C8E22363EE3B6182108FCE44939F
+
+
+Count = 53
+pt = 0D48A1375B1D061AEFC0BCB4BBD5B6
+key = 2AACE8D8CF2182E065B0A2F1FEAB58FB
+aad = DB6F06DBD66699EF4731F749F97D73
+iv = 61BADA856694FA1602525ADA
+ct = E76B6C0ED800033E9A9090585338C6E1E2054731A2A780125DFCD1E2B87E7B
+
+
+Count = 54
+pt = 4CB3C38953E580835E52E9F0E5BF0C
+key = D5088794E02462C8FDAFF91902275D09
+aad = 1CC25D27BFA6BA20D7393F4A052E08
+iv = 8BBF07A771FF504A59466E55
+ct = 24DB3DB4667B69DF4C3B8628564C271C745CF97E9991CA908D28B8F25E396F
+
+
+Count = 55
+pt = D1519C07EC79251DE230ABC85E58A5
+key = 1AD333F14AEBBB3D7FFC824D3F571A2B
+aad = 21D9A9E17EE186F30E8F81EE0C4365
+iv = F95BF0350A666747FEB68668
+ct = 9900CB8374E2A28DEAE719DE29DBD792FE578468511879612254CCC6AAC720
+
+
+Count = 56
+pt = 63EA6923C3F01F6BF7547D09BAA529
+key = 86250A3603F1E53B130D70946D0ADBCA
+aad = 7E911CD3EF577B60C7F681BCB9A875
+iv = 50DB67FE6570A63D27035294
+ct = 9BEE504C2F29E8FCEA46E7707C6A21B23F34DA82C2DBFF56994AFFEBD2EE20
+
+
+Count = 57
+pt = 45C301F7454EDC80F25A3216F09A31
+key = 77847490BDA0A7D8D88962F24EE71678
+aad = 17C2A8797DB7F3BFED542B463AB2FA
+iv = 1CFD810788C395CB631EA6FC
+ct = 247BBA1D8FA0CEE04C2AA031AE6347E80F317B8254EE10DA7B9616A2E01D36
+
+
+Count = 58
+pt = B7BB2CF3FFDE5018DA47462D10528F
+key = 9480A0754D0A37DA75C89AA3F27DF8D3
+aad = 35DDC612A02BEEA90FC79BE056EC5D
+iv = 42000392A4879DEA79FD0D4C
+ct = F084E14CF7F137610457C9496317BDC6AF096FC6646FF927342FAB13FC00CB
+
+
+Count = 59
+pt = A55A0B39CA6EF8A6707BA0E850577D
+key = D00D3C14593102EF99A490C22D640004
+aad = 60BDD99084450E6B51EA44AA7B8E09
+iv = 771092977218771860AD791B
+ct = E957075B3C0E687827A5F241DD70FB3554DA07C153C5274E55D2700423409F
+
+
+Count = 60
+pt = 162CDA0CA126A51E26CBCB39CA8124
+key = 8E2DCC4E2CD80BF2078E4428046A1AD1
+aad = D879965AB0F4B5D3E55F04973528B1
+iv = 372958673FAE957E090D375B
+ct = DC71A1C146BF3924EF3B5D0950CEF3473DEB505C82B68F0406BEBC95B86D2D
+
+
+Count = 61
+pt =
+key = 40B1BAC332016315249223BB0B736AFC
+aad =
+iv = 98BD87707CE1028177CD64C1
+ct = 57F3B1509E2A65D2C77E90449D96446C
+
+
+Count = 62
+pt =
+key = D74569E0739BCEEB5EAFD704EB60C6E9
+aad =
+iv = 82C6B15CB381CB69AE81F4C4
+ct = 5632DB3F68EE84CD204B2EE927CEBF24
+
+
+Count = 63
+pt =
+key = BE56E8790B567BA6ADD94C27AB0A2F63
+aad =
+iv = 56F7EBF35F3EC2E8D6F5A3D0
+ct = 69C0A9138A356BB7D24AC53659931A76
+
+
+Count = 64
+pt =
+key = 5BB55DB9015A7D1BFD1078FCCA72C48E
+aad =
+iv = 1AE7B05BA0D95D9AF4243A12
+ct = 09DE92C66434B95C58B10E549BF3377C
+
+
+Count = 65
+pt =
+key = 18DDD9EBB5AD3C08AA5269012383F4A4
+aad =
+iv = 441D6CA2E27E570C4AEB3C93
+ct = 23FD530A2EC1F5644EC54A23FF678D2E
+
+
+Count = 66
+pt =
+key = E7CD55F4E8E1E3D065658FAF50335DD3
+aad =
+iv = BAA21CB52C2B63612BD5B6A5
+ct = A42F99E1CAC0BD1ECC1B7B14BB91D111
+
+
+Count = 67
+pt =
+key = 487E320BE85FFF2EAC1054AF1C83C45D
+aad =
+iv = D9F920EEB676317241C9D8DC
+ct = B31B592F87A9EE89EEFD5EAB402E314E
+
+
+Count = 68
+pt =
+key = 465E52E37960E25048D6580C619C916F
+aad =
+iv = 84C4863C925A6C26DD6C6570
+ct = 46C7E95C1A62070DC7B4C189744292B7
+
+
+Count = 69
+pt =
+key = 6EA56B2426C365D12F6AFA60C0508B23
+aad =
+iv = 0AC4424081352C939EBC952D
+ct = AEF8F30F4E66794A24241468745C2647
+
+
+Count = 70
+pt =
+key = B63B242B91BD655AA56D18BF7CF12C70
+aad =
+iv = 8A67BFF4E67E87692C8D919F
+ct = 63104E5F1E8315A8E4ED277C61C045A2
+
+
+Count = 71
+pt =
+key = 94BAFDFF63E9FEC2F49499B7B33EDD36
+aad = B6EEF5FF384E01F10519D7A8436082
+iv = DA71E8A92FF23E55CDF4AA2C
+ct = 009029026752181F82941888DC224C81
+
+
+Count = 72
+pt =
+key = D41A5B2E02C7BB03C29AF33A4CAADFEA
+aad = BDDFA69C4ED87406B5570764483648
+iv = EDE81BCD9E8FA4625D53174E
+ct = CDF63B57A78FF27CB5D2725BAFC7423B
+
+
+Count = 73
+pt =
+key = 1D20D7188D36ED09EC19DFA4291B94C7
+aad = 71C3A89DCD75B71B3934EDC3FA08F0
+iv = 81C56866241ACF74D4EEFEB7
+ct = 984DF62F7A4F057A7C747DD0D71D8227
+
+
+Count = 74
+pt =
+key = 4EDCC3BB5B522127C3C0B085A6BD66EC
+aad = 287C30984EDE6B4B1C4538BA2A342C
+iv = D5F5EB378BE2A1C5F4245997
+ct = 0846218D0BA3F3C034E5BA2C2CFD9479
+
+
+Count = 75
+pt =
+key = 1852FD7DAA2B69F3F254394328B28F9A
+aad = CBF80AC13D886F1FCEFEACEBB86B7B
+iv = 8BC291505D02556833105999
+ct = 7627DF35527BB8EB40DD31EE13DDE79B
+
+
+Count = 76
+pt =
+key = A8F2084F5F17334D4BDBD2A91C4B0C8F
+aad = E767852490FAB6DE3FBDB0F4EEED18
+iv = 0A6160157A27686F5C949E2F
+ct = 8EF25446DADC3932B3AB0967DDBF8557
+
+
+Count = 77
+pt =
+key = 4906D1E527F545ADB89D8B208142602D
+aad = 46354F8DEAE01DB44DB68008D76F0D
+iv = 34F113C992AE23455F32D170
+ct = BB0807686CA263065C5F1073C2B29384
+
+
+Count = 78
+pt =
+key = D204CD158EE53237B75F2CFC06DEF93B
+aad = 30FE107C57A0C1CE7055B62DC86C13
+iv = F41DBC259A1CF75C362DA7BB
+ct = 012992B45A0DBB0AAAE820C765509F97
+
+
+Count = 79
+pt =
+key = 4B83E3298DF106E56D2D1C778ECC231A
+aad = 8795156E81445697AC9DAA4F40F048
+iv = D48429B20968BF4F40A3AD19
+ct = CFBC213C494D654752AFD4DE6719421D
+
+
+Count = 80
+pt =
+key = 3FE144DC44E58FDDDDACB1EC98E40349
+aad = 4FEBC0620884D82150F5C65E26B14F
+iv = 1B11365CBFD7B769CBA46A0F
+ct = 00F5B2BF7265A29585A821AE95791A50
+
+
+Count = 81
+pt =
+key = 9A6F32834B5C9270BCD7326892DC514B
+aad = 496D5DF96C620EE63F587849C38C0A
+iv = B9E290A6752298F6F297EABB
+ct = A86C41DA3D91A36326806623F2E62E47
+
+
+Count = 82
+pt = 090FEBF888B1CF851E63C1C023B34A
+key = D8F571DE92C8F7E68B41BA6172BA28CF
+aad =
+iv = D8BE421E18B0C4F6E5378766
+ct = 7BD7382D3228AE554B7184E467041FC0FF796277718191C854746812A0E674
+
+
+Count = 83
+pt = E7B648111446C5407701CB1538D9F9
+key = B603121200C770DECEC08E437892A4F8
+aad =
+iv = 4673736B55909EB6B4587870
+ct = 04A9F3E8BA245264D23A209B97DC2F1B0A2D7D569D9384F7073EFA5470D77B
+
+
+Count = 84
+pt = 76CF6C5E1CFB20A40E48F070F5B85A
+key = 78D265B62EC59FA41B5389F8E06D511D
+aad =
+iv = CC20DE0D3960D38A132FDF1F
+ct = 91503C83DE0603A75D8D43AE1A6652C96B631E67EDC32303B5BCB1F506FD58
+
+
+Count = 85
+pt = 69E1FB348943EE36BF626CCE902F93
+key = DEDAF6B443140FE5ADF869586AB302DA
+aad =
+iv = 7228BEBDC47D155BF0CB25AE
+ct = DCCA9B58A1C0E0ADD603D3FE1AA958BECA9195295962ABB886B30560C48A9D
+
+
+Count = 86
+pt = 42D20CCD61D8510E93C2002DA3519D
+key = 646AA7D3C6EE11D4EE36E271A4267812
+aad =
+iv = 8235AB5AC1F3D24EC7F47A89
+ct = BA5758A951826E2857138C58F3DAEC5A8E7135DC5B9CE779FB01DAAD479A1C
+
+
+Count = 87
+pt = 637DB0554AA8C8D58C7D4E88959D7D
+key = 479CFFD6D766BB3FA99576A8B88DC543
+aad =
+iv = 0F16DAB1640BA047C88329E6
+ct = ADE3FB4372F68E16D1398880DB1F4830546BC20236DE14C7D7E186AE826C40
+
+
+Count = 88
+pt = 414059A01DEEE201C85D8BDF6773DC
+key = F5E624F4713A4F12FE45DD7C8A0E97E7
+aad =
+iv = 394EBE28661E8C7B118069E9
+ct = 024A0DBC6D778D231CE2468128D677C317F9161F9BD61F0C06C5992E7AF6B8
+
+
+Count = 89
+pt = 8E864F35149742C891686EA47CA8B1
+key = 19D749F1FE62F140F35F6FDE17FE13C9
+aad =
+iv = 8D97801F88FD9D1D5FB2EB42
+ct = 653DC96E2CA456046995B82B35FCBE2A79F96C9EC65B742688C51C353AB25B
+
+
+Count = 90
+pt = 00A02B11532FC09E7F1B2034F6E979
+key = 6296913323D8E20C100C5DBE6C426887
+aad =
+iv = C2040995395BC305F4770DDE
+ct = 8A8B45621F7DC4535160AE801D46EB0FB72D870AF540F600836AC1BEB55A19
+
+
+Count = 91
+pt = B3159AAC85CED9FD38886F86E61D7D
+key = 8A24BADBF200200719E2C73004D64DA1
+aad =
+iv = 1FB9A7B46EF5AEDC89500BC0
+ct = BAEB6182C534D59074994C467AC46556DDE4308B9F4898171C707C4BF9FDB1
+
+
+Count = 92
+pt = 67E6E1B2AB862ACB283C0C8EBE62A8
+key = BC374CB6C93E71EA3B158E37067A9A16
+aad =
+iv = 26C42C388B58941F668B1682
+ct = 65E795EAF5A4AB84F14D401B38557D627FF3C38331B4CC3DBB4335ADD2C4BD
+
+
+Count = 93
+pt = C93C270900557C3BD76944F2060D91
+key = 1F53A1770A1329B47021D9DA1340D0F9
+aad = 529C6F4CFEAB024D1FE787CEDC3631
+iv = E99C1E08999FC1E9556568FB
+ct = 887C460AC255F41DFD66099F6D78852FEF2FC2BCC2EBC408C49A155F05AE49
+
+
+Count = 94
+pt = 4664D3C18C0061924C0FA3900F321E
+key = B36E51F1BE198D7EEF00CD2468730ECD
+aad = 90421DB62EAC5ED2774CF3DA7C3EF5
+iv = 1A8C0DDB6ACBE6FC74AC0B28
+ct = 501FAF2DFB13821D8A905F4E82E9948A96E70D64780CF11DC43232311D8475
+
+
+Count = 95
+pt = 42FE2758E60F81C75B339BC3563D22
+key = C69056657B404EE5369723E6B93E11AF
+aad = 71068A344D2198CAB7C160EDC5EC55
+iv = 2AD1C9426EA551260207B3D8
+ct = 735C70B66CB30D0317B8AC9107E16E517E35FABE51A45BFF4146969760217E
+
+
+Count = 96
+pt = C97D063C9AFB8A514FC5841AB02BC3
+key = ACA69C6E615AB919E399AE8E33DD4833
+aad = 9648294B4E59676CD519719149EE25
+iv = 1E8A4E4195C6FF10C0E68907
+ct = 8D870B64593A73D1764F0CB89A131B10AB20D22699D8F07F1E2FE36B5DB5FD
+
+
+Count = 97
+pt = 2FECE5F79F1575595430068508C83A
+key = 4FF13FA305438B2C3BF628E30500E7A2
+aad = DC8D44B409E2EE97868921A9DC9D07
+iv = 19E0B03B83E16594F05BA550
+ct = B5AB3C431766758C599A674A6420742BEF36AC5DCA50CC51F48D92731D6C8D
+
+
+Count = 98
+pt = 7F10BE63B76A5892B1091665BCB3AD
+key = 440D65618AB422FE1860BB3C09CA7103
+aad = BD9B4CA4764B17135CF2356A83702B
+iv = 759B6DABE18A3B3CB6EE0449
+ct = CDF0CB84D91F68A767ED8F02DE95E775A997589F259C3E9AC5F1AB57D1C963
+
+
+Count = 99
+pt = E7404ED214DC1CCBF1268477E60BA9
+key = 0B73FC3CE8732D46245025F43C57D8D0
+aad = 9FE659C7973708199AA36ED93B5243
+iv = CED56F8EED1E74CA90E8E169
+ct = F1A07582D3A7E8BB864F9353DCF7623047120A4B6ACC544CCAE3EAF37176FA
+
+
+Count = 100
+pt = 60A936A965FA2211BB26A64D6F5C4A
+key = 79B84E462EA22DA5D799A08C667A29DF
+aad = CA84B029D1266B5C59179B71D06852
+iv = 4A09074FB25E957A2C492B11
+ct = 8028ADD00BC82C02CCC07355EA58DD02CEF10B5398B2F7CC9C594130FBA0E7
+
+
+Count = 101
+pt = B33BB551E6874FC56C2FCB94B7792F
+key = 5EF776152C71269C4AD27D6B7FA06A0B
+aad = 1A2F5D2F2118DFB57C4A61680ECC63
+iv = F2546A1A2569AA781045D2D7
+ct = DF3DB8F1756A2D885C7E242B3ABBF3BCE6728905DF9B7E53F0B42FCBF4C6BF
+
+
+Count = 102
+pt = F2478134B8BC1FB3934FE4B4E16429
+key = 969B3BAD443AC754F0C96F2BBD7B243F
+aad = 8C735FF16B8BAE270E671FEAA160B4
+iv = 71965AD63AD56DDD6B6568C7
+ct = 2A0017A8E139195463F05AD246757867D01C5DB239C9B5D36A7C3C870F9E5C
+
diff --git a/testvectors/SIV_GCMtest.c b/testvectors/SIV_GCMtest.c
new file mode 100644
index 0000000..7b13df5
--- /dev/null
+++ b/testvectors/SIV_GCMtest.c
@@ -0,0 +1,143 @@
+/*
+ ==============================================================================
+ Name : SIV_GCMtest.c
+ Author : polfosol
+ Version : 1.0.1.1
+ Copyright : copyright © 2023 - polfosol
+ Description : demonstrating how to validate ACVP vectors for AES-GCM-SIV mode
+ ==============================================================================
+ */
+
+#include
+#include "../micro_aes.h"
+
+#define TESTFILEPATH "SIV_GCM_ACVP.tv"
+
+static void str2bytes(const char* hex, uint8_t* bytes)
+{
+ unsigned shl = 0;
+ for (--bytes; *hex; ++hex)
+ {
+ if (*hex < '0' || 'f' < *hex) continue;
+ if ((shl ^= 4) != 0) *++bytes = 0;
+ *bytes |= (*hex % 16 + (*hex > '9') * 9) << shl;
+ }
+}
+
+static void bytes2str(const uint8_t* bytes, char* str, const size_t len)
+{
+ 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;
+ }
+}
+
+static int ciphertest(uint8_t* key, uint8_t* iv, 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];
+ uint8_t tmp[0x90], t = 0;
+ sprintf(msg, "%s", "passed the test");
+
+ GCM_SIV_encrypt(key, iv, p, np, a, na, tmp, tmp + np);
+ if (memcmp(c, tmp, np + 16))
+ {
+ sprintf(msg, "%s", "encrypt failure");
+ t = 1;
+ }
+ memset(tmp, 0xcc , sizeof tmp);
+ t |= 2 * GCM_SIV_decrypt(key, iv, c, np, a, na, 16, tmp);
+ if (t > 1)
+ {
+ sprintf(msg, "%sdecrypt failure", t & 1 ? "encrypt & " : "");
+ }
+ bytes2str(key, sk, AES_KEY_SIZE);
+ bytes2str(iv, si, 12);
+ bytes2str(p, sp, np);
+ bytes2str(a, sa, na);
+ bytes2str(c, sc, np + 16);
+ sprintf(r, "%s\nK: %s\ni: %s\nP: %s\nA: %s\nC: %s", msg, sk, si, sp, sa, sc);
+ return t;
+}
+
+int main()
+{
+ const char *linehdr[] = { "key = ", "iv = ", "aad = ", "pt = ", "ct = " };
+ char buffer[0x400], *value = "";
+ size_t pass = 0, df = 0, ef = 0, sk = 0, sp = 0, sa = 0, n = 0;
+ uint8_t key[AES_KEY_SIZE], iv[12], p[80], c[96], a[80], i, j = 0;
+ FILE *fp, *fs, *ferr;
+
+ fp = fopen(TESTFILEPATH, "r");
+ fs = fopen("passed.log", "w");
+ ferr = fopen("failed.log", "w");
+
+ if (fp == NULL)
+ {
+ printf("File not found: %s\n", TESTFILEPATH);
+ return 1;
+ }
+ if (!fs || !ferr) return 1;
+
+ while (fgets(buffer, sizeof buffer, fp) != NULL)
+ {
+ buffer[strcspn(buffer, "\n")] = 0;
+ if (strlen(buffer) < 4) continue;
+ for (i = 0; i < 5; i++)
+ {
+ if (strncmp(buffer, linehdr[i], strlen(linehdr[i])) == 0)
+ {
+ value = strrchr(buffer, ' ') + 1;
+ break;
+ }
+ }
+ switch (i)
+ {
+ case 0:
+ sk = strlen(value) / 2;
+ if (sk == AES_KEY_SIZE) str2bytes(value, key);
+ break;
+ case 1:
+ if (strlen(value) == 24) str2bytes(value, iv);
+ break;
+ case 2:
+ sa = strlen(value) / 2;
+ str2bytes(value, a);
+ break;
+ case 3:
+ sp = strlen(value) / 2;
+ str2bytes(value, p); ++n;
+ break;
+ case 4:
+ str2bytes(value, c); ++n;
+ break;
+ }
+ if (n == 2)
+ {
+ if (sk == AES_KEY_SIZE)
+ {
+ n = ciphertest(key, iv, p, a, c, sp, sa, buffer);
+ fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
+ if (n == 0) ++pass;
+ else
+ {
+ if (n & 1) ++ef;
+ if (n & 2) ++df;
+ }
+ }
+ n = 0;
+ }
+ }
+ printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
+ pass + (ef > df ? ef : df), pass, ef, df);
+
+ fclose(fp); fclose(fs); fclose(ferr);
+ if (ef + df == 0)
+ {
+ remove("passed.log"); remove("failed.log");
+ }
+ return 0;
+}
diff --git a/testvectors/SIV_GCMtest.cbp b/testvectors/SIV_GCMtest.cbp
new file mode 100644
index 0000000..4fb7dd1
--- /dev/null
+++ b/testvectors/SIV_GCMtest.cbp
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testvectors/XTStest.c b/testvectors/XTStest.c
index 4a808e0..6b31c60 100644
--- a/testvectors/XTStest.c
+++ b/testvectors/XTStest.c
@@ -2,9 +2,9 @@
==============================================================================
Name : XTStest.c
Author : polfosol
- Version : 2.3.0.0
+ Version : 2.3.1.0
Copyright : copyright © 2022 - polfosol
- Description : illustrating how the NIST's vectors for AES-XTS mode are used
+ Description : illustrating how to validate NIST's vectors for AES-XTS mode
==============================================================================
*/
@@ -37,11 +37,11 @@ static void bytes2str(const uint8_t* bytes, char* str, size_t len)
str[j] = 0;
}
-static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* c, uint8_t n, char* r)
+static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* c, size_t n, char* r)
{
- char sk[4*AES_KEY_LENGTH + 16], si[40], sp[0x80], sc[0x80], msg[30];
+ char sk[4*AES_KEY_SIZE + 1], si[33], sp[0x80], sc[0x80], msg[30];
uint8_t tmp[0x80], t = 0;
- sprintf(msg, "%s", "success");
+ sprintf(msg, "%s", "passed the test");
AES_XTS_encrypt(key, iv, p, n, tmp);
if (memcmp(c, tmp, n))
@@ -56,7 +56,7 @@ static int ciphertest(uint8_t* key, uint8_t* iv, uint8_t* p, uint8_t* c, uint8_t
sprintf(msg, "%sdecrypt failure", t ? "encrypt & " : "");
t |= 2;
}
- bytes2str(key, sk, 2*AES_KEY_LENGTH);
+ bytes2str(key, sk, 2*AES_KEY_SIZE);
bytes2str(iv, si, 16);
bytes2str(p, sp, n);
bytes2str(c, sc, n);
@@ -69,7 +69,7 @@ int main()
const char *linehdr[] = { "Key = ", "i = ", "PT = ", "CT = ", "DataUnitLen = " };
char buffer[0x800], *value = "";
size_t i, n = 0, pass = 0, df = 0, ef = 0, s = 0, sk = 0;
- uint8_t key[2*AES_KEY_LENGTH], iv[16], p[0x80], c[0x80], ul[2];
+ uint8_t key[2*AES_KEY_SIZE], iv[16], p[0x80], c[0x80], ul[2];
FILE *fp, *fs, *ferr;
fp = fopen(TESTFILEPATH, "r");
@@ -99,7 +99,7 @@ int main()
{
case 0:
sk = strlen(value) / 2;
- if (sk == 2 * AES_KEY_LENGTH) str2bytes(value, key);
+ if (sk == 2 * AES_KEY_SIZE) str2bytes(value, key);
break;
case 1:
str2bytes(value, iv);
@@ -119,7 +119,7 @@ int main()
if (n == 2)
{
s = (ul[0] >> 4) *100 + (ul[0] & 15) *10 + (ul[1] >> 4);
- if (sk == 2 * AES_KEY_LENGTH && s % 8 == 0)
+ if (sk == 2 * AES_KEY_SIZE && s % 8 == 0)
{
n = ciphertest(key, iv, p, c, s / 8, buffer);
fprintf(n ? ferr : fs, "%s\n", buffer); /* save the log */
@@ -131,7 +131,7 @@ int main()
}
}
printf ("test cases: %d\nsuccessful: %d\nfailed encrypt: %d, failed decrypt: %d\n",
- pass + ef + df, pass, ef, df);
+ pass + (ef > df ? ef : df), pass, ef, df);
fclose(fp); fclose(fs); fclose(ferr);
if (ef + df == 0)
diff --git a/x86-improvements b/x86-improvements
new file mode 100644
index 0000000..63f075b
--- /dev/null
+++ b/x86-improvements
@@ -0,0 +1,318 @@
+/**
+ * Since µAES code is optimized for 8-bit CPUs, it might be much less efficient
+ * for a 32-bit machine. We can apply a few tweaks, especially in the process of
+ * mixing columns, to boost its performance on such systems. For example, here's
+ * a piece of code to replace the lines #83 to #131 of "micro_aes.c" source file
+ * —starting with `#if DONT_USE_FUNCTIONS`. The endian-ness of system is crucial
+ * and must be determined by appropriate macros, e.g. let BIG_ENDIAN_INTEGERS be
+ * FALSE when compiling for a little-endian system and TRUE otherwise. Note that
+ * the `unsigned` keyword is actually equivalent to `uint32_t`. Furthermore, the
+ * body code of `MixColumns` and `InvMixColumns` must be changed as follows.. */
+
+#if BIG_ENDIAN_INTEGERS
+#define RL8(x) rotl( x, 8 )
+#else
+#define RL8(x) rotl( x, 24 ) /* equivalent little-endian rotation */
+#endif
+#define R16(x) rotl( x, 16 )
+#define RRR(x) rotl( x, 8 ) ^ rotl( x, 16 ) ^ rotl( x, 24 )
+
+/** This method must simply compile to a bit-rotate CPU instruction (ror/rol) */
+static unsigned rotl( const unsigned value, unsigned shift )
+{
+ return (value << shift) | (value >> (32 - shift));
+}
+
+/** XOR two 128-bit numbers (blocks) src and dest: optimized for 32-bit CPUs. */
+static void xorBlock( const block_t src, block_t dest )
+{
+ XOR32BITS( src[ 0], dest[ 0] );
+ XOR32BITS( src[ 4], dest[ 4] );
+ XOR32BITS( src[ 8], dest[ 8] );
+ XOR32BITS( src[12], dest[12] );
+}
+
+/** all 4 bytes of an unsigned integer are doubled [i.e. xtime-ed] in GF(2^8) */
+static void quad_xtime( unsigned* x )
+{
+ unsigned cc = (*x >> 7 & 0x1010101L) * 0x1b;
+ *x = (*x << 1 & ~0x1010101L) ^ cc;
+}
+
+--------------------------------------------------------------------------------
+MixColumns:
+ unsigned rt, i, *s = (unsigned*) &state[0];
+ for (i = Nb; i--; ++s)
+ {
+ rt = RRR( *s );
+ *s ^= RL8( *s );
+ quad_xtime( s );
+ *s ^= rt;
+ }
+
+InvMixColumns:
+ unsigned rt, i, *s = (unsigned*) &state[0];
+ for (i = Nb; i--; ++s)
+ {
+ rt = RRR( *s );
+ quad_xtime( s );
+ rt ^= RL8( *s ) ^ *s;
+ quad_xtime( s );
+ rt ^= R16( *s ) ^ *s;
+ quad_xtime( s );
+ *s ^= RRR( *s ) ^ rt;
+ }
+
+================================================================================
+a sample compiled assembly output, given by gcc using `-S -Os` flags:
+
+xorBlock(unsigned char const*, unsigned char*):
+ mov eax, QWORD PTR [rdi]
+ xor QWORD PTR [rsi], eax
+ mov eax, QWORD PTR [rdi+8]
+ xor QWORD PTR [rsi+8], eax
+ ret
+quad_xtime(unsigned int*):
+ mov edx, DWORD PTR [rdi]
+ mov eax, edx
+ add edx, edx
+ shr eax, 7
+ and edx, -16843010
+ and eax, 16843009
+ imul eax, eax, 27
+ xor eax, edx
+ mov DWORD PTR [rdi], eax
+ ret
+KeyExpansion(unsigned char const*):
+ movups xmm0, XMMWORD PTR [rdi]
+ mov eax, 16
+ mov dl, 1
+ movaps XMMWORD PTR RoundKey[rip], xmm0
+.L7:
+ test al, 15
+ jne .L4
+ movaps xmm1, XMMWORD PTR RoundKey[rax-16]
+ movups XMMWORD PTR RoundKey[rax], xmm1
+ test dl, dl
+ jne .L5
+ mov dl, 27
+.L5:
+ movzx ecx, BYTE PTR RoundKey[rax-3]
+ mov cl, BYTE PTR sbox[rcx]
+ xor cl, BYTE PTR RoundKey[rax]
+ xor ecx, edx
+ add edx, edx
+ mov BYTE PTR RoundKey[rax], cl
+ movzx ecx, BYTE PTR RoundKey[rax-2]
+ mov cl, BYTE PTR sbox[rcx]
+ xor BYTE PTR RoundKey[rax+1], cl
+ movzx ecx, BYTE PTR RoundKey[rax-1]
+ mov cl, BYTE PTR sbox[rcx]
+ xor BYTE PTR RoundKey[rax+2], cl
+ movzx ecx, BYTE PTR RoundKey[rax-4]
+ mov cl, BYTE PTR sbox[rcx]
+ xor BYTE PTR RoundKey[rax+3], cl
+ jmp .L6
+.L4:
+ mov ecx, DWORD PTR RoundKey[rax]
+ xor ecx, DWORD PTR RoundKey[rax-4]
+ mov DWORD PTR RoundKey[rax], ecx
+.L6:
+ add rax, 4
+ cmp rax, 176
+ jne .L7
+ ret
+SubBytes(unsigned char*):
+ xor eax, eax
+.L12:
+ movzx edx, BYTE PTR [rdi+rax]
+ mov dl, BYTE PTR sbox[rdx]
+ mov BYTE PTR [rdi+rax], dl
+ inc rax
+ cmp rax, 16
+ jne .L12
+ ret
+ShiftRows(unsigned char (*) [4][4]):
+ mov dl, BYTE PTR [rdi+5]
+ mov al, BYTE PTR [rdi+1]
+ mov BYTE PTR [rdi+1], dl
+ mov dl, BYTE PTR [rdi+9]
+ mov BYTE PTR [rdi+5], dl
+ mov dl, BYTE PTR [rdi+13]
+ mov BYTE PTR [rdi+13], al
+ mov al, BYTE PTR [rdi+2]
+ mov BYTE PTR [rdi+9], dl
+ mov dl, BYTE PTR [rdi+10]
+ mov BYTE PTR [rdi+10], al
+ mov al, BYTE PTR [rdi+6]
+ mov BYTE PTR [rdi+2], dl
+ mov dl, BYTE PTR [rdi+14]
+ mov BYTE PTR [rdi+14], al
+ mov al, BYTE PTR [rdi+3]
+ mov BYTE PTR [rdi+6], dl
+ mov dl, BYTE PTR [rdi+15]
+ mov BYTE PTR [rdi+3], dl
+ mov dl, BYTE PTR [rdi+11]
+ mov BYTE PTR [rdi+15], dl
+ mov dl, BYTE PTR [rdi+7]
+ mov BYTE PTR [rdi+7], al
+ mov BYTE PTR [rdi+11], dl
+ ret
+MixColumns(unsigned char (*) [4][4]):
+ lea r8, [rdi+16]
+.L16:
+ mov eax, DWORD PTR [rdi]
+ mov esi, eax
+ mov ecx, eax
+ mov edx, eax
+ ror esi, 8
+ rol edx, 16
+ xor eax, esi
+ rol ecx, 8
+ mov DWORD PTR [rdi], eax
+ xor ecx, edx
+ call quad_xtime(unsigned int*)
+ xor ecx, DWORD PTR [rdi]
+ add rdi, 4
+ xor ecx, esi
+ mov DWORD PTR [rdi-4], ecx
+ cmp rdi, r8
+ jne .L16
+ ret
+rijndaelEncrypt(unsigned char const*, unsigned char*):
+ mov r9, rsi
+ push rdx
+ cmp rsi, rdi
+ je .L19
+ movups xmm0, XMMWORD PTR [rdi]
+ movups XMMWORD PTR [rsi], xmm0
+.L19:
+ mov r10d, OFFSET FLAT:RoundKey
+.L21:
+ mov rdi, r10
+ mov rsi, r9
+ add r10, 16
+ call xorBlock(unsigned char const*, unsigned char*)
+ mov rdi, r9
+ call SubBytes(unsigned char*)
+ call ShiftRows(unsigned char (*) [4][4])
+ cmp r10, OFFSET FLAT:RoundKey+160
+ je .L20
+ call MixColumns(unsigned char (*) [4][4])
+ jmp .L21
+.L20:
+ mov edi, OFFSET FLAT:RoundKey+160
+ pop rax
+ jmp xorBlock(unsigned char const*, unsigned char*)
+InvSubBytes(unsigned char*):
+ xor eax, eax
+.L24:
+ movzx edx, BYTE PTR [rdi+rax]
+ mov dl, BYTE PTR rsbox[rdx]
+ mov BYTE PTR [rdi+rax], dl
+ inc rax
+ cmp rax, 16
+ jne .L24
+ ret
+InvShiftRows(unsigned char (*) [4][4]):
+ mov dl, BYTE PTR [rdi+9]
+ mov al, BYTE PTR [rdi+13]
+ mov BYTE PTR [rdi+13], dl
+ mov dl, BYTE PTR [rdi+5]
+ mov BYTE PTR [rdi+9], dl
+ mov dl, BYTE PTR [rdi+1]
+ mov BYTE PTR [rdi+1], al
+ mov al, BYTE PTR [rdi+2]
+ mov BYTE PTR [rdi+5], dl
+ mov dl, BYTE PTR [rdi+10]
+ mov BYTE PTR [rdi+10], al
+ mov al, BYTE PTR [rdi+6]
+ mov BYTE PTR [rdi+2], dl
+ mov dl, BYTE PTR [rdi+14]
+ mov BYTE PTR [rdi+14], al
+ mov al, BYTE PTR [rdi+3]
+ mov BYTE PTR [rdi+6], dl
+ mov dl, BYTE PTR [rdi+7]
+ mov BYTE PTR [rdi+3], dl
+ mov dl, BYTE PTR [rdi+11]
+ mov BYTE PTR [rdi+7], dl
+ mov dl, BYTE PTR [rdi+15]
+ mov BYTE PTR [rdi+15], al
+ mov BYTE PTR [rdi+11], dl
+ ret
+InvMixColumns(unsigned char (*) [4][4]):
+ mov rcx, rdi
+ lea rsi, [rdi+16]
+.L28:
+ mov rdi, rcx
+ mov r8d, DWORD PTR [rcx]
+ add rcx, 4
+ call quad_xtime(unsigned int*)
+ mov r10d, DWORD PTR [rcx-4]
+ call quad_xtime(unsigned int*)
+ mov r9d, DWORD PTR [rcx-4]
+ call quad_xtime(unsigned int*)
+ mov edx, DWORD PTR [rcx-4]
+ mov eax, r10d
+ mov edi, r8d
+ rol edi, 8
+ xor eax, r9d
+ ror r10d, 8
+ xor eax, edx
+ rol r9d, 16
+ xor eax, edi
+ mov edi, r8d
+ ror r8d, 8
+ rol edi, 16
+ xor eax, edi
+ mov edi, edx
+ xor eax, r8d
+ rol edi, 8
+ xor eax, r10d
+ xor eax, r9d
+ xor eax, edi
+ mov edi, edx
+ ror edx, 8
+ rol edi, 16
+ xor eax, edi
+ xor eax, edx
+ mov DWORD PTR [rcx-4], eax
+ cmp rsi, rcx
+ jne .L28
+ ret
+rijndaelDecrypt(unsigned char const*, unsigned char*):
+ push rbp
+ mov r11, rsi
+ push rbx
+ push rdx
+ cmp rsi, rdi
+ je .L31
+ movups xmm0, XMMWORD PTR [rdi]
+ movups XMMWORD PTR [rsi], xmm0
+.L31:
+ mov ebp, OFFSET FLAT:RoundKey+144
+ mov bl, 10
+.L34:
+ cmp bl, 10
+ je .L32
+ mov rdi, r11
+ call InvMixColumns(unsigned char (*) [4][4])
+ jmp .L33
+.L32:
+ mov rsi, r11
+ mov edi, OFFSET FLAT:RoundKey+160
+ call xorBlock(unsigned char const*, unsigned char*)
+.L33:
+ mov rdi, r11
+ mov rsi, r11
+ call InvShiftRows(unsigned char (*) [4][4])
+ call InvSubBytes(unsigned char*)
+ mov rdi, rbp
+ sub rbp, 16
+ call xorBlock(unsigned char const*, unsigned char*)
+ dec bl
+ jne .L34
+ pop rax
+ pop rbx
+ pop rbp
+ ret