├── .gitignore ├── LICENSE.txt ├── Makefile.am ├── README.md ├── aes-min.c ├── aes-min.h ├── aes-min.pc.in ├── aes-print-block.h ├── autogen.sh ├── configure.ac ├── gcm-mul-cfg.h ├── gcm-mul.c ├── gcm-mul.h ├── python ├── ac0254.txt ├── gcm-mul-reduce-table.py ├── gcm-process-test-vectors.py ├── gmul.py ├── parse-vectors.py └── pow254test.py └── tests ├── aes-encrypt-test.c ├── aes-inv-test.c ├── aes-key-schedule-test.c ├── aes-sbox-test.c ├── aes-test-vectors.h ├── aes-vectors-test.c ├── gcm-test-vectors.c ├── gcm-test-vectors.h └── gcm-test.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore objects and archives, anywhere in the tree. 2 | *.[oa] 3 | *.lo 4 | *.la 5 | # Ignore build output files 6 | /build 7 | 8 | # Ignore backup files 9 | *~ 10 | 11 | # Ignore autotools files 12 | .deps 13 | .libs 14 | /autom4te.cache 15 | /build-aux 16 | /config.h 17 | /config.h.in 18 | /config.log 19 | /config.status 20 | /configure 21 | /libtool 22 | /stamp-h1 23 | *.m4 24 | Makefile 25 | Makefile.in 26 | *.pc 27 | 28 | # Ignore Python files 29 | *.pyc 30 | *.pyd 31 | 32 | # Ignore Eclipse project files 33 | /.cproject 34 | /.project 35 | /.autotools 36 | /.settings 37 | /.pydevproject 38 | 39 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | Copyright (c) 2014 Craig McQueen 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | ---------------------------------------------------------------------------- 22 | 23 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | ####################################### 3 | # The list of libraries we are building separated by spaces. 4 | # The 'lib_' indicates that these build products will be installed 5 | # in the $(libdir) directory. For example /usr/lib 6 | lib_LTLIBRARIES = lib@PACKAGE_NAME@.la 7 | 8 | ####################################### 9 | # Build information for each library 10 | 11 | 12 | library_include_aes_mindir=$(includedir)/@PACKAGE_NAME@ 13 | library_include_aes_min_HEADERS = aes-min.h gcm-mul.h 14 | lib@PACKAGE_NAME@_la_SOURCES = aes-min.c 15 | lib@PACKAGE_NAME@_la_SOURCES += gcm-mul.c 16 | if ENABLE_SBOX_SMALL 17 | lib@PACKAGE_NAME@_la_CFLAGS = -DENABLE_SBOX_SMALL 18 | endif 19 | lib@PACKAGE_NAME@_la_LDFLAGS = -version-info @LIB_SO_VERSION@ 20 | 21 | pkgconfigdir = $(libdir)/pkgconfig 22 | pkgconfig_DATA = @PACKAGE_NAME@.pc 23 | 24 | 25 | ####################################### 26 | # Tests 27 | 28 | TESTS = aes-sbox-test aes-inv-test aes-key-schedule-test aes-encrypt-test aes-vectors-test gcm-test 29 | 30 | check_PROGRAMS = aes-sbox-test aes-inv-test aes-key-schedule-test aes-encrypt-test aes-vectors-test gcm-test 31 | 32 | aes_sbox_test_SOURCES = tests/aes-sbox-test.c aes-print-block.h 33 | aes_sbox_test_LDADD = lib@PACKAGE_NAME@.la 34 | 35 | aes_inv_test_SOURCES = tests/aes-inv-test.c aes-print-block.h 36 | aes_inv_test_LDADD = lib@PACKAGE_NAME@.la 37 | aes_inv_test_CFLAGS = $(AM_CFLAGS) 38 | 39 | aes_key_schedule_test_SOURCES = tests/aes-key-schedule-test.c aes-print-block.h 40 | aes_key_schedule_test_LDADD = lib@PACKAGE_NAME@.la 41 | 42 | aes_encrypt_test_SOURCES = tests/aes-encrypt-test.c aes-print-block.h 43 | aes_encrypt_test_LDADD = lib@PACKAGE_NAME@.la 44 | 45 | aes_vectors_test_SOURCES = tests/aes-vectors-test.c tests/aes-test-vectors.h aes-print-block.h 46 | aes_vectors_test_LDADD = lib@PACKAGE_NAME@.la 47 | 48 | gcm_test_SOURCES = tests/gcm-test.c tests/gcm-test-vectors.c tests/gcm-test-vectors.h gcm-mul.h aes-print-block.h 49 | gcm_test_LDADD = lib@PACKAGE_NAME@.la 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aes-min 2 | ======= 3 | 4 | Minimal AES-128 ([Wikipedia][1]) encryption. 5 | 6 | This aims to be suitable for small embedded systems with limited RAM and ROM. 7 | 8 | It includes optional on-the-fly key schedule calculation, for minimal RAM usage if required in a very RAM-constrained application. For systems with sufficient RAM, there is also encryption and decryption with a pre-calculated key schedule. 9 | 10 | Normally the S-box implementation is by a simple 256-byte table look-up. An optional smaller S-box implementation is included for a *very* ROM-constrained application, where a 256-byte look-up table might be too big. This would only be expected to be necessary for especially tiny target applications, e.g. an automotive keyless entry remote. 11 | 12 | Encryption modes 13 | ---------------- 14 | 15 | Encryption modes (CBC, OFB, etc) are not implemented. This only provides the core AES encryption operation, and leaves it to the developer to implement the encryption mode. This is because for small embedded systems, there are so many possible ways to handle the data in a memory-constrained system, it's not possible to provide an API that suits the needs of every system. 16 | 17 | In most cases, implementation of the encryption mode is reasonably straight-forward, requiring only a few block XOR operations. The function `aes_block_xor()` can be used for the block XOR operation. 18 | 19 | AES-GCM encryption mode 20 | ----------------------- 21 | 22 | [GCM encryption mode (Galois/Counter Mode)][2] is an authenticated encryption mode, which uses a Galois 128-bit multiply operation. Code is provided to do the 128-bit Galois multiply operation needed for GCM mode. Several implementations are provided, depending on the required trade-off between speed and RAM consumption: 23 | 24 | * a bit-by-bit implementation (slow but requiring minimal RAM) 25 | * a table implementation using an 8-bit table look-up (fast, but requiring 4,080 bytes of calculated table data per key) 26 | * a 4-bit table look-up implementation (moderately fast, requiring 480 bytes of calculated table data per key) 27 | 28 | Testing 29 | ------- 30 | 31 | Test programs are included, which test the S-box implementation and encrypt and decrypt operations. 32 | 33 | Encryption and decryption are tested against some files in the official [test vectors][3]. Specifically, the ECB mode test files were used, for AES-128. These files: 34 | 35 | * `ECBGFSbox128.rsp` 36 | * `ECBKeySbox128.rsp` 37 | * `ECBVarKey128.rsp` 38 | * `ECBVarTxt128.rsp` 39 | 40 | The test vectors were parsed and converted to C data structures using a Python program. 41 | 42 | For AES-GCM mode, the Galois 128-bit multiply is tested against [these AES-GCM test vectors from NIST][4]. 43 | 44 | When using autotools, run the tests via: 45 | 46 | make check 47 | 48 | License 49 | ------- 50 | 51 | This code is released under the MIT license. See [`LICENSE.txt`][5] for details. 52 | 53 | 54 | [1]: http://en.wikipedia.org/wiki/Advanced_Encryption_Standard 55 | [2]: https://en.wikipedia.org/wiki/Galois/Counter_Mode 56 | [3]: http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip 57 | [4]: https://csrc.nist.gov/csrc/media/projects/cryptographic-algorithm-validation-program/documents/mac/gcmtestvectors.zip 58 | [5]: LICENSE.txt 59 | -------------------------------------------------------------------------------- /aes-min.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * aes-min.c 3 | * 4 | * Minimal byte-oriented AES-128 encryption/decryption implementation suitable 5 | * for small microprocessors. 6 | ****************************************************************************/ 7 | 8 | /***************************************************************************** 9 | * Includes 10 | ****************************************************************************/ 11 | 12 | #include "aes-min.h" 13 | 14 | #include 15 | 16 | /***************************************************************************** 17 | * Defines 18 | ****************************************************************************/ 19 | 20 | #define AES_KEY_SCHEDULE_FIRST_RCON 1u 21 | #define AES128_KEY_SCHEDULE_LAST_RCON 54u 22 | 23 | #define AES_REDUCE_BYTE 0x1Bu 24 | #define AES_2_INVERSE 141u 25 | 26 | #define AES_INV_CHAIN_LEN 11u 27 | 28 | /***************************************************************************** 29 | * Look-up tables 30 | ****************************************************************************/ 31 | 32 | #ifndef ENABLE_SBOX_SMALL 33 | 34 | static const uint8_t aes_sbox_table[256u] = 35 | { 36 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 37 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 38 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 39 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 40 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 41 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 42 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 43 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 44 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 45 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 46 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 47 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 48 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 49 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 50 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 51 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 52 | }; 53 | 54 | static const uint8_t aes_sbox_inv_table[256u] = 55 | { 56 | 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 57 | 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 58 | 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 59 | 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 60 | 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 61 | 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 62 | 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 63 | 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 64 | 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 65 | 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 66 | 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 67 | 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 68 | 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 69 | 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 70 | 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 71 | 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D 72 | }; 73 | 74 | #endif 75 | 76 | /***************************************************************************** 77 | * Local function prototypes 78 | ****************************************************************************/ 79 | 80 | static void aes128_key_schedule_round(uint8_t p_key[AES128_KEY_SIZE], uint8_t rcon); 81 | static void aes128_key_schedule_inv_round(uint8_t p_key[AES128_KEY_SIZE], uint8_t rcon); 82 | static uint8_t aes_mul(uint8_t a, uint8_t b); 83 | static uint8_t aes_inv(uint8_t a); 84 | static uint8_t aes_sbox(uint8_t a); 85 | static uint8_t aes_sbox_inv(uint8_t a); 86 | static void aes_sbox_apply_block(uint8_t p_block[AES_BLOCK_SIZE]); 87 | static void aes_sbox_inv_apply_block(uint8_t p_block[AES_BLOCK_SIZE]); 88 | static void aes_shift_rows(uint8_t p_block[AES_BLOCK_SIZE]); 89 | static void aes_shift_rows_inv(uint8_t p_block[AES_BLOCK_SIZE]); 90 | static void aes_mix_columns(uint8_t p_block[AES_BLOCK_SIZE]); 91 | static void aes_mix_columns_inv(uint8_t p_block[AES_BLOCK_SIZE]); 92 | 93 | /***************************************************************************** 94 | * Inline functions 95 | ****************************************************************************/ 96 | 97 | #if 0 98 | 99 | /* This is probably the most straight-forward expression of the algorithm. 100 | * This seems more likely to have variable timing, although inspection 101 | * of compiled code would be needed to confirm it. 102 | * It is more likely to have variable timing when no optimisations are 103 | * enabled. */ 104 | static inline uint8_t aes_mul2(uint8_t a) 105 | { 106 | uint8_t result; 107 | 108 | result = a << 1u; 109 | if (a & 0x80u) 110 | result ^= AES_REDUCE_BYTE; 111 | return result; 112 | } 113 | 114 | static inline uint8_t aes_div2(uint8_t a) 115 | { 116 | uint8_t result; 117 | 118 | result = a >> 1u; 119 | if (a & 1u) 120 | result ^= AES_2_INVERSE; 121 | return result; 122 | } 123 | 124 | #elif 0 125 | 126 | /* This hopefully has fixed timing, although inspection 127 | * of compiled code would be needed to confirm it. */ 128 | static inline uint8_t aes_mul2(uint8_t a) 129 | { 130 | static const uint8_t reduce[2] = { 0, AES_REDUCE_BYTE }; 131 | 132 | return (a << 1u) ^ reduce[a >= 0x80u]; 133 | } 134 | 135 | static inline uint8_t aes_div2(uint8_t a) 136 | { 137 | static const uint8_t reduce[2] = { 0, AES_2_INVERSE }; 138 | 139 | return (a >> 1u) ^ reduce[a & 1u]; 140 | } 141 | 142 | #else 143 | 144 | /* This hopefully has fixed timing, although inspection 145 | * of compiled code would be needed to confirm it. */ 146 | static inline uint8_t aes_mul2(uint8_t a) 147 | { 148 | return (a << 1u) ^ ((-(a >= 0x80u)) & AES_REDUCE_BYTE); 149 | } 150 | 151 | static inline uint8_t aes_div2(uint8_t a) 152 | { 153 | return (a >> 1u) ^ ((-(a & 1u)) & AES_2_INVERSE); 154 | } 155 | 156 | #endif 157 | 158 | /* Hopefully the compiler reduces this to a single rotate instruction. 159 | * However in testing with gcc on x86-64, it didn't happen. But it is target- 160 | * and compiler-specific. 161 | * 162 | * Alternatively for a particular platform: 163 | * - Use an intrinsic 8-bit rotate function provided by the compiler. 164 | * - Use inline assembler. 165 | * 166 | * TODO: Examine code produced on the target platform. 167 | */ 168 | static inline uint8_t aes_rotate_left_uint8(uint8_t a, uint_fast8_t num_bits) 169 | { 170 | return ((a << num_bits) | (a >> (8u - num_bits))); 171 | } 172 | 173 | /***************************************************************************** 174 | * Functions 175 | ****************************************************************************/ 176 | 177 | /* AES-128 encryption. 178 | * 179 | * p_block points to a 16-byte buffer of plain data to encrypt. Encryption 180 | * is done in-place in that buffer. 181 | * p_key_schedule points to a pre-calculated key schedule, which can be 182 | * calculated by aes128_key_schedule(). 183 | */ 184 | void aes128_encrypt(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE]) 185 | { 186 | uint_fast8_t round; 187 | 188 | aes_block_xor(p_block, p_key_schedule); 189 | for (round = 1; round < AES128_NUM_ROUNDS; ++round) 190 | { 191 | aes_sbox_apply_block(p_block); 192 | aes_shift_rows(p_block); 193 | aes_mix_columns(p_block); 194 | aes_block_xor(p_block, &p_key_schedule[round * AES_BLOCK_SIZE]); 195 | } 196 | aes_sbox_apply_block(p_block); 197 | aes_shift_rows(p_block); 198 | aes_block_xor(p_block, &p_key_schedule[AES128_NUM_ROUNDS * AES_BLOCK_SIZE]); 199 | } 200 | 201 | /* AES-128 decryption. 202 | * 203 | * p_block points to a 16-byte buffer of encrypted data to decrypt. Decryption 204 | * is done in-place in that buffer. 205 | * p_key_schedule points to a pre-calculated key schedule, which can be 206 | * calculated by aes128_key_schedule(). 207 | */ 208 | void aes128_decrypt(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE]) 209 | { 210 | uint_fast8_t round; 211 | 212 | aes_block_xor(p_block, &p_key_schedule[AES128_NUM_ROUNDS * AES_BLOCK_SIZE]); 213 | aes_shift_rows_inv(p_block); 214 | aes_sbox_inv_apply_block(p_block); 215 | for (round = AES128_NUM_ROUNDS - 1u; round >= 1; --round) 216 | { 217 | aes_block_xor(p_block, &p_key_schedule[round * AES_BLOCK_SIZE]); 218 | aes_mix_columns_inv(p_block); 219 | aes_shift_rows_inv(p_block); 220 | aes_sbox_inv_apply_block(p_block); 221 | } 222 | aes_block_xor(p_block, p_key_schedule); 223 | } 224 | 225 | void aes128_key_schedule(uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE], const uint8_t p_key[AES128_KEY_SIZE]) 226 | { 227 | uint_fast8_t round; 228 | uint8_t * p_key_0 = p_key_schedule + AES128_KEY_SIZE; 229 | uint8_t temp_byte; 230 | uint8_t rcon = AES_KEY_SCHEDULE_FIRST_RCON; 231 | 232 | /* Initial part of key schedule is simply the AES-128 key copied verbatim. */ 233 | memcpy(p_key_schedule, p_key, AES128_KEY_SIZE); 234 | 235 | for (round = 0; round < (AES128_KEY_SCHEDULE_SIZE - AES128_KEY_SIZE) / AES_KEY_SCHEDULE_WORD_SIZE; ++round) 236 | { 237 | memcpy(p_key_0, p_key_0 - AES_KEY_SCHEDULE_WORD_SIZE, AES_KEY_SCHEDULE_WORD_SIZE); 238 | 239 | if ((round % (AES128_KEY_SIZE / AES_KEY_SCHEDULE_WORD_SIZE)) == 0) 240 | { 241 | /* Rotate previous word and apply S-box. Also XOR Rcon for first byte. */ 242 | temp_byte = p_key_0[0]; 243 | p_key_0[0] = aes_sbox(p_key_0[1]) ^ rcon; 244 | p_key_0[1] = aes_sbox(p_key_0[2]); 245 | p_key_0[2] = aes_sbox(p_key_0[3]); 246 | p_key_0[3] = aes_sbox(temp_byte); 247 | 248 | /* Next rcon */ 249 | rcon = aes_mul2(rcon); 250 | } 251 | 252 | /* XOR in bytes from AES128_KEY_SIZE bytes ago */ 253 | p_key_0[0] ^= p_key_0[0 - (signed)AES128_KEY_SIZE]; 254 | p_key_0[1] ^= p_key_0[1 - (signed)AES128_KEY_SIZE]; 255 | p_key_0[2] ^= p_key_0[2 - (signed)AES128_KEY_SIZE]; 256 | p_key_0[3] ^= p_key_0[3 - (signed)AES128_KEY_SIZE]; 257 | 258 | p_key_0 += AES_KEY_SCHEDULE_WORD_SIZE; 259 | } 260 | } 261 | 262 | /* AES-128 encryption with on-the-fly key schedule calculation. 263 | * 264 | * p_block points to a 16-byte buffer of plain data to encrypt. Encryption 265 | * is done in-place in that buffer. 266 | * p_key must initially point to a starting key state for encryption, which is 267 | * simply the 16 bytes of the AES-128 key. Key schedule is calculated on-the- 268 | * fly in that buffer, so the buffer must re-initialised for subsequent 269 | * encryption operations. 270 | */ 271 | void aes128_otfks_encrypt(uint8_t p_block[AES_BLOCK_SIZE], uint8_t p_key[AES128_KEY_SIZE]) 272 | { 273 | uint_fast8_t round; 274 | uint8_t rcon = AES_KEY_SCHEDULE_FIRST_RCON; 275 | 276 | aes_block_xor(p_block, p_key); 277 | for (round = 1; round < AES128_NUM_ROUNDS; ++round) 278 | { 279 | aes128_key_schedule_round(p_key, rcon); 280 | aes_sbox_apply_block(p_block); 281 | aes_shift_rows(p_block); 282 | aes_mix_columns(p_block); 283 | aes_block_xor(p_block, p_key); 284 | 285 | /* Next rcon */ 286 | rcon = aes_mul2(rcon); 287 | } 288 | aes128_key_schedule_round(p_key, rcon); 289 | aes_sbox_apply_block(p_block); 290 | aes_shift_rows(p_block); 291 | aes_block_xor(p_block, p_key); 292 | } 293 | 294 | /* Calculate the starting key state needed for decryption with on-the-fly key 295 | * schedule calculation. The starting decryption key state is the last 16 bytes 296 | * of the AES-128 key schedule. 297 | * The decryption start key calculation is done in-place in the buffer p_key[]. 298 | * So p_key points to a 16-byte buffer containing the AES-128 key. On exit, it 299 | * contains the decryption start key state suitable for aes128_otfks_decrypt(). 300 | */ 301 | void aes128_otfks_decrypt_start_key(uint8_t p_key[AES128_KEY_SIZE]) 302 | { 303 | uint_fast8_t round; 304 | uint8_t rcon = AES_KEY_SCHEDULE_FIRST_RCON; 305 | 306 | for (round = 0; round < AES128_NUM_ROUNDS; ++round) 307 | { 308 | aes128_key_schedule_round(p_key, rcon); 309 | 310 | /* Next rcon */ 311 | rcon = aes_mul2(rcon); 312 | } 313 | } 314 | 315 | /* AES-128 decryption with on-the-fly key schedule calculation. 316 | * 317 | * p_block points to a 16-byte buffer of encrypted data to decrypt. Decryption 318 | * is done in-place in that buffer. 319 | * p_key must initially point to a starting key state for decryption, which is 320 | * the last 16 bytes of the AES-128 key schedule. It can be calculated from the 321 | * AES-128 16-byte key by aes128_otfks_decrypt_start_key(). Key schedule is 322 | * calculated on-the-fly in that buffer, so the buffer must re-initialised for 323 | * subsequent decryption operations. 324 | */ 325 | void aes128_otfks_decrypt(uint8_t p_block[AES_BLOCK_SIZE], uint8_t p_key[AES128_KEY_SIZE]) 326 | { 327 | uint_fast8_t round; 328 | uint8_t rcon = AES128_KEY_SCHEDULE_LAST_RCON; 329 | 330 | aes_block_xor(p_block, p_key); 331 | aes_shift_rows_inv(p_block); 332 | aes_sbox_inv_apply_block(p_block); 333 | for (round = AES128_NUM_ROUNDS - 1u; round >= 1; --round) 334 | { 335 | aes128_key_schedule_inv_round(p_key, rcon); 336 | aes_block_xor(p_block, p_key); 337 | aes_mix_columns_inv(p_block); 338 | aes_shift_rows_inv(p_block); 339 | aes_sbox_inv_apply_block(p_block); 340 | 341 | /* Previous rcon */ 342 | rcon = aes_div2(rcon); 343 | } 344 | aes128_key_schedule_inv_round(p_key, rcon); 345 | aes_block_xor(p_block, p_key); 346 | } 347 | 348 | uint8_t _aes_inv_for_test(uint8_t a) 349 | { 350 | return aes_inv(a); 351 | } 352 | 353 | void _aes_sbox_apply_block_for_test(uint8_t p_block[AES_BLOCK_SIZE]) 354 | { 355 | aes_sbox_apply_block(p_block); 356 | } 357 | 358 | /***************************************************************************** 359 | * Local functions 360 | ****************************************************************************/ 361 | 362 | /* This is used for aes128_otfks_encrypt(), on-the-fly key schedule encryption. 363 | * It is also used by aes128_otfks_decrypt_start_key() to calculate the 364 | * starting key state for decryption with on-the-fly key schedule calculation. 365 | * rcon for the round must be provided, out of the sequence: 366 | * 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 367 | * Subsequent values can be calculated with aes_mul2(). 368 | */ 369 | static void aes128_key_schedule_round(uint8_t p_key[AES128_KEY_SIZE], uint8_t rcon) 370 | { 371 | uint_fast8_t round; 372 | uint8_t * p_key_0 = p_key; 373 | uint8_t * p_key_m1 = p_key + AES128_KEY_SIZE - AES_KEY_SCHEDULE_WORD_SIZE; 374 | 375 | /* Rotate previous word and apply S-box. Also XOR Rcon for first byte. */ 376 | p_key_0[0] ^= aes_sbox(p_key_m1[1]) ^ rcon; 377 | p_key_0[1] ^= aes_sbox(p_key_m1[2]); 378 | p_key_0[2] ^= aes_sbox(p_key_m1[3]); 379 | p_key_0[3] ^= aes_sbox(p_key_m1[0]); 380 | 381 | for (round = 1; round < AES128_KEY_SIZE / AES_KEY_SCHEDULE_WORD_SIZE; ++round) 382 | { 383 | p_key_m1 = p_key_0; 384 | p_key_0 += AES_KEY_SCHEDULE_WORD_SIZE; 385 | 386 | /* XOR in previous word */ 387 | p_key_0[0] ^= p_key_m1[0]; 388 | p_key_0[1] ^= p_key_m1[1]; 389 | p_key_0[2] ^= p_key_m1[2]; 390 | p_key_0[3] ^= p_key_m1[3]; 391 | } 392 | } 393 | 394 | /* This is used for aes128_otfks_decrypt(), on-the-fly key schedule decryption. 395 | * rcon for the round must be provided, out of the sequence: 396 | * 54, 27, 128, 64, 32, 16, 8, 4, 2, 1 397 | * Subsequent values can be calculated with aes_div2(). 398 | */ 399 | static void aes128_key_schedule_inv_round(uint8_t p_key[AES128_KEY_SIZE], uint8_t rcon) 400 | { 401 | uint_fast8_t round; 402 | uint8_t * p_key_0 = p_key + AES128_KEY_SIZE - AES_KEY_SCHEDULE_WORD_SIZE; 403 | uint8_t * p_key_m1 = p_key_0 - AES_KEY_SCHEDULE_WORD_SIZE; 404 | 405 | for (round = 1; round < AES128_KEY_SIZE / AES_KEY_SCHEDULE_WORD_SIZE; ++round) 406 | { 407 | /* XOR in previous word */ 408 | p_key_0[0] ^= p_key_m1[0]; 409 | p_key_0[1] ^= p_key_m1[1]; 410 | p_key_0[2] ^= p_key_m1[2]; 411 | p_key_0[3] ^= p_key_m1[3]; 412 | 413 | p_key_0 = p_key_m1; 414 | p_key_m1 -= AES_KEY_SCHEDULE_WORD_SIZE; 415 | } 416 | 417 | /* Rotate previous word and apply S-box. Also XOR Rcon for first byte. */ 418 | p_key_m1 = p_key + AES128_KEY_SIZE - AES_KEY_SCHEDULE_WORD_SIZE; 419 | p_key_0[0] ^= aes_sbox(p_key_m1[1]) ^ rcon; 420 | p_key_0[1] ^= aes_sbox(p_key_m1[2]); 421 | p_key_0[2] ^= aes_sbox(p_key_m1[3]); 422 | p_key_0[3] ^= aes_sbox(p_key_m1[0]); 423 | } 424 | 425 | /* Multiply two numbers in Galois field GF(2^8) with reduction polynomial 426 | * 0x11B. 427 | * TODO: To prevent timing attacks, analyse the compiler-generated code 428 | * to see if it has constant execution time regardless of input values. 429 | */ 430 | static uint8_t aes_mul(uint8_t a, uint8_t b) 431 | { 432 | uint8_t result = 0; 433 | uint_fast8_t i; 434 | for (i = 0; i < 8u; i++) 435 | { 436 | #if 0 437 | /* This code variant is less likely to have constant execution time, 438 | * and thus more likely to be vulnerable to timing attacks. */ 439 | if (b & 1) 440 | { 441 | result ^= a; 442 | } 443 | #else 444 | result ^= (-(b & 1u)) & a; 445 | #endif 446 | a = aes_mul2(a); 447 | b >>= 1; 448 | } 449 | return result; 450 | } 451 | 452 | /* Calculation of inverse in GF(2^8), by exponentiation to power 254. 453 | * Use minimal addition chain to raise to the power of 254, which requires 454 | * 11 multiplies. 455 | * There are many addition chains of length 11 for 254. This one was picked 456 | * because it has the most multiplies by the previous value, and least 457 | * references to earlier history, which in theory could minimise the size of 458 | * prev_values[]. However, in the end we do the simplest possible 459 | * implementation of the algorithm to minimise code size (because aes_inv() is 460 | * used to achieve smallest possible S-box implementation), so it doesn't 461 | * really matter which addition chain we pick. 462 | */ 463 | static uint8_t aes_inv(uint8_t a) 464 | { 465 | static const uint8_t addition_chain_idx[AES_INV_CHAIN_LEN] = { 0, 1, 1, 3, 4, 3, 6, 7, 3, 9, 1 }; 466 | uint_fast8_t i; 467 | uint8_t prev_values[AES_INV_CHAIN_LEN]; 468 | 469 | for (i = 0; i < AES_INV_CHAIN_LEN; i++) 470 | { 471 | prev_values[i] = a; 472 | a = aes_mul(a, prev_values[addition_chain_idx[i]]); 473 | } 474 | return a; 475 | } 476 | 477 | #ifdef ENABLE_SBOX_SMALL 478 | 479 | static uint8_t aes_sbox(uint8_t a) 480 | { 481 | uint8_t x; 482 | 483 | a = aes_inv(a); 484 | 485 | x = aes_rotate_left_uint8(a, 1u); 486 | x ^= aes_rotate_left_uint8(x, 1u); 487 | x ^= aes_rotate_left_uint8(x, 2u); 488 | 489 | return a ^ x ^ 0x63u; 490 | } 491 | 492 | static uint8_t aes_sbox_inv(uint8_t a) 493 | { 494 | uint8_t x; 495 | 496 | x = aes_rotate_left_uint8(a, 1u); 497 | a = aes_rotate_left_uint8(x, 2u); 498 | x ^= a; 499 | a = aes_rotate_left_uint8(a, 3u); 500 | 501 | return aes_inv(a ^ x ^ 0x05u); 502 | } 503 | 504 | #else /* ENABLE_SBOX_SMALL */ 505 | 506 | static uint8_t aes_sbox(uint8_t a) 507 | { 508 | return aes_sbox_table[a]; 509 | } 510 | 511 | static uint8_t aes_sbox_inv(uint8_t a) 512 | { 513 | return aes_sbox_inv_table[a]; 514 | } 515 | 516 | #endif /* ENABLE_SBOX_SMALL */ 517 | 518 | static void aes_sbox_apply_block(uint8_t p_block[AES_BLOCK_SIZE]) 519 | { 520 | uint_fast8_t i; 521 | 522 | for (i = 0; i < AES_BLOCK_SIZE; ++i) 523 | { 524 | p_block[i] = aes_sbox(p_block[i]); 525 | } 526 | } 527 | 528 | static void aes_sbox_inv_apply_block(uint8_t p_block[AES_BLOCK_SIZE]) 529 | { 530 | uint_fast8_t i; 531 | 532 | for (i = 0; i < AES_BLOCK_SIZE; ++i) 533 | { 534 | p_block[i] = aes_sbox_inv(p_block[i]); 535 | } 536 | } 537 | 538 | static void aes_shift_rows(uint8_t p_block[AES_BLOCK_SIZE]) 539 | { 540 | uint8_t temp_byte; 541 | 542 | /* First row doesn't shift */ 543 | 544 | /* Shift the second row */ 545 | temp_byte = p_block[0 * AES_COLUMN_SIZE + 1u]; 546 | p_block[0 * AES_COLUMN_SIZE + 1u] = p_block[1u * AES_COLUMN_SIZE + 1u]; 547 | p_block[1u * AES_COLUMN_SIZE + 1u] = p_block[2u * AES_COLUMN_SIZE + 1u]; 548 | p_block[2u * AES_COLUMN_SIZE + 1u] = p_block[3u * AES_COLUMN_SIZE + 1u]; 549 | p_block[3u * AES_COLUMN_SIZE + 1u] = temp_byte; 550 | 551 | /* Shift the third row */ 552 | temp_byte = p_block[0 * AES_COLUMN_SIZE + 2u]; 553 | p_block[0 * AES_COLUMN_SIZE + 2u] = p_block[2u * AES_COLUMN_SIZE + 2u]; 554 | p_block[2u * AES_COLUMN_SIZE + 2u] = temp_byte; 555 | temp_byte = p_block[1u * AES_COLUMN_SIZE + 2u]; 556 | p_block[1u * AES_COLUMN_SIZE + 2u] = p_block[3u * AES_COLUMN_SIZE + 2u]; 557 | p_block[3u * AES_COLUMN_SIZE + 2u] = temp_byte; 558 | 559 | /* Shift the fourth row */ 560 | temp_byte = p_block[3u * AES_COLUMN_SIZE + 3u]; 561 | p_block[3u * AES_COLUMN_SIZE + 3u] = p_block[2u * AES_COLUMN_SIZE + 3u]; 562 | p_block[2u * AES_COLUMN_SIZE + 3u] = p_block[1u * AES_COLUMN_SIZE + 3u]; 563 | p_block[1u * AES_COLUMN_SIZE + 3u] = p_block[0 * AES_COLUMN_SIZE + 3u]; 564 | p_block[0 * AES_COLUMN_SIZE + 3u] = temp_byte; 565 | } 566 | 567 | static void aes_shift_rows_inv(uint8_t p_block[AES_BLOCK_SIZE]) 568 | { 569 | uint8_t temp_byte; 570 | 571 | /* First row doesn't shift */ 572 | 573 | /* Shift the second row */ 574 | temp_byte = p_block[3u * AES_COLUMN_SIZE + 1u]; 575 | p_block[3u * AES_COLUMN_SIZE + 1u] = p_block[2u * AES_COLUMN_SIZE + 1u]; 576 | p_block[2u * AES_COLUMN_SIZE + 1u] = p_block[1u * AES_COLUMN_SIZE + 1u]; 577 | p_block[1u * AES_COLUMN_SIZE + 1u] = p_block[0 * AES_COLUMN_SIZE + 1u]; 578 | p_block[0 * AES_COLUMN_SIZE + 1u] = temp_byte; 579 | 580 | /* Shift the third row */ 581 | temp_byte = p_block[0 * AES_COLUMN_SIZE + 2u]; 582 | p_block[0 * AES_COLUMN_SIZE + 2u] = p_block[2u * AES_COLUMN_SIZE + 2u]; 583 | p_block[2u * AES_COLUMN_SIZE + 2u] = temp_byte; 584 | temp_byte = p_block[1u * AES_COLUMN_SIZE + 2u]; 585 | p_block[1u * AES_COLUMN_SIZE + 2u] = p_block[3u * AES_COLUMN_SIZE + 2u]; 586 | p_block[3u * AES_COLUMN_SIZE + 2u] = temp_byte; 587 | 588 | /* Shift the fourth row */ 589 | temp_byte = p_block[0 * AES_COLUMN_SIZE + 3u]; 590 | p_block[0 * AES_COLUMN_SIZE + 3u] = p_block[1u * AES_COLUMN_SIZE + 3u]; 591 | p_block[1u * AES_COLUMN_SIZE + 3u] = p_block[2u * AES_COLUMN_SIZE + 3u]; 592 | p_block[2u * AES_COLUMN_SIZE + 3u] = p_block[3u * AES_COLUMN_SIZE + 3u]; 593 | p_block[3u * AES_COLUMN_SIZE + 3u] = temp_byte; 594 | } 595 | 596 | static void aes_mix_columns(uint8_t p_block[AES_BLOCK_SIZE]) 597 | { 598 | uint8_t temp_column[AES_COLUMN_SIZE]; 599 | uint_fast8_t i; 600 | uint_fast8_t j; 601 | uint8_t byte_value; 602 | uint8_t byte_value_2; 603 | 604 | for (i = 0; i < AES_NUM_COLUMNS; i++) 605 | { 606 | memset(temp_column, 0, AES_COLUMN_SIZE); 607 | for (j = 0; j < AES_COLUMN_SIZE; j++) 608 | { 609 | byte_value = p_block[i * AES_COLUMN_SIZE + j]; 610 | byte_value_2 = aes_mul2(byte_value); 611 | temp_column[(j + 0 ) % AES_COLUMN_SIZE] ^= byte_value_2; 612 | temp_column[(j + 1u) % AES_COLUMN_SIZE] ^= byte_value; 613 | temp_column[(j + 2u) % AES_COLUMN_SIZE] ^= byte_value; 614 | temp_column[(j + 3u) % AES_COLUMN_SIZE] ^= byte_value ^ byte_value_2; 615 | } 616 | memcpy(&p_block[i * AES_COLUMN_SIZE], temp_column, AES_COLUMN_SIZE); 617 | } 618 | } 619 | 620 | /* 14 = 1110b 621 | * 9 = 1001b 622 | * 13 = 1101b 623 | * 11 = 1011b 624 | */ 625 | static void aes_mix_columns_inv(uint8_t p_block[AES_BLOCK_SIZE]) 626 | { 627 | uint8_t temp_column[AES_COLUMN_SIZE]; 628 | uint_fast8_t i; 629 | uint_fast8_t j; 630 | uint8_t byte_value; 631 | uint8_t byte_value_2; 632 | uint8_t byte_value_4; 633 | uint8_t byte_value_8; 634 | 635 | for (i = 0; i < AES_NUM_COLUMNS; i++) 636 | { 637 | memset(temp_column, 0, AES_COLUMN_SIZE); 638 | for (j = 0; j < AES_COLUMN_SIZE; j++) 639 | { 640 | byte_value = p_block[i * AES_COLUMN_SIZE + j]; 641 | byte_value_2 = aes_mul2(byte_value); 642 | byte_value_4 = aes_mul2(byte_value_2); 643 | byte_value_8 = aes_mul2(byte_value_4); 644 | temp_column[(j + 0 ) % AES_COLUMN_SIZE] ^= byte_value_8 ^ byte_value_4 ^ byte_value_2; // 14 = 1110b 645 | temp_column[(j + 1u) % AES_COLUMN_SIZE] ^= byte_value_8 ^ byte_value; // 9 = 1001b 646 | temp_column[(j + 2u) % AES_COLUMN_SIZE] ^= byte_value_8 ^ byte_value_4 ^ byte_value; // 13 = 1101b 647 | temp_column[(j + 3u) % AES_COLUMN_SIZE] ^= byte_value_8 ^ byte_value_2 ^ byte_value; // 11 = 1011b 648 | } 649 | memcpy(&p_block[i * AES_COLUMN_SIZE], temp_column, AES_COLUMN_SIZE); 650 | } 651 | } 652 | -------------------------------------------------------------------------------- /aes-min.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * aes-min.h 3 | * 4 | * Minimal byte-oriented AES-128 encryption/decryption implementation suitable 5 | * for small microprocessors. 6 | ****************************************************************************/ 7 | 8 | #ifndef AES_MIN_H 9 | #define AES_MIN_H 10 | 11 | /***************************************************************************** 12 | * Includes 13 | ****************************************************************************/ 14 | 15 | #include 16 | 17 | /***************************************************************************** 18 | * Defines 19 | ****************************************************************************/ 20 | 21 | #define AES_BLOCK_SIZE 16u 22 | #define AES_COLUMN_SIZE 4u 23 | #define AES_NUM_COLUMNS 4u 24 | 25 | #define AES_KEY_SCHEDULE_WORD_SIZE 4u 26 | 27 | #define AES128_NUM_ROUNDS 10u 28 | #define AES128_KEY_SIZE 16u 29 | #define AES128_KEY_SCHEDULE_SIZE (AES_BLOCK_SIZE * (AES128_NUM_ROUNDS + 1u)) 30 | 31 | /***************************************************************************** 32 | * Inline functions 33 | ****************************************************************************/ 34 | 35 | /* 36 | * XOR the specified round key into the AES block. 37 | * Fixed block size. 38 | */ 39 | static inline void aes_block_xor(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_data[AES_BLOCK_SIZE]) 40 | { 41 | uint_fast8_t i; 42 | 43 | for (i = 0; i < AES_BLOCK_SIZE; ++i) 44 | { 45 | p_block[i] ^= p_data[i]; 46 | } 47 | } 48 | 49 | /***************************************************************************** 50 | * Function prototypes 51 | ****************************************************************************/ 52 | 53 | void aes128_encrypt(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE]); 54 | void aes128_decrypt(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE]); 55 | 56 | void aes128_key_schedule(uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE], const uint8_t p_key[AES128_KEY_SIZE]); 57 | 58 | void aes128_otfks_encrypt(uint8_t p_block[AES_BLOCK_SIZE], uint8_t p_key[AES128_KEY_SIZE]); 59 | void aes128_otfks_decrypt(uint8_t p_block[AES_BLOCK_SIZE], uint8_t p_decrypt_start_key[AES128_KEY_SIZE]); 60 | 61 | void aes128_otfks_decrypt_start_key(uint8_t p_key[AES128_KEY_SIZE]); 62 | 63 | 64 | #endif /* !defined(AES_MIN_H) */ 65 | -------------------------------------------------------------------------------- /aes-min.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: @PACKAGE_NAME@ 7 | Description: Minimal AES encryption with 128-bit key. 8 | Version: @PACKAGE_VERSION@ 9 | Libs: -L${libdir} -l@PACKAGE_NAME@ 10 | Cflags: -I${includedir}/@PACKAGE_NAME@ 11 | -------------------------------------------------------------------------------- /aes-print-block.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * aes-print-block.h 3 | ****************************************************************************/ 4 | 5 | #ifndef AES_PRINT_BLOCK_H 6 | #define AES_PRINT_BLOCK_H 7 | 8 | /***************************************************************************** 9 | * Includes 10 | ****************************************************************************/ 11 | 12 | #include 13 | #include 14 | 15 | /***************************************************************************** 16 | * Inline functions 17 | ****************************************************************************/ 18 | 19 | static inline void print_block_hex(const uint8_t * p_block, size_t len) 20 | { 21 | while (len > 1) 22 | { 23 | printf("%02X ", *p_block++); 24 | len--; 25 | } 26 | if (len) 27 | { 28 | printf("%02X", *p_block); 29 | } 30 | printf("\n"); 31 | } 32 | 33 | 34 | #endif /* !defined(AES_PRINT_BLOCK_H) */ 35 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | autoreconf --install || exit 1 2 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | 3 | AC_PREREQ(2.68) 4 | AC_INIT([aes-min], [0.3.1]) #set project name and version 5 | 6 | # Put autotools auxiliary files in subdirectories to reduce clutter: 7 | AC_CONFIG_AUX_DIR([build-aux]) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | 10 | AC_PROG_CC 11 | 12 | #AC_CANONICAL_SYSTEM 13 | 14 | # Put configuration results here, so we can easily #include them: 15 | AC_CONFIG_HEADERS([config.h]) 16 | 17 | # library version as current:revision:age 18 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 19 | AC_SUBST([LIB_SO_VERSION], [5:1:0]) 20 | 21 | # Enable "automake" to simplify creating makefiles: 22 | AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror -Wno-portability]) 23 | AM_SILENT_RULES([yes]) 24 | AC_CONFIG_FILES([Makefile 25 | aes-min.pc]) 26 | 27 | #dnl this allows us specify individual linking flags for each target 28 | AM_PROG_CC_C_O 29 | 30 | dnl Initialize Libtool 31 | LT_INIT 32 | 33 | dnl Check if Libtool is present 34 | dnl Libtool is used for building share libraries 35 | AC_PROG_LIBTOOL 36 | 37 | AC_ARG_ENABLE([sbox-small], 38 | AS_HELP_STRING([--enable-sbox-small], [Enable small S-box implementation])) 39 | 40 | AS_IF([test "x$enable_sbox_small" = "xyes"], [ 41 | AC_DEFINE([ENABLE_SBOX_SMALL], [1], [Enable small S-box implementation]) 42 | ]) 43 | AM_CONDITIONAL([ENABLE_SBOX_SMALL], [test "x$enable_sbox_small" = "xyes"]) 44 | 45 | AC_OUTPUT 46 | -------------------------------------------------------------------------------- /gcm-mul-cfg.h: -------------------------------------------------------------------------------- 1 | /** 2 | * gcm_mul_cfg.h 3 | * 4 | * Select which GCM Galois multiplication implementation to use. 5 | */ 6 | 7 | #ifndef GCM_MUL_CFG_H 8 | #define GCM_MUL_CFG_H 9 | 10 | 11 | /////////////////////////////////////////////////////////////////////////////////////////////////// 12 | // Defines 13 | /////////////////////////////////////////////////////////////////////////////////////////////////// 14 | 15 | /* Set an element type that is efficient on the target platform. 1, 2, 4 or 8. 16 | * Same size as platform's unsigned int is probably a good value. 17 | * But for 8-bit platforms, 1 may be better. For 64-bit platforms, 8 is probably good. 18 | * If 1 is used, gcm_u128_struct_from_bytes() etc could simply be 19 | * replaced by memcpy(). */ 20 | #define GCM_U128_ELEMENT_SIZE 4 21 | 22 | // Select little-endian optimisation 23 | #undef GCM_MUL_LITTLE_ENDIAN 24 | 25 | // Control which GCM Galois multiplication implementations are compiled in gcm_mul.c. 26 | 27 | #define GCM_MUL_BIT_BY_BIT 28 | #define GCM_MUL_TABLE_4 29 | #define GCM_MUL_TABLE_8 30 | 31 | 32 | #endif /* !defined( GCM_MUL_CFG_H ) */ 33 | -------------------------------------------------------------------------------- /gcm-mul.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * gcm-mul.c 3 | * 4 | * Functions to support GCM mode. 5 | ****************************************************************************/ 6 | 7 | /***************************************************************************** 8 | * Includes 9 | ****************************************************************************/ 10 | 11 | #include "gcm-mul.h" 12 | 13 | #include 14 | 15 | /***************************************************************************** 16 | * Defines 17 | ****************************************************************************/ 18 | 19 | #define GCM_U128_ELEMENT_SIZE_BITS (8u * GCM_U128_ELEMENT_SIZE) 20 | 21 | #define GCM_U128_STRUCT_INIT_0 { { 0 } } 22 | 23 | /***************************************************************************** 24 | * Local function prototypes 25 | ****************************************************************************/ 26 | 27 | static void gcm_u128_struct_from_bytes(gcm_u128_struct_t * restrict p_dst, const uint8_t p_src[AES_BLOCK_SIZE]); 28 | static void gcm_u128_struct_to_bytes(uint8_t p_dst[AES_BLOCK_SIZE], const gcm_u128_struct_t * p_src); 29 | static void uint128_struct_mul2(gcm_u128_struct_t * restrict p); 30 | static void block_mul256(gcm_u128_struct_t * restrict p); 31 | 32 | /***************************************************************************** 33 | * Local inline functions 34 | ****************************************************************************/ 35 | 36 | /* 37 | * XOR for gcm_u128_struct_t. 38 | * 39 | * In-place XOR all the bits of p_src into p_dst. 40 | */ 41 | static inline void uint128_struct_xor(gcm_u128_struct_t * p_dst, const gcm_u128_struct_t * p_src) 42 | { 43 | uint_fast8_t i; 44 | 45 | for (i = 0; i < GCM_U128_NUM_ELEMENTS; i++) 46 | { 47 | p_dst->element[i] ^= p_src->element[i]; 48 | } 49 | } 50 | 51 | /***************************************************************************** 52 | * Functions 53 | ****************************************************************************/ 54 | 55 | #ifdef GCM_MUL_BIT_BY_BIT 56 | 57 | /* 58 | * Galois 128-bit multiply for GCM mode of encryption. 59 | * 60 | * This implementation uses a bit-by-bit calculation of the multiplication. 61 | * It is the slowest implementation, but requires minimal memory. 62 | */ 63 | void gcm_mul(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key[AES_BLOCK_SIZE]) 64 | { 65 | gcm_u128_struct_t a; 66 | gcm_u128_struct_t result = GCM_U128_STRUCT_INIT_0; 67 | uint_fast8_t i = AES_BLOCK_SIZE - 1u; 68 | uint8_t j_bit = 1u; 69 | 70 | gcm_u128_struct_from_bytes(&a, p_key); 71 | 72 | /* Skip initial uint128_struct_mul2(&result) which is unnecessary when 73 | * result is initially zero. */ 74 | goto start; 75 | 76 | for (;;) 77 | { 78 | for (j_bit = 1u; j_bit != 0; j_bit <<= 1u) 79 | { 80 | uint128_struct_mul2(&result); 81 | start: 82 | if (p_block[i] & j_bit) 83 | { 84 | uint128_struct_xor(&result, &a); 85 | } 86 | } 87 | if (i == 0) 88 | { 89 | break; 90 | } 91 | i--; 92 | } 93 | 94 | gcm_u128_struct_to_bytes(p_block, &result); 95 | } 96 | 97 | #endif // defined(GCM_MUL_BIT_BY_BIT) 98 | 99 | 100 | #ifdef GCM_MUL_TABLE_8 101 | 102 | /* 103 | * Given a key, pre-calculate the large table that is needed for 104 | * gcm_mul_table(), the 8-bit table-driven implementation of GCM multiplication. 105 | */ 106 | void gcm_mul_prepare_table8(gcm_mul_table8_t * restrict p_table, const uint8_t p_key[AES_BLOCK_SIZE]) 107 | { 108 | gcm_u128_struct_t a; 109 | gcm_u128_struct_t block; 110 | uint_fast8_t i_bit = 0x80u; 111 | uint_fast8_t j; 112 | 113 | memset(p_table, 0u, sizeof(*p_table)); 114 | gcm_u128_struct_from_bytes(&a, p_key); 115 | memcpy(block.bytes, p_key, AES_BLOCK_SIZE); 116 | 117 | for (;;) 118 | { 119 | for (j = 255u; j != 0u; j--) 120 | { 121 | if (j & i_bit) 122 | { 123 | uint128_struct_xor(&p_table->key_data[j - 1u], &block); 124 | } 125 | } 126 | i_bit >>= 1u; 127 | if (i_bit == 0u) 128 | break; 129 | uint128_struct_mul2(&a); 130 | gcm_u128_struct_to_bytes(block.bytes, &a); 131 | } 132 | } 133 | 134 | /* 135 | * Galois 128-bit multiply for GCM mode of encryption. 136 | * 137 | * This implementation uses an 8-bit table look-up. 138 | * It is the fastest implementation, but requires a large table pre-calculated 139 | * from the key. 140 | */ 141 | void gcm_mul_table8(uint8_t p_block[AES_BLOCK_SIZE], const gcm_mul_table8_t * p_table) 142 | { 143 | uint8_t block_byte; 144 | gcm_u128_struct_t result = GCM_U128_STRUCT_INIT_0; 145 | uint_fast8_t i = AES_BLOCK_SIZE - 1u; 146 | 147 | /* Skip initial block_mul256(&result) which is unnecessary when 148 | * result is initially zero. */ 149 | goto start; 150 | 151 | for (;;) 152 | { 153 | block_mul256(&result); 154 | start: 155 | block_byte = p_block[i]; 156 | if (block_byte) 157 | { 158 | uint128_struct_xor(&result, &p_table->key_data[block_byte - 1u]); 159 | } 160 | if (i == 0u) 161 | { 162 | break; 163 | } 164 | i--; 165 | } 166 | memcpy(p_block, result.bytes, AES_BLOCK_SIZE); 167 | } 168 | 169 | #endif // defined(GCM_MUL_TABLE_8) 170 | 171 | 172 | #ifdef GCM_MUL_TABLE_4 173 | 174 | /* 175 | * Given a key, pre-calculate the medium-sized table that is needed for 176 | * gcm_mul_table4(), the 4-bit table-driven implementation of GCM multiplication. 177 | */ 178 | void gcm_mul_prepare_table4(gcm_mul_table4_t * restrict p_table, const uint8_t p_key[AES_BLOCK_SIZE]) 179 | { 180 | gcm_u128_struct_t a; 181 | gcm_u128_struct_t block; 182 | uint_fast8_t i_bit = 0x80u; 183 | uint_fast8_t j; 184 | 185 | memset(p_table, 0u, sizeof(*p_table)); 186 | gcm_u128_struct_from_bytes(&a, p_key); 187 | memcpy(block.bytes, p_key, AES_BLOCK_SIZE); 188 | 189 | for (;;) 190 | { 191 | if (i_bit >= 0x10u) 192 | { 193 | for (j = 15u; j != 0u; j--) 194 | { 195 | if (j & (i_bit >> 4u)) 196 | { 197 | uint128_struct_xor(&p_table->key_data_hi[j - 1u], &block); 198 | } 199 | } 200 | } 201 | else 202 | { 203 | for (j = 15u; j != 0u; j--) 204 | { 205 | if (j & i_bit) 206 | { 207 | uint128_struct_xor(&p_table->key_data_lo[j - 1u], &block); 208 | } 209 | } 210 | } 211 | 212 | i_bit >>= 1u; 213 | if (i_bit == 0u) 214 | break; 215 | uint128_struct_mul2(&a); 216 | gcm_u128_struct_to_bytes(block.bytes, &a); 217 | } 218 | } 219 | 220 | /* 221 | * Galois 128-bit multiply for GCM mode of encryption. 222 | * 223 | * This implementation uses an 4-bit table look-up. 224 | * This implementation is faster than the bit-by-bit implementation, but has 225 | * more modest memory requirements for the table pre-calculated from the key, 226 | * compared to the 8-bit table look-up of gcm_mul_table(). 227 | */ 228 | void gcm_mul_table4(uint8_t p_block[AES_BLOCK_SIZE], const gcm_mul_table4_t * p_table) 229 | { 230 | uint8_t block_byte; 231 | uint8_t block_nibble; 232 | gcm_u128_struct_t result = GCM_U128_STRUCT_INIT_0; 233 | uint_fast8_t i = AES_BLOCK_SIZE - 1u; 234 | 235 | /* Skip initial block_mul256(&result) which is unnecessary when 236 | * result is initially zero. */ 237 | goto start; 238 | 239 | for (;;) 240 | { 241 | block_mul256(&result); 242 | start: 243 | block_byte = p_block[i]; 244 | /* High nibble */ 245 | block_nibble = (block_byte >> 4u) & 0xFu; 246 | if (block_nibble) 247 | { 248 | uint128_struct_xor(&result, &p_table->key_data_hi[block_nibble - 1u]); 249 | } 250 | /* Low nibble */ 251 | block_nibble = block_byte & 0xFu; 252 | if (block_nibble) 253 | { 254 | uint128_struct_xor(&result, &p_table->key_data_lo[block_nibble - 1u]); 255 | } 256 | if (i == 0u) 257 | { 258 | break; 259 | } 260 | i--; 261 | } 262 | memcpy(p_block, result.bytes, AES_BLOCK_SIZE); 263 | } 264 | 265 | #endif // defined(GCM_MUL_TABLE_4) 266 | 267 | 268 | /***************************************************************************** 269 | * Local functions 270 | ****************************************************************************/ 271 | 272 | /* 273 | * Convert a multiplicand for GCM Galois 128-bit multiply into a form that can 274 | * be more efficiently manipulated for bit-by-bit calculation of the multiply. 275 | */ 276 | static void gcm_u128_struct_from_bytes(gcm_u128_struct_t * restrict p_dst, const uint8_t p_src[AES_BLOCK_SIZE]) 277 | { 278 | uint_fast8_t i; 279 | uint_fast8_t j; 280 | const uint8_t * p_src_tmp; 281 | gcm_u128_element_t temp; 282 | 283 | p_src_tmp = p_src; 284 | for (i = 0; i < GCM_U128_NUM_ELEMENTS; i++) 285 | { 286 | temp = 0; 287 | for (j = 0; j < GCM_U128_ELEMENT_SIZE; j++) 288 | { 289 | temp = (temp << 8) | *p_src_tmp++; 290 | } 291 | p_dst->element[i] = temp; 292 | } 293 | } 294 | 295 | /* 296 | * Convert the GCM Galois 128-bit multiply special form back into an ordinary 297 | * string of bytes. 298 | */ 299 | static void gcm_u128_struct_to_bytes(uint8_t p_dst[AES_BLOCK_SIZE], const gcm_u128_struct_t * p_src) 300 | { 301 | uint_fast8_t i; 302 | uint_fast8_t j; 303 | uint8_t * p_dst_tmp; 304 | gcm_u128_element_t temp; 305 | 306 | p_dst_tmp = p_dst; 307 | for (i = 0; i < GCM_U128_NUM_ELEMENTS; i++) 308 | { 309 | temp = p_src->element[i]; 310 | for (j = 0; j < GCM_U128_ELEMENT_SIZE; j++) 311 | { 312 | *p_dst_tmp++ = (temp >> (GCM_U128_ELEMENT_SIZE_BITS - 8u)); 313 | temp <<= 8; 314 | } 315 | } 316 | } 317 | 318 | /* 319 | * Galois 128-bit multiply by 2. 320 | * 321 | * Multiply is done in-place on the gcm_u128_struct_t operand. 322 | */ 323 | static void uint128_struct_mul2(gcm_u128_struct_t * restrict p) 324 | { 325 | uint_fast8_t i = 0; 326 | gcm_u128_element_t carry; 327 | gcm_u128_element_t next_carry; 328 | 329 | /* 330 | * This expression is intended to be timing invariant to prevent a timing 331 | * attack due to execution timing dependent on the bits of the GHASH key. 332 | * Check generated assembler from the compiler to confirm it. 333 | * This could be expressed as an 'if' statement, but then it's less likely 334 | * to be timing invariant. 335 | * 336 | * (0xE1u << (GCM_U128_ELEMENT_SIZE_BITS - 8u)) is the reduction poly bits. 337 | * (p->element[GCM_U128_NUM_ELEMENTS - 1u] & 1u) is the check of the MSbit 338 | * to determine if it's necessary to XOR the reduction poly. 339 | * (-(p->element[GCM_U128_NUM_ELEMENTS - 1u] & 1u)) turns it into a mask for 340 | * the bitwise AND. 341 | */ 342 | carry = ((gcm_u128_element_t)0xE1u << (GCM_U128_ELEMENT_SIZE_BITS - 8u)) & (-(p->element[GCM_U128_NUM_ELEMENTS - 1u] & 1u)); 343 | 344 | goto start; 345 | for (i = 0; i < GCM_U128_NUM_ELEMENTS - 1u; i++) 346 | { 347 | carry = next_carry; 348 | start: 349 | next_carry = ((p->element[i] & 1u) << (GCM_U128_ELEMENT_SIZE_BITS - 1u)); 350 | p->element[i] = (p->element[i] >> 1u) ^ carry; 351 | } 352 | p->element[i] = (p->element[i] >> 1u) ^ next_carry; 353 | } 354 | 355 | #if defined(GCM_MUL_LITTLE_ENDIAN) && GCM_U128_ELEMENT_SIZE != 1 356 | 357 | /* 358 | * Galois 128-bit multiply by 2^8. 359 | * 360 | * Multiply is done in-place on the byte array of standard AES block size. 361 | * 362 | * Little-endian specific implementation. 363 | * This implementation requires gcm_u128_element_t to be at least a 16-bit 364 | * integer. I.e. it doesn't work with uint8_t. 365 | */ 366 | static void block_mul256(gcm_u128_struct_t * restrict p) 367 | { 368 | static const uint16_t reduce_table[] = 369 | { 370 | 0x0000u, 0xC201u, 0x8403u, 0x4602u, 0x0807u, 0xCA06u, 0x8C04u, 0x4E05u, 0x100Eu, 0xD20Fu, 0x940Du, 0x560Cu, 0x1809u, 0xDA08u, 0x9C0Au, 0x5E0Bu, 371 | 0x201Cu, 0xE21Du, 0xA41Fu, 0x661Eu, 0x281Bu, 0xEA1Au, 0xAC18u, 0x6E19u, 0x3012u, 0xF213u, 0xB411u, 0x7610u, 0x3815u, 0xFA14u, 0xBC16u, 0x7E17u, 372 | 0x4038u, 0x8239u, 0xC43Bu, 0x063Au, 0x483Fu, 0x8A3Eu, 0xCC3Cu, 0x0E3Du, 0x5036u, 0x9237u, 0xD435u, 0x1634u, 0x5831u, 0x9A30u, 0xDC32u, 0x1E33u, 373 | 0x6024u, 0xA225u, 0xE427u, 0x2626u, 0x6823u, 0xAA22u, 0xEC20u, 0x2E21u, 0x702Au, 0xB22Bu, 0xF429u, 0x3628u, 0x782Du, 0xBA2Cu, 0xFC2Eu, 0x3E2Fu, 374 | 0x8070u, 0x4271u, 0x0473u, 0xC672u, 0x8877u, 0x4A76u, 0x0C74u, 0xCE75u, 0x907Eu, 0x527Fu, 0x147Du, 0xD67Cu, 0x9879u, 0x5A78u, 0x1C7Au, 0xDE7Bu, 375 | 0xA06Cu, 0x626Du, 0x246Fu, 0xE66Eu, 0xA86Bu, 0x6A6Au, 0x2C68u, 0xEE69u, 0xB062u, 0x7263u, 0x3461u, 0xF660u, 0xB865u, 0x7A64u, 0x3C66u, 0xFE67u, 376 | 0xC048u, 0x0249u, 0x444Bu, 0x864Au, 0xC84Fu, 0x0A4Eu, 0x4C4Cu, 0x8E4Du, 0xD046u, 0x1247u, 0x5445u, 0x9644u, 0xD841u, 0x1A40u, 0x5C42u, 0x9E43u, 377 | 0xE054u, 0x2255u, 0x6457u, 0xA656u, 0xE853u, 0x2A52u, 0x6C50u, 0xAE51u, 0xF05Au, 0x325Bu, 0x7459u, 0xB658u, 0xF85Du, 0x3A5Cu, 0x7C5Eu, 0xBE5Fu, 378 | 0x00E1u, 0xC2E0u, 0x84E2u, 0x46E3u, 0x08E6u, 0xCAE7u, 0x8CE5u, 0x4EE4u, 0x10EFu, 0xD2EEu, 0x94ECu, 0x56EDu, 0x18E8u, 0xDAE9u, 0x9CEBu, 0x5EEAu, 379 | 0x20FDu, 0xE2FCu, 0xA4FEu, 0x66FFu, 0x28FAu, 0xEAFBu, 0xACF9u, 0x6EF8u, 0x30F3u, 0xF2F2u, 0xB4F0u, 0x76F1u, 0x38F4u, 0xFAF5u, 0xBCF7u, 0x7EF6u, 380 | 0x40D9u, 0x82D8u, 0xC4DAu, 0x06DBu, 0x48DEu, 0x8ADFu, 0xCCDDu, 0x0EDCu, 0x50D7u, 0x92D6u, 0xD4D4u, 0x16D5u, 0x58D0u, 0x9AD1u, 0xDCD3u, 0x1ED2u, 381 | 0x60C5u, 0xA2C4u, 0xE4C6u, 0x26C7u, 0x68C2u, 0xAAC3u, 0xECC1u, 0x2EC0u, 0x70CBu, 0xB2CAu, 0xF4C8u, 0x36C9u, 0x78CCu, 0xBACDu, 0xFCCFu, 0x3ECEu, 382 | 0x8091u, 0x4290u, 0x0492u, 0xC693u, 0x8896u, 0x4A97u, 0x0C95u, 0xCE94u, 0x909Fu, 0x529Eu, 0x149Cu, 0xD69Du, 0x9898u, 0x5A99u, 0x1C9Bu, 0xDE9Au, 383 | 0xA08Du, 0x628Cu, 0x248Eu, 0xE68Fu, 0xA88Au, 0x6A8Bu, 0x2C89u, 0xEE88u, 0xB083u, 0x7282u, 0x3480u, 0xF681u, 0xB884u, 0x7A85u, 0x3C87u, 0xFE86u, 384 | 0xC0A9u, 0x02A8u, 0x44AAu, 0x86ABu, 0xC8AEu, 0x0AAFu, 0x4CADu, 0x8EACu, 0xD0A7u, 0x12A6u, 0x54A4u, 0x96A5u, 0xD8A0u, 0x1AA1u, 0x5CA3u, 0x9EA2u, 385 | 0xE0B5u, 0x22B4u, 0x64B6u, 0xA6B7u, 0xE8B2u, 0x2AB3u, 0x6CB1u, 0xAEB0u, 0xF0BBu, 0x32BAu, 0x74B8u, 0xB6B9u, 0xF8BCu, 0x3ABDu, 0x7CBFu, 0xBEBEu, 386 | }; 387 | uint_fast8_t i = 0; 388 | gcm_u128_element_t carry; 389 | gcm_u128_element_t next_carry; 390 | 391 | carry = reduce_table[p->bytes[AES_BLOCK_SIZE - 1u]]; 392 | 393 | goto start; 394 | for (; i < GCM_U128_NUM_ELEMENTS - 1u; i++) 395 | { 396 | carry = next_carry; 397 | start: 398 | next_carry = p->element[i] >> (GCM_U128_ELEMENT_SIZE_BITS - 8u); 399 | p->element[i] = (p->element[i] << 8u) ^ carry; 400 | } 401 | p->element[i] = (p->element[i] << 8u) ^ next_carry; 402 | } 403 | 404 | #else // !defined(GCM_MUL_LITTLE_ENDIAN) 405 | 406 | /* 407 | * Galois 128-bit multiply by 2^8. 408 | * 409 | * Multiply is done in-place on the byte array of standard AES block size. 410 | * 411 | * Generic implementation that should work for either big- or little-endian, 412 | * albeit not necessarily as fast. 413 | */ 414 | static void block_mul256(gcm_u128_struct_t * restrict p) 415 | { 416 | static const uint16_t reduce_table[] = 417 | { 418 | 0x0000u, 0x01C2u, 0x0384u, 0x0246u, 0x0708u, 0x06CAu, 0x048Cu, 0x054Eu, 0x0E10u, 0x0FD2u, 0x0D94u, 0x0C56u, 0x0918u, 0x08DAu, 0x0A9Cu, 0x0B5Eu, 419 | 0x1C20u, 0x1DE2u, 0x1FA4u, 0x1E66u, 0x1B28u, 0x1AEAu, 0x18ACu, 0x196Eu, 0x1230u, 0x13F2u, 0x11B4u, 0x1076u, 0x1538u, 0x14FAu, 0x16BCu, 0x177Eu, 420 | 0x3840u, 0x3982u, 0x3BC4u, 0x3A06u, 0x3F48u, 0x3E8Au, 0x3CCCu, 0x3D0Eu, 0x3650u, 0x3792u, 0x35D4u, 0x3416u, 0x3158u, 0x309Au, 0x32DCu, 0x331Eu, 421 | 0x2460u, 0x25A2u, 0x27E4u, 0x2626u, 0x2368u, 0x22AAu, 0x20ECu, 0x212Eu, 0x2A70u, 0x2BB2u, 0x29F4u, 0x2836u, 0x2D78u, 0x2CBAu, 0x2EFCu, 0x2F3Eu, 422 | 0x7080u, 0x7142u, 0x7304u, 0x72C6u, 0x7788u, 0x764Au, 0x740Cu, 0x75CEu, 0x7E90u, 0x7F52u, 0x7D14u, 0x7CD6u, 0x7998u, 0x785Au, 0x7A1Cu, 0x7BDEu, 423 | 0x6CA0u, 0x6D62u, 0x6F24u, 0x6EE6u, 0x6BA8u, 0x6A6Au, 0x682Cu, 0x69EEu, 0x62B0u, 0x6372u, 0x6134u, 0x60F6u, 0x65B8u, 0x647Au, 0x663Cu, 0x67FEu, 424 | 0x48C0u, 0x4902u, 0x4B44u, 0x4A86u, 0x4FC8u, 0x4E0Au, 0x4C4Cu, 0x4D8Eu, 0x46D0u, 0x4712u, 0x4554u, 0x4496u, 0x41D8u, 0x401Au, 0x425Cu, 0x439Eu, 425 | 0x54E0u, 0x5522u, 0x5764u, 0x56A6u, 0x53E8u, 0x522Au, 0x506Cu, 0x51AEu, 0x5AF0u, 0x5B32u, 0x5974u, 0x58B6u, 0x5DF8u, 0x5C3Au, 0x5E7Cu, 0x5FBEu, 426 | 0xE100u, 0xE0C2u, 0xE284u, 0xE346u, 0xE608u, 0xE7CAu, 0xE58Cu, 0xE44Eu, 0xEF10u, 0xEED2u, 0xEC94u, 0xED56u, 0xE818u, 0xE9DAu, 0xEB9Cu, 0xEA5Eu, 427 | 0xFD20u, 0xFCE2u, 0xFEA4u, 0xFF66u, 0xFA28u, 0xFBEAu, 0xF9ACu, 0xF86Eu, 0xF330u, 0xF2F2u, 0xF0B4u, 0xF176u, 0xF438u, 0xF5FAu, 0xF7BCu, 0xF67Eu, 428 | 0xD940u, 0xD882u, 0xDAC4u, 0xDB06u, 0xDE48u, 0xDF8Au, 0xDDCCu, 0xDC0Eu, 0xD750u, 0xD692u, 0xD4D4u, 0xD516u, 0xD058u, 0xD19Au, 0xD3DCu, 0xD21Eu, 429 | 0xC560u, 0xC4A2u, 0xC6E4u, 0xC726u, 0xC268u, 0xC3AAu, 0xC1ECu, 0xC02Eu, 0xCB70u, 0xCAB2u, 0xC8F4u, 0xC936u, 0xCC78u, 0xCDBAu, 0xCFFCu, 0xCE3Eu, 430 | 0x9180u, 0x9042u, 0x9204u, 0x93C6u, 0x9688u, 0x974Au, 0x950Cu, 0x94CEu, 0x9F90u, 0x9E52u, 0x9C14u, 0x9DD6u, 0x9898u, 0x995Au, 0x9B1Cu, 0x9ADEu, 431 | 0x8DA0u, 0x8C62u, 0x8E24u, 0x8FE6u, 0x8AA8u, 0x8B6Au, 0x892Cu, 0x88EEu, 0x83B0u, 0x8272u, 0x8034u, 0x81F6u, 0x84B8u, 0x857Au, 0x873Cu, 0x86FEu, 432 | 0xA9C0u, 0xA802u, 0xAA44u, 0xAB86u, 0xAEC8u, 0xAF0Au, 0xAD4Cu, 0xAC8Eu, 0xA7D0u, 0xA612u, 0xA454u, 0xA596u, 0xA0D8u, 0xA11Au, 0xA35Cu, 0xA29Eu, 433 | 0xB5E0u, 0xB422u, 0xB664u, 0xB7A6u, 0xB2E8u, 0xB32Au, 0xB16Cu, 0xB0AEu, 0xBBF0u, 0xBA32u, 0xB874u, 0xB9B6u, 0xBCF8u, 0xBD3Au, 0xBF7Cu, 0xBEBEu, 434 | }; 435 | #if 0 436 | uint_fast8_t i; 437 | #endif 438 | uint_fast16_t reduce; 439 | 440 | reduce = reduce_table[p->bytes[AES_BLOCK_SIZE - 1u]]; 441 | #if 0 442 | for (i = AES_BLOCK_SIZE - 1u; i != 0; i--) 443 | { 444 | p->bytes[i] = p->bytes[i - 1u]; 445 | } 446 | #else 447 | memmove(p->bytes + 1, p->bytes, AES_BLOCK_SIZE - 1u); 448 | #endif 449 | p->bytes[0] = reduce >> 8; 450 | p->bytes[1] ^= reduce; 451 | } 452 | 453 | #endif // !defined(GCM_MUL_LITTLE_ENDIAN) 454 | -------------------------------------------------------------------------------- /gcm-mul.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * gcm-mul.h 3 | * 4 | * Functions to support GCM mode. 5 | ****************************************************************************/ 6 | 7 | #ifndef GCM_MUL_H 8 | #define GCM_MUL_H 9 | 10 | /***************************************************************************** 11 | * Includes 12 | ****************************************************************************/ 13 | 14 | #include "aes-min.h" 15 | 16 | #include "gcm-mul-cfg.h" 17 | 18 | 19 | /***************************************************************************** 20 | * Defines 21 | ****************************************************************************/ 22 | 23 | #ifndef GCM_U128_ELEMENT_SIZE 24 | #define GCM_U128_ELEMENT_SIZE 4 25 | #endif 26 | 27 | #define GCM_U128_NUM_ELEMENTS (AES_BLOCK_SIZE / GCM_U128_ELEMENT_SIZE) 28 | 29 | /***************************************************************************** 30 | * Types 31 | ****************************************************************************/ 32 | 33 | #if GCM_U128_ELEMENT_SIZE == 1 34 | typedef uint8_t gcm_u128_element_t; 35 | #elif GCM_U128_ELEMENT_SIZE == 2 36 | typedef uint16_t gcm_u128_element_t; 37 | #elif GCM_U128_ELEMENT_SIZE == 4 38 | typedef uint32_t gcm_u128_element_t; 39 | #elif GCM_U128_ELEMENT_SIZE == 8 40 | typedef uint64_t gcm_u128_element_t; 41 | #else 42 | #error Invalid GCM_U128_ELEMENT_SIZE 43 | #endif 44 | 45 | /* 46 | * This struct is basically to enable big-integer calculations in the 128-bit 47 | * Galois field. The struct is fixed size for this purpose. The functions that 48 | * operate on it are specialised to do the bit-reversed operations needed 49 | * specifically for the Galois 128-bit multiply used in the GCM algorithm. 50 | */ 51 | typedef union 52 | { 53 | gcm_u128_element_t element[GCM_U128_NUM_ELEMENTS]; 54 | uint16_t reduce_bytes; 55 | uint8_t bytes[AES_BLOCK_SIZE]; 56 | } gcm_u128_struct_t; 57 | 58 | typedef struct 59 | { 60 | gcm_u128_struct_t key_data[255]; 61 | } gcm_mul_table8_t; 62 | 63 | typedef struct 64 | { 65 | gcm_u128_struct_t key_data_hi[15]; 66 | gcm_u128_struct_t key_data_lo[15]; 67 | } gcm_mul_table4_t; 68 | 69 | /***************************************************************************** 70 | * Functions 71 | ****************************************************************************/ 72 | 73 | #ifdef GCM_MUL_BIT_BY_BIT 74 | 75 | void gcm_mul(uint8_t p_block[AES_BLOCK_SIZE], const uint8_t p_key[AES_BLOCK_SIZE]); 76 | 77 | #endif 78 | 79 | 80 | #ifdef GCM_MUL_TABLE_8 81 | 82 | void gcm_mul_prepare_table8(gcm_mul_table8_t * restrict p_table, const uint8_t p_key[AES_BLOCK_SIZE]); 83 | void gcm_mul_table8(uint8_t p_block[AES_BLOCK_SIZE], const gcm_mul_table8_t * p_table); 84 | 85 | #endif 86 | 87 | 88 | #ifdef GCM_MUL_TABLE_4 89 | 90 | void gcm_mul_prepare_table4(gcm_mul_table4_t * restrict p_table, const uint8_t p_key[AES_BLOCK_SIZE]); 91 | void gcm_mul_table4(uint8_t p_block[AES_BLOCK_SIZE], const gcm_mul_table4_t * p_table); 92 | 93 | #endif 94 | 95 | 96 | #endif /* !defined(GCM_MUL_H) */ 97 | -------------------------------------------------------------------------------- /python/gcm-mul-reduce-table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | REDUCE_BYTE = 0xE1 4 | 5 | reduce_table = [0] * 256 6 | for i in range(8): 7 | i_bit = 1 << i 8 | for j in range(256): 9 | if j & i_bit: 10 | reduce_table[j] ^= (REDUCE_BYTE << (i + 1)) 11 | 12 | for j in range(256): 13 | if j and (j % 16) == 0: 14 | print() 15 | reduce_value = reduce_table[j] 16 | if False: 17 | # Swap endianness. 18 | reduce_value = ((reduce_value & 0xFF) << 8) | ((reduce_value >> 8) & 0xFF) 19 | if True: 20 | print('0x{:04X}u, '.format(reduce_value), end='') 21 | else: 22 | print('{{ {{ 0x{:02X}u, 0x{:02X}u, }} }}, '.format(reduce_value >> 8, reduce_value & 0xFF), end='') 23 | print() 24 | -------------------------------------------------------------------------------- /python/gcm-process-test-vectors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import codecs 4 | import re 5 | import fileinput 6 | 7 | bracket_re = re.compile(r'^\[\s*(\w+)\s*=\s*(\w+)\s*\]$') 8 | params_re = re.compile(r'^\s*(\w+)\s*=\s*(\w*)\s*$') 9 | 10 | group_params = {} 11 | params = {} 12 | num_out = 0 13 | 14 | def to_c_init(hex_str): 15 | if hex_str: 16 | bytes_init = ', '.join([ '0x{:02X}u'.format(x) for x in codecs.decode(hex_str, 'hex') ]) 17 | return '(const uint8_t []){ ' + bytes_init + ', }' 18 | else: 19 | return 'NULL' 20 | 21 | def c_len(key, hex_str): 22 | data_len = len(hex_str) // 2 23 | return data_len 24 | 25 | TEMPLATE = ''' {{ 26 | // {} 27 | .p_key = {}, 28 | .p_iv = {}, 29 | .aad_len = {}, 30 | .p_aad = {}, 31 | .pt_len = {}, 32 | .p_pt = {}, 33 | .ct_len = {}, 34 | .p_ct = {}, 35 | .tag_len = {}, 36 | .p_tag = {}, 37 | }},''' 38 | 39 | for line_num, line in enumerate(fileinput.input()): 40 | line = line.rstrip() 41 | #print(line) 42 | 43 | if not line: 44 | if params and group_params['Keylen'] == 128 and group_params['IVlen'] == 96: 45 | #print(group_params) 46 | #print(params) 47 | #print() 48 | num_out += 1 49 | try: 50 | print(TEMPLATE.format( 51 | num_out - 1, 52 | to_c_init(params['Key']), 53 | to_c_init(params['IV']), 54 | c_len('AAD', params['AAD']), 55 | to_c_init(params['AAD']), 56 | c_len('PT', params['PT']), 57 | to_c_init(params['PT']), 58 | c_len('CT', params['CT']), 59 | to_c_init(params['CT']), 60 | c_len('Tag', params['Tag']), 61 | to_c_init(params['Tag']), 62 | )) 63 | except Exception: 64 | print(line_num, num_out, params) 65 | raise 66 | params = {} 67 | continue 68 | 69 | if line[0] == '#': 70 | continue 71 | 72 | m = bracket_re.match(line) 73 | if m: 74 | key = m.group(1) 75 | value = m.group(2) 76 | try: 77 | value = int(value) 78 | except Exception: 79 | pass 80 | group_params[key] = value 81 | #print(key, value) 82 | else: 83 | m = params_re.match(line) 84 | if m: 85 | key = m.group(1) 86 | value = m.group(2) 87 | params[key] = value 88 | #print(key, value) 89 | print('\n\n#define GCM_NUM_VECTORS {}'.format(num_out)) 90 | -------------------------------------------------------------------------------- /python/gmul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | def gmul(a, b): 6 | a = int(a) 7 | b = int(b) 8 | result = 0 9 | while a: 10 | if a & 1: 11 | result ^= b 12 | a >>= 1 13 | b <<= 1 14 | if b & 0x100: 15 | b ^= 0x11B 16 | return result 17 | 18 | 19 | if __name__ == "__main__": 20 | print(gmul(sys.argv[1], sys.argv[2])) 21 | 22 | -------------------------------------------------------------------------------- /python/parse-vectors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import codecs 4 | #from pprint import pprint 5 | 6 | key_map = { 7 | 'COUNT': 'count', 8 | 'KEY': 'key', 9 | 'PLAINTEXT': 'plain', 10 | 'CIPHERTEXT': 'cipher', 11 | } 12 | 13 | def c_escaped_string(s, encoding='latin'): 14 | if isinstance(s, str): 15 | s = s.encode(encoding) 16 | s = s.decode('latin') 17 | result = '' 18 | for c in s: 19 | if c in '\\"': 20 | result += '\\' + c 21 | elif not (32 <= ord(c) < 127): 22 | result += '\\%03o' % ord(c) 23 | else: 24 | result += c 25 | return '"' + result + '"' 26 | 27 | def byte_string_to_c_array_init(byte_string): 28 | return ", ".join("0x{:02X}".format(c) for c in byte_string) 29 | 30 | def vectors_iter(fileobj): 31 | for line in fileobj: 32 | line = line.strip() 33 | if "[ENCRYPT]" in line: 34 | break 35 | for line in fileobj: 36 | line = line.strip() 37 | if "[DECRYPT]" in line: 38 | break 39 | if line.startswith("COUNT"): 40 | parts = line.split("=") 41 | count = int(parts[1].strip()) 42 | #yield count 43 | test_data = { 'count': count } 44 | for line in fileobj: 45 | line = line.strip() 46 | if not line: 47 | yield test_data 48 | break 49 | key, valuestr = [ a.strip() for a in line.split("=") ] 50 | key = key_map.get(key, key) 51 | value = codecs.decode(valuestr, "hex") 52 | test_data[key] = value 53 | 54 | def files_vectors_iter(filenames): 55 | for setnum, filename in enumerate(filenames): 56 | with open(filename, "r") as f: 57 | for test_data in vectors_iter(f): 58 | test_data['set'] = setnum 59 | yield test_data 60 | 61 | def main(): 62 | import os.path 63 | import sys 64 | 65 | filenames = sys.argv[1:] 66 | vectors_list = [] 67 | set_names = list(filenames) 68 | #set_names = [ '"', '\\', 'abc'] 69 | print(""" 70 | /* This file was generated by Python program {} 71 | from the AES KAT (Known Answer Tests), using the following command: 72 | 73 | {} 74 | 75 | This file should not be edited manually. 76 | 77 | It is used by tests/aes-vectors-test.c. 78 | */ 79 | """.format(os.path.basename(sys.argv[0]), " ".join(sys.argv))) 80 | for test_data in files_vectors_iter(filenames): 81 | #pprint(test_data) 82 | vector_prefix = "set{}count{}".format(test_data['set'], test_data['count']) 83 | for key in ('key', 'plain', 'cipher'): 84 | if key in test_data: 85 | array_data = byte_string_to_c_array_init(test_data[key]) 86 | print("const uint8_t {}{}[] = {{ {} }};".format(vector_prefix, key, array_data)) 87 | 88 | print("const vector_data_t {} = {{".format(vector_prefix)) 89 | print(" .set_num = {},".format(test_data['set'])) 90 | print(" .count = {},".format(test_data['count'])) 91 | for key in ('key', 'plain', 'cipher'): 92 | if key in test_data: 93 | print(" .{} = {}{},".format(key, vector_prefix, key)) 94 | else: 95 | print(" .{} = NULL,".format(key)) 96 | print("};\n") 97 | vectors_list.append(vector_prefix) 98 | 99 | print("const vector_data_t * const test_vectors[] = {") 100 | for vector_name in vectors_list: 101 | print(" &{},".format(vector_name)) 102 | print("};\n") 103 | 104 | print("const char * const set_names[] = {") 105 | for set_name in set_names: 106 | print(' {},'.format(c_escaped_string(set_name))) 107 | print("};\n") 108 | 109 | if __name__ == "__main__": 110 | main() 111 | 112 | -------------------------------------------------------------------------------- /python/pow254test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | 5 | from bisect import bisect_left 6 | 7 | from gmul import gmul 8 | 9 | def delta_gen(i): 10 | ii = iter(i) 11 | prev = next(ii) 12 | for a in ii: 13 | yield(a - prev) 14 | prev = a 15 | 16 | def index(a, x): 17 | 'Locate the leftmost value exactly equal to x' 18 | i = bisect_left(a, x) 19 | if i != len(a) and a[i] == x: 20 | return i 21 | raise ValueError 22 | 23 | def brauer_gen(fd): 24 | for line in fd: 25 | line = line.strip() 26 | num_line, tag = line.rsplit(" ", 1) 27 | if tag == "b": 28 | nums = tuple( int(x) for x in num_line.split(" ") ) 29 | deltas = tuple(delta_gen(nums)) 30 | indices = tuple( index(nums, x) for i, x in enumerate(delta_gen(nums)) ) 31 | yield indices 32 | 33 | def main(): 34 | best = (-100, ()) 35 | with open("ac0254.txt") as f: 36 | for a in brauer_gen(f): 37 | #print(a) 38 | count_zeros = sum(1 if i==x else 0 for i, x in enumerate(a)) 39 | non_zero_indices_for_min = tuple(99 if i==x else x for i, x in enumerate(a)) 40 | non_zero_indices_for_max = tuple(0 if i==x else x for i, x in enumerate(a)) 41 | delta_indices = tuple(i - x for i, x in enumerate(a)) 42 | worst_delta = max(delta_indices) 43 | min_non_zero_index = min(non_zero_indices_for_min) 44 | max_non_zero_index = max(non_zero_indices_for_max) 45 | #print(" ", worst_delta) 46 | 47 | if 0: 48 | if worst_delta >= best[1]: 49 | best = (worst_delta, a) 50 | print(best) 51 | if 1: 52 | if worst_delta <= 11 and min_non_zero_index >= 1 and max_non_zero_index <= 3 and count_zeros >= 7: 53 | print((worst_delta, count_zeros, (min_non_zero_index, max_non_zero_index), a)) 54 | 55 | #print("Best:", best) 56 | 57 | 58 | if __name__ == "__main__": 59 | main() 60 | 61 | -------------------------------------------------------------------------------- /tests/aes-encrypt-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "aes-min.h" 3 | #include "aes-print-block.h" 4 | 5 | #include 6 | #include 7 | 8 | 9 | static const uint8_t key_0[AES128_KEY_SIZE] = 10 | { 11 | 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 12 | }; 13 | static const uint8_t plain_0[AES128_KEY_SIZE] = 14 | { 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 16 | }; 17 | static const uint8_t encrypt_0_ref[AES128_KEY_SCHEDULE_SIZE] = 18 | { 19 | 0x0e, 0xdd, 0x33, 0xd3, 0xc6, 0x21, 0xe5, 0x46, 0x45, 0x5b, 0xd8, 0xba, 0x14, 0x18, 0xbe, 0xc8 20 | }; 21 | 22 | static bool encrypt_test(const uint8_t p_key[AES128_KEY_SIZE], 23 | const uint8_t p_plain[AES_BLOCK_SIZE], 24 | const uint8_t p_encrypted[AES_BLOCK_SIZE], 25 | const char * p_id, bool use_otfks) 26 | { 27 | uint8_t key_schedule[AES128_KEY_SCHEDULE_SIZE]; 28 | uint8_t block[AES_BLOCK_SIZE]; 29 | uint8_t otfks_decrypt_start_key[AES128_KEY_SIZE]; 30 | uint8_t key_work[AES128_KEY_SIZE]; 31 | 32 | if (use_otfks) 33 | { 34 | memcpy(otfks_decrypt_start_key, p_key, AES128_KEY_SIZE); 35 | aes128_otfks_decrypt_start_key(otfks_decrypt_start_key); 36 | } 37 | else 38 | { 39 | aes128_key_schedule(key_schedule, p_key); 40 | } 41 | 42 | memcpy(block, p_plain, AES_BLOCK_SIZE); 43 | if (use_otfks) 44 | { 45 | memcpy(key_work, p_key, AES128_KEY_SIZE); 46 | aes128_otfks_encrypt(block, key_work); 47 | } 48 | else 49 | { 50 | aes128_encrypt(block, key_schedule); 51 | } 52 | 53 | printf("Encrypt %s output:\n", p_id); 54 | print_block_hex(block, AES_BLOCK_SIZE); 55 | 56 | if (memcmp(block, p_encrypted, AES_BLOCK_SIZE) != 0) 57 | return 0; 58 | 59 | if (use_otfks) 60 | { 61 | memcpy(key_work, otfks_decrypt_start_key, AES128_KEY_SIZE); 62 | aes128_otfks_decrypt(block, key_work); 63 | } 64 | else 65 | { 66 | aes128_decrypt(block, key_schedule); 67 | } 68 | 69 | printf("Decrypt %s output:\n", p_id); 70 | print_block_hex(block, AES_BLOCK_SIZE); 71 | printf("\n"); 72 | 73 | return (memcmp(block, p_plain, AES_BLOCK_SIZE) == 0); 74 | } 75 | 76 | int main(int argc, char **argv) 77 | { 78 | bool is_okay; 79 | 80 | (void)argc; 81 | (void)argv; 82 | 83 | is_okay = encrypt_test(key_0, plain_0, encrypt_0_ref, "0", false); 84 | if (!is_okay) 85 | return 1; 86 | is_okay = encrypt_test(key_0, plain_0, encrypt_0_ref, "0 OTFKS", true); 87 | if (!is_okay) 88 | return 1; 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /tests/aes-inv-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "aes-print-block.h" 3 | 4 | #include 5 | 6 | uint8_t _aes_inv_for_test(uint8_t a); 7 | 8 | /* See: 9 | * gf2_8_inv[] in http://www.lomont.org/Software/Misc/AES/Rijndael.cpp 10 | */ 11 | static const uint8_t inv_ref[256u] = 12 | { 13 | 0x00, 0x01, 0x8D, 0xF6, 0xCB, 0x52, 0x7B, 0xD1, 0xE8, 0x4F, 0x29, 0xC0, 0xB0, 0xE1, 0xE5, 0xC7, 14 | 0x74, 0xB4, 0xAA, 0x4B, 0x99, 0x2B, 0x60, 0x5F, 0x58, 0x3F, 0xFD, 0xCC, 0xFF, 0x40, 0xEE, 0xB2, 15 | 0x3A, 0x6E, 0x5A, 0xF1, 0x55, 0x4D, 0xA8, 0xC9, 0xC1, 0x0A, 0x98, 0x15, 0x30, 0x44, 0xA2, 0xC2, 16 | 0x2C, 0x45, 0x92, 0x6C, 0xF3, 0x39, 0x66, 0x42, 0xF2, 0x35, 0x20, 0x6F, 0x77, 0xBB, 0x59, 0x19, 17 | 0x1D, 0xFE, 0x37, 0x67, 0x2D, 0x31, 0xF5, 0x69, 0xA7, 0x64, 0xAB, 0x13, 0x54, 0x25, 0xE9, 0x09, 18 | 0xED, 0x5C, 0x05, 0xCA, 0x4C, 0x24, 0x87, 0xBF, 0x18, 0x3E, 0x22, 0xF0, 0x51, 0xEC, 0x61, 0x17, 19 | 0x16, 0x5E, 0xAF, 0xD3, 0x49, 0xA6, 0x36, 0x43, 0xF4, 0x47, 0x91, 0xDF, 0x33, 0x93, 0x21, 0x3B, 20 | 0x79, 0xB7, 0x97, 0x85, 0x10, 0xB5, 0xBA, 0x3C, 0xB6, 0x70, 0xD0, 0x06, 0xA1, 0xFA, 0x81, 0x82, 21 | 0x83, 0x7E, 0x7F, 0x80, 0x96, 0x73, 0xBE, 0x56, 0x9B, 0x9E, 0x95, 0xD9, 0xF7, 0x02, 0xB9, 0xA4, 22 | 0xDE, 0x6A, 0x32, 0x6D, 0xD8, 0x8A, 0x84, 0x72, 0x2A, 0x14, 0x9F, 0x88, 0xF9, 0xDC, 0x89, 0x9A, 23 | 0xFB, 0x7C, 0x2E, 0xC3, 0x8F, 0xB8, 0x65, 0x48, 0x26, 0xC8, 0x12, 0x4A, 0xCE, 0xE7, 0xD2, 0x62, 24 | 0x0C, 0xE0, 0x1F, 0xEF, 0x11, 0x75, 0x78, 0x71, 0xA5, 0x8E, 0x76, 0x3D, 0xBD, 0xBC, 0x86, 0x57, 25 | 0x0B, 0x28, 0x2F, 0xA3, 0xDA, 0xD4, 0xE4, 0x0F, 0xA9, 0x27, 0x53, 0x04, 0x1B, 0xFC, 0xAC, 0xE6, 26 | 0x7A, 0x07, 0xAE, 0x63, 0xC5, 0xDB, 0xE2, 0xEA, 0x94, 0x8B, 0xC4, 0xD5, 0x9D, 0xF8, 0x90, 0x6B, 27 | 0xB1, 0x0D, 0xD6, 0xEB, 0xC6, 0x0E, 0xCF, 0xAD, 0x08, 0x4E, 0xD7, 0xE3, 0x5D, 0x50, 0x1E, 0xB3, 28 | 0x5B, 0x23, 0x38, 0x34, 0x68, 0x46, 0x03, 0x8C, 0xDD, 0x9C, 0x7D, 0xA0, 0xCD, 0x1A, 0x41, 0x1C 29 | }; 30 | 31 | 32 | int main(int argc, char **argv) 33 | { 34 | size_t i; 35 | uint8_t inv_out[256u]; 36 | 37 | (void)argc; 38 | (void)argv; 39 | 40 | for (i = 0; i < 256u; i++) 41 | { 42 | inv_out[i] = _aes_inv_for_test(i); 43 | } 44 | 45 | printf("AES Galois inverse array:\n"); 46 | for (i = 0; i < 256u; i += 16u) 47 | { 48 | print_block_hex(&inv_out[i], 16u); 49 | } 50 | 51 | return memcmp(inv_out, inv_ref, 256u) ? 1 : 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /tests/aes-key-schedule-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "aes-min.h" 3 | #include "aes-print-block.h" 4 | 5 | #include 6 | #include 7 | 8 | 9 | static const uint8_t key_0[AES128_KEY_SIZE] = 10 | { 11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 12 | }; 13 | static const uint8_t key_0_ref[AES128_KEY_SCHEDULE_SIZE] = 14 | { 15 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 16 | 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 0x62, 0x63, 0x63, 0x63, 17 | 0x9b, 0x98, 0x98, 0xc9, 0xf9, 0xfb, 0xfb, 0xaa, 0x9b, 0x98, 0x98, 0xc9, 0xf9, 0xfb, 0xfb, 0xaa, 18 | 0x90, 0x97, 0x34, 0x50, 0x69, 0x6c, 0xcf, 0xfa, 0xf2, 0xf4, 0x57, 0x33, 0x0b, 0x0f, 0xac, 0x99, 19 | 0xee, 0x06, 0xda, 0x7b, 0x87, 0x6a, 0x15, 0x81, 0x75, 0x9e, 0x42, 0xb2, 0x7e, 0x91, 0xee, 0x2b, 20 | 0x7f, 0x2e, 0x2b, 0x88, 0xf8, 0x44, 0x3e, 0x09, 0x8d, 0xda, 0x7c, 0xbb, 0xf3, 0x4b, 0x92, 0x90, 21 | 0xec, 0x61, 0x4b, 0x85, 0x14, 0x25, 0x75, 0x8c, 0x99, 0xff, 0x09, 0x37, 0x6a, 0xb4, 0x9b, 0xa7, 22 | 0x21, 0x75, 0x17, 0x87, 0x35, 0x50, 0x62, 0x0b, 0xac, 0xaf, 0x6b, 0x3c, 0xc6, 0x1b, 0xf0, 0x9b, 23 | 0x0e, 0xf9, 0x03, 0x33, 0x3b, 0xa9, 0x61, 0x38, 0x97, 0x06, 0x0a, 0x04, 0x51, 0x1d, 0xfa, 0x9f, 24 | 0xb1, 0xd4, 0xd8, 0xe2, 0x8a, 0x7d, 0xb9, 0xda, 0x1d, 0x7b, 0xb3, 0xde, 0x4c, 0x66, 0x49, 0x41, 25 | 0xb4, 0xef, 0x5b, 0xcb, 0x3e, 0x92, 0xe2, 0x11, 0x23, 0xe9, 0x51, 0xcf, 0x6f, 0x8f, 0x18, 0x8e 26 | }; 27 | 28 | static const uint8_t key_1[AES128_KEY_SIZE] = 29 | { 30 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 31 | }; 32 | static const uint8_t key_1_ref[AES128_KEY_SCHEDULE_SIZE] = 33 | { 34 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 35 | 0xe8, 0xe9, 0xe9, 0xe9, 0x17, 0x16, 0x16, 0x16, 0xe8, 0xe9, 0xe9, 0xe9, 0x17, 0x16, 0x16, 0x16, 36 | 0xad, 0xae, 0xae, 0x19, 0xba, 0xb8, 0xb8, 0x0f, 0x52, 0x51, 0x51, 0xe6, 0x45, 0x47, 0x47, 0xf0, 37 | 0x09, 0x0e, 0x22, 0x77, 0xb3, 0xb6, 0x9a, 0x78, 0xe1, 0xe7, 0xcb, 0x9e, 0xa4, 0xa0, 0x8c, 0x6e, 38 | 0xe1, 0x6a, 0xbd, 0x3e, 0x52, 0xdc, 0x27, 0x46, 0xb3, 0x3b, 0xec, 0xd8, 0x17, 0x9b, 0x60, 0xb6, 39 | 0xe5, 0xba, 0xf3, 0xce, 0xb7, 0x66, 0xd4, 0x88, 0x04, 0x5d, 0x38, 0x50, 0x13, 0xc6, 0x58, 0xe6, 40 | 0x71, 0xd0, 0x7d, 0xb3, 0xc6, 0xb6, 0xa9, 0x3b, 0xc2, 0xeb, 0x91, 0x6b, 0xd1, 0x2d, 0xc9, 0x8d, 41 | 0xe9, 0x0d, 0x20, 0x8d, 0x2f, 0xbb, 0x89, 0xb6, 0xed, 0x50, 0x18, 0xdd, 0x3c, 0x7d, 0xd1, 0x50, 42 | 0x96, 0x33, 0x73, 0x66, 0xb9, 0x88, 0xfa, 0xd0, 0x54, 0xd8, 0xe2, 0x0d, 0x68, 0xa5, 0x33, 0x5d, 43 | 0x8b, 0xf0, 0x3f, 0x23, 0x32, 0x78, 0xc5, 0xf3, 0x66, 0xa0, 0x27, 0xfe, 0x0e, 0x05, 0x14, 0xa3, 44 | 0xd6, 0x0a, 0x35, 0x88, 0xe4, 0x72, 0xf0, 0x7b, 0x82, 0xd2, 0xd7, 0x85, 0x8c, 0xd7, 0xc3, 0x26 45 | }; 46 | 47 | static const uint8_t key_2[AES128_KEY_SIZE] = 48 | { 49 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f 50 | }; 51 | static const uint8_t key_2_ref[AES128_KEY_SCHEDULE_SIZE] = 52 | { 53 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 54 | 0xd6, 0xaa, 0x74, 0xfd, 0xd2, 0xaf, 0x72, 0xfa, 0xda, 0xa6, 0x78, 0xf1, 0xd6, 0xab, 0x76, 0xfe, 55 | 0xb6, 0x92, 0xcf, 0x0b, 0x64, 0x3d, 0xbd, 0xf1, 0xbe, 0x9b, 0xc5, 0x00, 0x68, 0x30, 0xb3, 0xfe, 56 | 0xb6, 0xff, 0x74, 0x4e, 0xd2, 0xc2, 0xc9, 0xbf, 0x6c, 0x59, 0x0c, 0xbf, 0x04, 0x69, 0xbf, 0x41, 57 | 0x47, 0xf7, 0xf7, 0xbc, 0x95, 0x35, 0x3e, 0x03, 0xf9, 0x6c, 0x32, 0xbc, 0xfd, 0x05, 0x8d, 0xfd, 58 | 0x3c, 0xaa, 0xa3, 0xe8, 0xa9, 0x9f, 0x9d, 0xeb, 0x50, 0xf3, 0xaf, 0x57, 0xad, 0xf6, 0x22, 0xaa, 59 | 0x5e, 0x39, 0x0f, 0x7d, 0xf7, 0xa6, 0x92, 0x96, 0xa7, 0x55, 0x3d, 0xc1, 0x0a, 0xa3, 0x1f, 0x6b, 60 | 0x14, 0xf9, 0x70, 0x1a, 0xe3, 0x5f, 0xe2, 0x8c, 0x44, 0x0a, 0xdf, 0x4d, 0x4e, 0xa9, 0xc0, 0x26, 61 | 0x47, 0x43, 0x87, 0x35, 0xa4, 0x1c, 0x65, 0xb9, 0xe0, 0x16, 0xba, 0xf4, 0xae, 0xbf, 0x7a, 0xd2, 62 | 0x54, 0x99, 0x32, 0xd1, 0xf0, 0x85, 0x57, 0x68, 0x10, 0x93, 0xed, 0x9c, 0xbe, 0x2c, 0x97, 0x4e, 63 | 0x13, 0x11, 0x1d, 0x7f, 0xe3, 0x94, 0x4a, 0x17, 0xf3, 0x07, 0xa7, 0x8b, 0x4d, 0x2b, 0x30, 0xc5, 64 | }; 65 | 66 | static bool key_schedule_test(const uint8_t p_key[AES128_KEY_SIZE], 67 | const uint8_t p_key_schedule[AES128_KEY_SCHEDULE_SIZE], 68 | const char * p_id) 69 | { 70 | size_t i; 71 | uint8_t key_schedule_out[AES128_KEY_SCHEDULE_SIZE]; 72 | 73 | aes128_key_schedule(key_schedule_out, p_key); 74 | 75 | printf("Key schedule %s output:\n", p_id); 76 | for (i = 0; i < AES128_KEY_SCHEDULE_SIZE; i += 16u) 77 | { 78 | print_block_hex(&key_schedule_out[i], 16u); 79 | } 80 | printf("\n"); 81 | 82 | return (memcmp(key_schedule_out, p_key_schedule, AES128_KEY_SCHEDULE_SIZE) == 0); 83 | } 84 | 85 | int main(int argc, char **argv) 86 | { 87 | bool is_okay; 88 | 89 | (void)argc; 90 | (void)argv; 91 | 92 | is_okay = key_schedule_test(key_0, key_0_ref, "0"); 93 | if (!is_okay) 94 | return 1; 95 | is_okay = key_schedule_test(key_1, key_1_ref, "1"); 96 | if (!is_okay) 97 | return 1; 98 | is_okay = key_schedule_test(key_2, key_2_ref, "2"); 99 | if (!is_okay) 100 | return 1; 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /tests/aes-sbox-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "aes-min.h" 3 | #include "aes-print-block.h" 4 | 5 | #include 6 | 7 | 8 | void _aes_sbox_apply_block_for_test(uint8_t p_block[AES_BLOCK_SIZE]); 9 | 10 | 11 | static const uint8_t sbox_ref[256u] = 12 | { 13 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 14 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 15 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 16 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 17 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 18 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 19 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 20 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 21 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 22 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 23 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 24 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 25 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 26 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 27 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 28 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 29 | }; 30 | 31 | 32 | int main(int argc, char **argv) 33 | { 34 | size_t i; 35 | uint8_t sbox_out[256u]; 36 | 37 | (void)argc; 38 | (void)argv; 39 | 40 | for (i = 0; i < 256u; i++) 41 | { 42 | sbox_out[i] = i; 43 | } 44 | for (i = 0; i < 256u; i += AES_BLOCK_SIZE) 45 | { 46 | _aes_sbox_apply_block_for_test(&sbox_out[i]); 47 | } 48 | 49 | printf("s-box array:\n"); 50 | for (i = 0; i < 256u; i += 16u) 51 | { 52 | print_block_hex(&sbox_out[i], 16u); 53 | } 54 | 55 | return memcmp(sbox_out, sbox_ref, 256u) ? 1 : 0; 56 | } 57 | 58 | -------------------------------------------------------------------------------- /tests/aes-vectors-test.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * aes-vectors-test.c 3 | * 4 | * Test Khazad encryption against the published test vectors, provided in the 5 | * zip file khazad-tweak-test-vectors.zip, containing 6 | * khazad-tweak-test-vectors.txt. 7 | ****************************************************************************/ 8 | 9 | /***************************************************************************** 10 | * Includes 11 | ****************************************************************************/ 12 | 13 | #include "aes-min.h" 14 | //#include "aes-otfks.h" 15 | #include "aes-print-block.h" 16 | 17 | #include 18 | #include 19 | 20 | /***************************************************************************** 21 | * Defines 22 | ****************************************************************************/ 23 | 24 | #ifndef dimof 25 | #define dimof(array) (sizeof(array) / sizeof(array[0])) 26 | #endif 27 | 28 | /***************************************************************************** 29 | * Types 30 | ****************************************************************************/ 31 | 32 | typedef struct 33 | { 34 | const uint32_t set_num; 35 | const uint32_t count; 36 | const uint8_t * key; 37 | const uint8_t * plain; 38 | const uint8_t * cipher; 39 | } vector_data_t; 40 | 41 | /***************************************************************************** 42 | * Include generated code 43 | ****************************************************************************/ 44 | 45 | #include "aes-test-vectors.h" /* Generated by Python parse-vectors.py */ 46 | 47 | /***************************************************************************** 48 | * Functions 49 | ****************************************************************************/ 50 | 51 | static bool test_aes(const vector_data_t * p_vector_data, bool do_otfks) 52 | { 53 | uint8_t encrypt_key_schedule[AES128_KEY_SCHEDULE_SIZE] = {}; 54 | uint8_t otfks_encrypt_key_start[AES128_KEY_SIZE] = {}; 55 | uint8_t otfks_decrypt_key_start[AES128_KEY_SIZE] = {}; 56 | uint8_t otfks_key_work[AES128_KEY_SIZE] = {}; 57 | uint8_t crypt_block[AES_BLOCK_SIZE] = {}; 58 | 59 | if (do_otfks) 60 | { 61 | /* Start key for encrypt */ 62 | memcpy(otfks_encrypt_key_start, p_vector_data->key, AES128_KEY_SIZE); 63 | //aes128_otfks_encrypt_start_key(otfks_encrypt_key_start); 64 | /* Start key for decrypt */ 65 | memcpy(otfks_decrypt_key_start, p_vector_data->key, AES128_KEY_SIZE); 66 | aes128_otfks_decrypt_start_key(otfks_decrypt_key_start); 67 | } 68 | else 69 | { 70 | /* Encrypt key schedule */ 71 | aes128_key_schedule(encrypt_key_schedule, p_vector_data->key); 72 | } 73 | 74 | memcpy(crypt_block, p_vector_data->plain, AES_BLOCK_SIZE); 75 | 76 | /* Encrypt 1 */ 77 | if (do_otfks) 78 | { 79 | memcpy(otfks_key_work, otfks_encrypt_key_start, AES128_KEY_SIZE); 80 | aes128_otfks_encrypt(crypt_block, otfks_key_work); 81 | } 82 | else 83 | { 84 | aes128_encrypt(crypt_block, encrypt_key_schedule); 85 | } 86 | 87 | /* Check encryption */ 88 | if (p_vector_data->cipher && 89 | memcmp(crypt_block, p_vector_data->cipher, AES_BLOCK_SIZE) != 0) 90 | { 91 | printf("set %u vector %u encrypt error\n", 92 | p_vector_data->set_num, p_vector_data->count); 93 | return false; 94 | } 95 | 96 | /* Decrypt back to plain text */ 97 | if (do_otfks) 98 | { 99 | memcpy(otfks_key_work, otfks_decrypt_key_start, AES128_KEY_SIZE); 100 | aes128_otfks_decrypt(crypt_block, otfks_key_work); 101 | } 102 | else 103 | { 104 | aes128_decrypt(crypt_block, encrypt_key_schedule); 105 | } 106 | 107 | /* Check decryption */ 108 | if (memcmp(crypt_block, p_vector_data->plain, AES_BLOCK_SIZE) != 0) 109 | { 110 | printf("set %u vector %u decrypt error\n", 111 | p_vector_data->set_num, p_vector_data->count); 112 | return false; 113 | } 114 | 115 | return true; 116 | } 117 | 118 | int main(int argc, char **argv) 119 | { 120 | size_t i; 121 | bool is_okay; 122 | bool do_otfks; 123 | 124 | (void)argc; 125 | (void)argv; 126 | 127 | for (i = 0; i < dimof(test_vectors); ++i) 128 | { 129 | /* Do each test twice, once with pre-calculated key schedule, then 130 | * again with on-the-fly key schedule calculation. */ 131 | do_otfks = false; 132 | for (;;) 133 | { 134 | /* Using pre-calculated key schedule */ 135 | is_okay = test_aes(test_vectors[i], do_otfks); 136 | if (is_okay == false) 137 | { 138 | printf("set %u vector %u %s%s\n", 139 | test_vectors[i]->set_num, test_vectors[i]->count, 140 | do_otfks ? "(OTFKS) " : "", 141 | is_okay ? "succeeded" : "failed"); 142 | } 143 | if (!is_okay) 144 | { 145 | return 1; 146 | } 147 | if (do_otfks == false) 148 | do_otfks = true; 149 | else 150 | break; 151 | } 152 | } 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /tests/gcm-test-vectors.h: -------------------------------------------------------------------------------- 1 | #ifndef GCM_TEST_VECTORS_H 2 | #define GCM_TEST_VECTORS_H 3 | 4 | /***************************************************************************** 5 | * Includes 6 | ****************************************************************************/ 7 | 8 | #include 9 | #include 10 | 11 | /***************************************************************************** 12 | * Defines 13 | ****************************************************************************/ 14 | 15 | #define GCM_NUM_VECTORS 2625u 16 | 17 | /***************************************************************************** 18 | * Types 19 | ****************************************************************************/ 20 | 21 | typedef struct 22 | { 23 | const uint8_t * p_key; 24 | 25 | /* Assume IV is always 96 bits. */ 26 | const uint8_t * p_iv; 27 | 28 | size_t aad_len; 29 | const uint8_t * p_aad; 30 | 31 | size_t pt_len; 32 | const uint8_t * p_pt; 33 | 34 | size_t ct_len; 35 | const uint8_t * p_ct; 36 | 37 | size_t tag_len; 38 | const uint8_t * p_tag; 39 | } gcm_test_vector_t; 40 | 41 | /***************************************************************************** 42 | * Look-up tables 43 | ****************************************************************************/ 44 | 45 | extern const gcm_test_vector_t gcm_test_vectors[]; 46 | 47 | 48 | #endif /* !defined(GCM_TEST_VECTORS_H) */ 49 | -------------------------------------------------------------------------------- /tests/gcm-test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "gcm-mul.h" 3 | #include "aes-min.h" 4 | #include "aes-print-block.h" 5 | 6 | #include "gcm-test-vectors.h" 7 | 8 | #include 9 | 10 | #include 11 | 12 | /***************************************************************************** 13 | * Defines 14 | ****************************************************************************/ 15 | 16 | #define SIMPLE_IV_SIZE 12u 17 | 18 | #define MAX(A, B) ((A) >= (B) ? (A) : (B)) 19 | #define MIN(A, B) ((A) <= (B) ? (A) : (B)) 20 | 21 | /***************************************************************************** 22 | * Types 23 | ****************************************************************************/ 24 | 25 | typedef enum 26 | { 27 | TEST_GCM_MUL_BIT_BY_BIT, 28 | TEST_GCM_MUL_TABLE4, 29 | TEST_GCM_MUL_TABLE8, 30 | } gcm_mul_implementation_t; 31 | 32 | typedef struct 33 | { 34 | uint8_t a[AES_BLOCK_SIZE]; 35 | uint8_t b[AES_BLOCK_SIZE]; 36 | uint8_t result[AES_BLOCK_SIZE]; 37 | } mul_test_vector_t; 38 | 39 | typedef union 40 | { 41 | uint8_t bytes[AES_BLOCK_SIZE]; 42 | struct 43 | { 44 | uint8_t iv[SIMPLE_IV_SIZE]; 45 | union 46 | { 47 | uint8_t ctr_bytes[4]; 48 | uint32_t ctr; 49 | }; 50 | }; 51 | } gcm_iv_t; 52 | 53 | typedef union 54 | { 55 | uint8_t bytes[AES_BLOCK_SIZE]; 56 | struct 57 | { 58 | uint32_t padding1; 59 | uint32_t aad_len; 60 | uint32_t padding2; 61 | uint32_t pt_len; 62 | }; 63 | } ghash_lengths_t; 64 | 65 | /***************************************************************************** 66 | * Look-up tables 67 | ****************************************************************************/ 68 | 69 | static const mul_test_vector_t mul_test_vectors[] = 70 | { 71 | { 72 | { 0x95u, 0x2Bu, 0x2Au, 0x56u, 0xA5u, 0x60u, 0x4Au, 0xC0u, 0xB3u, 0x2Bu, 0x66u, 0x56u, 0xA0u, 0x5Bu, 0x40u, 0xB6u, }, 73 | { 0xDFu, 0xA6u, 0xBFu, 0x4Du, 0xEDu, 0x81u, 0xDBu, 0x03u, 0xFFu, 0xCAu, 0xFFu, 0x95u, 0xF8u, 0x30u, 0xF0u, 0x61u, }, 74 | { 0xDAu, 0x53u, 0xEBu, 0x0Au, 0xD2u, 0xC5u, 0x5Bu, 0xB6u, 0x4Fu, 0xC4u, 0x80u, 0x2Cu, 0xC3u, 0xFEu, 0xDAu, 0x60u, }, 75 | }, 76 | { 77 | { 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 78 | { 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 79 | { 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 80 | }, 81 | { 82 | { 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 83 | { 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 84 | { 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 85 | }, 86 | { 87 | { 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 88 | { 0x40u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 89 | { 0x40u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 90 | }, 91 | { 92 | { 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 93 | { 0x00u, 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 94 | { 0x00u, 0x80u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, 0x00u, }, 95 | }, 96 | }; 97 | 98 | /***************************************************************************** 99 | * Local functions 100 | ****************************************************************************/ 101 | 102 | static int gcm_mul_test_one(const uint8_t a[AES_BLOCK_SIZE], const uint8_t b[AES_BLOCK_SIZE], const uint8_t correct_result[AES_BLOCK_SIZE]) 103 | { 104 | int result; 105 | uint8_t gmul_out[AES_BLOCK_SIZE]; 106 | 107 | memcpy(gmul_out, a, AES_BLOCK_SIZE); 108 | gcm_mul(gmul_out, b); 109 | 110 | result = memcmp(gmul_out, correct_result, AES_BLOCK_SIZE) ? 1 : 0; 111 | if (result) 112 | { 113 | printf("gcm_mul() a:\n"); 114 | print_block_hex(a, AES_BLOCK_SIZE); 115 | 116 | printf("gcm_mul() b:\n"); 117 | print_block_hex(b, AES_BLOCK_SIZE); 118 | 119 | printf("gcm_mul() expected:\n"); 120 | print_block_hex(correct_result, AES_BLOCK_SIZE); 121 | 122 | printf("gcm_mul() result:\n"); 123 | print_block_hex(gmul_out, AES_BLOCK_SIZE); 124 | return result; 125 | } 126 | return 0; 127 | } 128 | 129 | static int gcm_mul_test(void) 130 | { 131 | size_t i; 132 | int result; 133 | 134 | for (i = 0; i < (sizeof(mul_test_vectors)/sizeof(mul_test_vectors[0])); i++) 135 | { 136 | result = gcm_mul_test_one(mul_test_vectors[i].a, mul_test_vectors[i].b, mul_test_vectors[i].result); 137 | if (result) 138 | return result; 139 | 140 | /* Swapped. */ 141 | result = gcm_mul_test_one(mul_test_vectors[i].b, mul_test_vectors[i].a, mul_test_vectors[i].result); 142 | if (result) 143 | return result; 144 | } 145 | return 0; 146 | } 147 | 148 | static int gcm_mul_table8_test_one(const uint8_t a[AES_BLOCK_SIZE], const uint8_t b[AES_BLOCK_SIZE], const uint8_t correct_result[AES_BLOCK_SIZE]) 149 | { 150 | gcm_mul_table8_t mul_table; 151 | size_t j; 152 | int result; 153 | uint8_t gmul_out[AES_BLOCK_SIZE]; 154 | 155 | /* Prepare the table. */ 156 | //printf("gcm_mul_prepare_table8()\n"); 157 | gcm_mul_prepare_table8(&mul_table, b); 158 | 159 | /* Do the multiply. */ 160 | memcpy(gmul_out, a, AES_BLOCK_SIZE); 161 | //printf("gcm_mul_table8()\n"); 162 | gcm_mul_table8(gmul_out, &mul_table); 163 | 164 | result = memcmp(gmul_out, correct_result, AES_BLOCK_SIZE) ? 1 : 0; 165 | if (result) 166 | { 167 | printf("gcm_mul_prepare_table8() result:\n"); 168 | for (j = 0; j < 255; j++) 169 | { 170 | printf("%02zX: ", j + 1); 171 | print_block_hex(mul_table.key_data[j].bytes, AES_BLOCK_SIZE); 172 | } 173 | 174 | printf("gcm_mul_table8() a:\n"); 175 | print_block_hex(a, AES_BLOCK_SIZE); 176 | 177 | printf("gcm_mul_table8() b:\n"); 178 | print_block_hex(b, AES_BLOCK_SIZE); 179 | 180 | printf("gcm_mul_table8() expected:\n"); 181 | print_block_hex(correct_result, AES_BLOCK_SIZE); 182 | 183 | printf("gcm_mul_table8() result:\n"); 184 | print_block_hex(gmul_out, AES_BLOCK_SIZE); 185 | 186 | return result; 187 | } 188 | return 0; 189 | } 190 | 191 | static int gcm_mul_table8_test(void) 192 | { 193 | size_t i; 194 | int result; 195 | 196 | for (i = 0; i < (sizeof(mul_test_vectors)/sizeof(mul_test_vectors[0])); i++) 197 | { 198 | result = gcm_mul_table8_test_one(mul_test_vectors[i].a, mul_test_vectors[i].b, mul_test_vectors[i].result); 199 | if (result) 200 | return result; 201 | 202 | /* Swapped. */ 203 | result = gcm_mul_table8_test_one(mul_test_vectors[i].b, mul_test_vectors[i].a, mul_test_vectors[i].result); 204 | if (result) 205 | return result; 206 | } 207 | return 0; 208 | } 209 | 210 | static int gcm_mul_table4_test_one(const uint8_t a[AES_BLOCK_SIZE], const uint8_t b[AES_BLOCK_SIZE], const uint8_t correct_result[AES_BLOCK_SIZE]) 211 | { 212 | gcm_mul_table4_t mul_table; 213 | size_t j; 214 | int result; 215 | uint8_t gmul_out[AES_BLOCK_SIZE]; 216 | 217 | /* Prepare the table. */ 218 | //printf("gcm_mul_prepare_table4()\n"); 219 | gcm_mul_prepare_table4(&mul_table, b); 220 | 221 | /* Do the multiply. */ 222 | memcpy(gmul_out, a, AES_BLOCK_SIZE); 223 | //printf("gcm_mul_table4()\n"); 224 | gcm_mul_table4(gmul_out, &mul_table); 225 | 226 | result = memcmp(gmul_out, correct_result, AES_BLOCK_SIZE) ? 1 : 0; 227 | if (result) 228 | { 229 | printf("gcm_mul_prepare_table4() result:\n"); 230 | for (j = 0; j < 15; j++) 231 | { 232 | printf("Hi %02zX: ", j + 1); 233 | print_block_hex(mul_table.key_data_hi[j].bytes, AES_BLOCK_SIZE); 234 | } 235 | for (j = 0; j < 15; j++) 236 | { 237 | printf("Lo %02zX: ", j + 1); 238 | print_block_hex(mul_table.key_data_lo[j].bytes, AES_BLOCK_SIZE); 239 | } 240 | 241 | printf("gcm_mul_table4() a:\n"); 242 | print_block_hex(a, AES_BLOCK_SIZE); 243 | 244 | printf("gcm_mul_table4() b:\n"); 245 | print_block_hex(b, AES_BLOCK_SIZE); 246 | 247 | printf("gcm_mul_table4() expected:\n"); 248 | print_block_hex(correct_result, AES_BLOCK_SIZE); 249 | 250 | printf("gcm_mul_table4() result:\n"); 251 | print_block_hex(gmul_out, AES_BLOCK_SIZE); 252 | 253 | return result; 254 | } 255 | return 0; 256 | } 257 | 258 | static int gcm_mul_table4_test(void) 259 | { 260 | size_t i; 261 | int result; 262 | 263 | for (i = 0; i < (sizeof(mul_test_vectors)/sizeof(mul_test_vectors[0])); i++) 264 | { 265 | result = gcm_mul_table4_test_one(mul_test_vectors[i].a, mul_test_vectors[i].b, mul_test_vectors[i].result); 266 | if (result) 267 | return result; 268 | 269 | /* Swapped. */ 270 | result = gcm_mul_table4_test_one(mul_test_vectors[i].b, mul_test_vectors[i].a, mul_test_vectors[i].result); 271 | if (result) 272 | return result; 273 | } 274 | return 0; 275 | } 276 | 277 | static int gcm_test(gcm_mul_implementation_t mul_impl) 278 | { 279 | size_t i; 280 | size_t data_len; 281 | int result; 282 | gcm_iv_t iv_block; 283 | ghash_lengths_t ghash_lengths; 284 | const uint8_t * p_data; 285 | uint8_t data_block[AES_BLOCK_SIZE]; 286 | uint8_t aes_key[AES_BLOCK_SIZE]; 287 | uint8_t aes_work[AES_BLOCK_SIZE]; 288 | uint8_t ghash_key[AES_BLOCK_SIZE]; 289 | uint8_t ghash_work[AES_BLOCK_SIZE]; 290 | gcm_mul_table8_t mul_table8; 291 | gcm_mul_table4_t mul_table4; 292 | 293 | for (i = 0; i < GCM_NUM_VECTORS; i++) 294 | { 295 | /* Prepare working IV. */ 296 | memcpy(iv_block.iv, gcm_test_vectors[i].p_iv, sizeof(iv_block.iv)); 297 | iv_block.ctr = htobe32(1); 298 | 299 | /* Prepare GHASH calculation. */ 300 | memset(ghash_work, 0, sizeof(ghash_work)); 301 | memset(ghash_key, 0, sizeof(ghash_key)); 302 | memcpy(aes_key, gcm_test_vectors[i].p_key, sizeof(aes_key)); 303 | aes128_otfks_encrypt(ghash_key, aes_key); 304 | switch (mul_impl) 305 | { 306 | case TEST_GCM_MUL_BIT_BY_BIT: 307 | break; 308 | case TEST_GCM_MUL_TABLE4: 309 | gcm_mul_prepare_table4(&mul_table4, ghash_key); 310 | break; 311 | case TEST_GCM_MUL_TABLE8: 312 | gcm_mul_prepare_table8(&mul_table8, ghash_key); 313 | break; 314 | } 315 | 316 | /* Compute GHASH for any AAD (additional authenticated data). */ 317 | if (gcm_test_vectors[i].p_aad) 318 | { 319 | p_data = gcm_test_vectors[i].p_aad; 320 | data_len = gcm_test_vectors[i].aad_len; 321 | while (data_len) 322 | { 323 | memcpy(data_block, p_data, MIN(data_len, sizeof(data_block))); 324 | if (data_len < sizeof(data_block)) 325 | memset(data_block + data_len, 0, sizeof(data_block) - data_len); 326 | 327 | aes_block_xor(ghash_work, data_block); 328 | switch (mul_impl) 329 | { 330 | case TEST_GCM_MUL_BIT_BY_BIT: 331 | gcm_mul(ghash_work, ghash_key); 332 | break; 333 | case TEST_GCM_MUL_TABLE4: 334 | gcm_mul_table4(ghash_work, &mul_table4); 335 | break; 336 | case TEST_GCM_MUL_TABLE8: 337 | gcm_mul_table8(ghash_work, &mul_table8); 338 | break; 339 | } 340 | 341 | p_data += MIN(data_len, sizeof(data_block)); 342 | data_len -= MIN(data_len, sizeof(data_block)); 343 | } 344 | } 345 | 346 | /* Compute GHASH for any plaintext. */ 347 | if (gcm_test_vectors[i].p_pt) 348 | { 349 | p_data = gcm_test_vectors[i].p_pt; 350 | data_len = gcm_test_vectors[i].pt_len; 351 | while (data_len) 352 | { 353 | iv_block.ctr = htobe32(be32toh(iv_block.ctr) + 1); 354 | memcpy(aes_work, iv_block.bytes, sizeof(aes_work)); 355 | memcpy(aes_key, gcm_test_vectors[i].p_key, sizeof(aes_key)); 356 | aes128_otfks_encrypt(aes_work, aes_key); 357 | 358 | memcpy(data_block, p_data, MIN(data_len, sizeof(data_block))); 359 | aes_block_xor(data_block, aes_work); 360 | if (data_len < sizeof(data_block)) 361 | memset(data_block + data_len, 0, sizeof(data_block) - data_len); 362 | /* TODO: Verify ciphertext against that in the test vector. */ 363 | 364 | aes_block_xor(ghash_work, data_block); 365 | switch (mul_impl) 366 | { 367 | case TEST_GCM_MUL_BIT_BY_BIT: 368 | gcm_mul(ghash_work, ghash_key); 369 | break; 370 | case TEST_GCM_MUL_TABLE4: 371 | gcm_mul_table4(ghash_work, &mul_table4); 372 | break; 373 | case TEST_GCM_MUL_TABLE8: 374 | gcm_mul_table8(ghash_work, &mul_table8); 375 | break; 376 | } 377 | 378 | p_data += MIN(data_len, sizeof(data_block)); 379 | data_len -= MIN(data_len, sizeof(data_block)); 380 | } 381 | } 382 | 383 | /* Final GHASH calculation. 384 | * Add block that indicates lengths of AAD and plaintext. */ 385 | ghash_lengths.padding1 = 0; 386 | ghash_lengths.aad_len = htobe32(gcm_test_vectors[i].aad_len * 8u); 387 | ghash_lengths.padding2 = 0; 388 | ghash_lengths.pt_len = htobe32(gcm_test_vectors[i].pt_len * 8u); 389 | aes_block_xor(ghash_work, ghash_lengths.bytes); 390 | switch (mul_impl) 391 | { 392 | case TEST_GCM_MUL_BIT_BY_BIT: 393 | gcm_mul(ghash_work, ghash_key); 394 | break; 395 | case TEST_GCM_MUL_TABLE4: 396 | gcm_mul_table4(ghash_work, &mul_table4); 397 | break; 398 | case TEST_GCM_MUL_TABLE8: 399 | gcm_mul_table8(ghash_work, &mul_table8); 400 | break; 401 | } 402 | 403 | /* Final AES operation that is XORed with final GHASH value. */ 404 | iv_block.ctr = htobe32(1); 405 | memcpy(aes_work, iv_block.bytes, sizeof(aes_work)); 406 | memcpy(aes_key, gcm_test_vectors[i].p_key, sizeof(aes_key)); 407 | aes128_otfks_encrypt(aes_work, aes_key); 408 | aes_block_xor(ghash_work, aes_work); 409 | /* ghash_work now contains calculated tag. */ 410 | 411 | /* Verify tag. */ 412 | result = memcmp(ghash_work, gcm_test_vectors[i].p_tag, gcm_test_vectors[i].tag_len) ? 1 : 0; 413 | if (result) 414 | { 415 | printf("Test vector %zu failed\n", i); 416 | 417 | printf("Tag result:\n"); 418 | print_block_hex(ghash_work, gcm_test_vectors[i].tag_len); 419 | 420 | printf("Tag expected:\n"); 421 | print_block_hex(gcm_test_vectors[i].p_tag, gcm_test_vectors[i].tag_len); 422 | return result; 423 | } 424 | } 425 | return 0; 426 | } 427 | 428 | /***************************************************************************** 429 | * Functions 430 | ****************************************************************************/ 431 | 432 | int main(int argc, char **argv) 433 | { 434 | int result; 435 | 436 | (void)argc; 437 | (void)argv; 438 | 439 | result = gcm_mul_test(); 440 | if (result) 441 | return result; 442 | 443 | result = gcm_mul_table8_test(); 444 | if (result) 445 | return result; 446 | 447 | result = gcm_mul_table4_test(); 448 | if (result) 449 | return result; 450 | 451 | result = gcm_test(TEST_GCM_MUL_BIT_BY_BIT); 452 | if (result) 453 | return result; 454 | result = gcm_test(TEST_GCM_MUL_TABLE4); 455 | if (result) 456 | return result; 457 | result = gcm_test(TEST_GCM_MUL_TABLE8); 458 | if (result) 459 | return result; 460 | 461 | return 0; 462 | } 463 | 464 | --------------------------------------------------------------------------------