├── ctr ├── README.md ├── Makefile ├── aes256ctr.h └── aes256ctr.c ├── LICENSE ├── Makefile ├── aes256.h ├── README.md ├── demo.c └── aes256.c /ctr/README.md: -------------------------------------------------------------------------------- 1 | # AES-256-CTR 2 | 3 | This is a source code for the counter mode encryption based on the byte-oriented AES-256 implementation. 4 | 5 | ## Usage 6 | 7 | Use `make obj` to compile the object file or `make test` to build a test executable. 8 | 9 | Building the test executable requires both aes256.c and aes256.h assumed residing in the parent directory. Otherwise, you may use `AESDIR` with `make test` to specify an actual location. 10 | -------------------------------------------------------------------------------- /ctr/Makefile: -------------------------------------------------------------------------------- 1 | ## AES-256-CTR 2 | ## 3 | ## Usage: make [target] 4 | ## Targets: 5 | ## obj compile the object file 6 | ## test build the test executable 7 | ## fast use with test for building a faster executable 8 | ## help show this help message 9 | 10 | CC := $(if $(shell which clang),clang,gcc) 11 | CFLAGS := -O3 -Wall -Wextra -pedantic 12 | override USE_TABLES := $(if $(findstring fast,$(MAKECMDGOALS)),-DBACK_TO_TABLES,) 13 | AESDIR := .. 14 | 15 | .PHONY: help obj clean fast 16 | 17 | help: 18 | @grep -h '^\##' $(MAKEFILE_LIST) | cut -c4- 19 | 20 | aes256ctr.o: aes256ctr.c aes256ctr.h 21 | $(CC) $(CFLAGS) -I$(AESDIR) -c -o $@ $< 22 | 23 | obj: aes256ctr.o 24 | 25 | test: aes256ctr.c aes256ctr.h $(AESDIR)/aes256.c 26 | $(CC) $(CFLAGS) -I$(AESDIR) $(USE_TABLES) -DAES256CTR_SELF_TEST__ -o $@ $(?:%.h=) 27 | 28 | clean: 29 | rm -f test *.o 30 | 31 | fast: 32 | @: 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ## A compact byte-oriented AES-256 implementation 2 | ## 3 | ## Usage: make [target] 4 | ## 5 | ## Targets: 6 | ## 7 | ## aes256 compile AES256 to an object file 8 | ## clean delete all compiled files 9 | ## demo build the demo executable 10 | ## fast use together with aes256/verify for a pre-computed tables variant 11 | ## help show this help message 12 | ## verify run cbmc checks to verify code properties 13 | ## 14 | ## Use FUNC to focus verification on a particular function: 15 | ## make verify FUNC=aes256_init 16 | ## 17 | 18 | CC := $(if $(shell which clang),clang,gcc) 19 | CBMC := cbmc 20 | CFLAGS := -O3 -ffast-math -Wall -Wextra -pedantic 21 | override USE_TABLES := $(if $(findstring fast,$(MAKECMDGOALS)),-DBACK_TO_TABLES,) 22 | 23 | .PHONY: help aes256 clean fast verify 24 | 25 | help: 26 | @grep -h '^\##' $(MAKEFILE_LIST) | cut -c4- 27 | 28 | aes256.o: aes256.c aes256.h 29 | $(CC) $(CFLAGS) $(USE_TABLES) -c -o $@ $< 30 | 31 | aes256: aes256.o 32 | @: 33 | 34 | clean: 35 | rm -f demo *.o 36 | 37 | demo: demo.c aes256.o 38 | $(CC) $(CFLAGS) -o $@ $^ 39 | 40 | fast: 41 | @: 42 | 43 | verify: demo.c aes256.c 44 | $(CBMC) $^ -D_cbmc_ $(if $(FUNC),--function $(FUNC),) $(USE_TABLES) \ 45 | --unwind 64 --partial-loops \ 46 | --bounds-check \ 47 | --memory-leak-check `$(CBMC) --help | grep '\--pointer-' | cut -d' ' -f2` \ 48 | --div-by-zero-check --conversion-check \ 49 | --signed-overflow-check --unsigned-overflow-check \ 50 | --undefined-shift-check --float-overflow-check 51 | -------------------------------------------------------------------------------- /ctr/aes256ctr.h: -------------------------------------------------------------------------------- 1 | // 2 | // AES-256-CTR implementation. 3 | // Complies with RFC3686, http://tools.ietf.org/html/rfc3686 4 | // 5 | // Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 6 | // 7 | // This source code is licensed under the terms of the MIT license. 8 | // For a copy, see . 9 | 10 | 11 | #ifndef AES256CTR_H__ 12 | #define AES256CTR_H__ 1 13 | 14 | #include "aes256.h" 15 | #include 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | typedef struct rfc3686_blk { 22 | uint8_t nonce[4]; 23 | uint8_t iv[8]; 24 | uint8_t ctr[4]; 25 | } rfc3686_blk_t; 26 | 27 | typedef union aes256ctr_context { 28 | aes256_context_t ecb; 29 | struct ctr_ctx { 30 | aes256_key_t key; 31 | aes256_key_t enckey; 32 | rfc3686_blk_t blk; 33 | } ctr; 34 | } aes256ctr_ctx_t; 35 | 36 | 37 | /// Initialize a counter mode context. 38 | /// @param[in] key Pointer to an encryption key. 39 | /// @param[in] blk Pointer to a counter block. 40 | /// @return the initialized context structure. 41 | /// 42 | aes256ctr_ctx_t aes256ctr_init( 43 | aes256_key_t *key, 44 | rfc3686_blk_t *blk 45 | ); 46 | 47 | 48 | /// (Re)set a counter block within the context. 49 | /// @param[in,out] ctx Pointer to the initialized context variable. 50 | /// @param[in] blk Pointer to a source counter block. 51 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 52 | /// 53 | uint8_t aes256ctr_setblk( 54 | aes256ctr_ctx_t *ctx, 55 | rfc3686_blk_t *blk 56 | ); 57 | 58 | 59 | /// Encrypt data, in place. 60 | /// @param[in,out] ctx Pointer to the initialized context variable. 61 | /// @param[in,out] buf Pointer to a data buffer. 62 | /// @param[in] size Data buffer size in bytes. 63 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 64 | /// 65 | uint8_t aes256ctr_encrypt( 66 | aes256ctr_ctx_t *ctx, 67 | uint8_t *buf, 68 | size_t size 69 | ); 70 | 71 | #define aes256ctr_decrypt aes256ctr_encrypt 72 | 73 | /// Clear the context. 74 | /// @param[in,out] ctx Pointer to the context variable. 75 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 76 | /// 77 | uint8_t aes256ctr_done( 78 | aes256ctr_ctx_t *ctx 79 | ); 80 | 81 | #ifdef __cplusplus 82 | } 83 | #endif 84 | #endif // AES256CTR_H__ 85 | -------------------------------------------------------------------------------- /aes256.h: -------------------------------------------------------------------------------- 1 | // 2 | // A compact byte-oriented AES-256 implementation. 3 | // All lookup tables replaced with 'on the fly' calculations. 4 | // 5 | // Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com 6 | // Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 7 | // 8 | // Other contributors: Hal Finney. 9 | // 10 | // Permission to use, copy, modify, and distribute this software for any 11 | // purpose with or without fee is hereby granted, provided that the above 12 | // copyright notice and this permission notice appear in all copies. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | 22 | #ifndef AES256_H__ 23 | #define AES256_H__ 1 24 | 25 | #ifndef uint8_t 26 | #define uint8_t unsigned char 27 | #endif 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define AES_SUCCESS (0) 34 | #define AES_ERROR (1) 35 | 36 | typedef struct aes256_key_t { uint8_t raw[32]; } aes256_key_t; 37 | typedef struct aes256_blk_t { uint8_t raw[16]; } aes256_blk_t; 38 | 39 | typedef struct aes256_context_t { 40 | aes256_key_t key; 41 | aes256_key_t enckey; 42 | aes256_key_t deckey; 43 | } aes256_context_t; 44 | 45 | 46 | /// @function aes256_init 47 | /// @brief Initialize a context structure. 48 | /// @param[in,out] ctx Pointer to a pre-allocated context structure. 49 | /// @param[in] key Pointer to a key initialized buffer. 50 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 51 | /// 52 | uint8_t aes256_init( 53 | aes256_context_t *ctx, 54 | aes256_key_t *key 55 | ); 56 | 57 | /// @brief Clear the context structure. 58 | /// @param[in,out] ctx Pointer to a context structure. 59 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 60 | /// 61 | uint8_t aes256_done( 62 | aes256_context_t *ctx 63 | ); 64 | 65 | /// @brief Encrypt a single data block in place. 66 | /// @param[in] ctx Pointer to an initialized context structure. 67 | /// @param[in,out] buf Plaintext in, ciphertext out. 68 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 69 | /// 70 | uint8_t aes256_encrypt_ecb( 71 | aes256_context_t *ctx, 72 | aes256_blk_t *buf 73 | ); 74 | 75 | /// @brief Decrypt a single data block in place. 76 | /// @param[in] ctx Pointer to an initialized context structure. 77 | /// @param[in,out] buf Ciphertext in, plaintext out. 78 | /// @return AES_SUCCESS on success, AES_ERROR on failure. 79 | /// 80 | uint8_t aes256_decrypt_ecb( 81 | aes256_context_t *ctx, 82 | aes256_blk_t *buf 83 | ); 84 | 85 | #ifdef __cplusplus 86 | } 87 | #endif 88 | 89 | #endif // AES256_H__ 90 | 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A byte-oriented AES-256 implementation 2 | 3 | Here is a compact implementation of AES-256 in C. It uses only 4 | a byte type and is portable enough to fit even an 8-bit computer. 5 | It also has a small memory footprint because S-box operations 6 | use on-the-fly calculations instead of lookup tables. 7 | 8 | ## Usage 9 | 10 | Add [aes256.c](aes256.c) and [aes256.h](aes256.h) to your project 11 | and compile as usual. 12 | 13 | Define `BACK_TO_TABLES` if you want to get a faster version that 14 | will use lookup tables instead of calculations. 15 | 16 | There is also the Makefile. Use `make help` for details. 17 | 18 | ## Modes 19 | 20 | This source code gives you a codebook, an ECB core that works 21 | on a 16-byte block, and it is up to you to choose and implement 22 | an appropriate [block cipher mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation) yourself. 23 | 24 | Check the [ctr](ctr) directory for a counter mode complementary implementation. 25 | 26 | ## Portablility 27 | 28 | I try my best to keep this source code portable. But supporting 29 | a wide range of esoteric or long-obsolete compilers is no longer 30 | a priority. Look at [the basic edition](https://github.com/ilvn/aes256/releases/tag/basic) if you still need 31 | that support and can't use the current variant. 32 | 33 | The primary development is with `clang` and `GCC` on macOS and 34 | Linux platforms. 35 | 36 | ## Correctness 37 | 38 | ### Test Vectors 39 | 40 | The [demo.c](demo.c) uses a few known-answer tests from several official 41 | documents to verify this is a valid AES-256 implementation. 42 | 43 | ### Formal Verification 44 | 45 | We rely on [C Bounded Model Checker](http://www.cprover.org/cbmc/) to formally 46 | verify code properties. 47 | 48 | Use `make verify` to verify all the aes256-prefixed functions bound with 49 | the demo code. 50 | 51 | If you want to focus verification on a single function, use 52 | `make verify FUNC=aes256_XYZ`, where `aes256_XYZ` is a function name. 53 | 54 | Check [https://github.com/diffblue/cbmc](https://github.com/diffblue/cbmc) 55 | for the latest version of CBMC. 56 | 57 | ## History 58 | 59 | I initially wrote this source code in 2007 in response to a request 60 | from colleagues for a compact implementation of AES-256 in C. 61 | 62 | They didn't worry about performance; they only needed something 63 | portable to produce small code without using Assembly language. 64 | 65 | Unfortunately, none of the publicly available AES implementations 66 | at the time fit the bill. 67 | 68 | So, I made this straightforward and a somewhat naïve byte-oriented 69 | implementation that was slower and more predisposed to potential 70 | side-channel attacks by nature. Still, it did the trick. 71 | 72 | Later, in 2009, Hal Finney convinced me to make a few changes 73 | so that the implementation could benefit a wider audience. 74 | We improved decryption subroutines and added an option to compile 75 | a faster version with pre-calculated lookup tables. 76 | 77 | ### Legacy 78 | 79 | The original version of the source code from [http://www.literatecode.com](http://literatecode.com) 80 | is available under the tag [legacy](https://github.com/ilvn/aes256/releases/tag/legacy). 81 | It is provided only for reference. 82 | 83 | ## See also 84 | 85 | Since its first public release, many people have used this 86 | implementation for cool things and exciting projects. Not 87 | all of those were public. Also, I wasn't great at tracking. 88 | Still, there are a couple that may interest you: 89 | 90 | * [AES-256 cryptographic library for Python](https://github.com/ostinelli/PyAES256) by Roberto Ostinelli; 91 | * [ArduinoAES256](https://github.com/qistoph/ArduinoAES256) by Chris van Marle. 92 | 93 | The chances are your project could be interesting. 94 | So do not hesitate to share. 95 | -------------------------------------------------------------------------------- /ctr/aes256ctr.c: -------------------------------------------------------------------------------- 1 | // 2 | // A compact AES-256-CTR implementation. 3 | // Complies with RFC3686, http://tools.ietf.org/html/rfc3686 4 | // 5 | // Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 6 | // 7 | // This source code is licensed under the terms of the MIT license. 8 | // For a copy, see . 9 | 10 | #include "aes256ctr.h" 11 | 12 | // ----------------------------------------------------------------------------- 13 | static inline uint8_t 14 | _inc_b(uint8_t b) 15 | { 16 | return ((b == 0xff) ? 0 : (1 + b)); 17 | } // _inc_b 18 | 19 | 20 | // ----------------------------------------------------------------------------- 21 | static inline uint8_t 22 | _inc_ctr(uint8_t val[static 4]) 23 | { 24 | if (0 == (val[3] = _inc_b(val[3]))) 25 | if (0 == (val[2] = _inc_b(val[2]))) 26 | if (0 == (val[1] = _inc_b(val[1]))) { 27 | val[0] = _inc_b(val[0]); 28 | } 29 | return 0; 30 | } // _inc_ctr 31 | 32 | 33 | // ----------------------------------------------------------------------------- 34 | static uint8_t 35 | _clock_keystream(aes256ctr_ctx_t *ctx, aes256_blk_t *kb) 36 | { 37 | *kb = *((aes256_blk_t *)&ctx->ctr.blk); 38 | aes256_encrypt_ecb(&ctx->ecb, kb); 39 | 40 | return _inc_ctr(&ctx->ctr.blk.ctr[0]); 41 | } // _clock_keystream 42 | 43 | 44 | // ----------------------------------------------------------------------------- 45 | uint8_t 46 | aes256ctr_setblk(aes256ctr_ctx_t *ctx, rfc3686_blk_t *blk) 47 | { 48 | if ((NULL != ctx) && (NULL != blk)) { 49 | ctx->ctr.blk = *blk; 50 | return AES_SUCCESS; 51 | } 52 | 53 | return AES_ERROR; 54 | } // aes256ctr_setblk 55 | 56 | 57 | // ----------------------------------------------------------------------------- 58 | aes256ctr_ctx_t 59 | aes256ctr_init(aes256_key_t *key, rfc3686_blk_t *blk) 60 | { 61 | aes256ctr_ctx_t ret = {0}; 62 | 63 | if (NULL != key) { 64 | ret.ctr.enckey = *key; 65 | } 66 | (void)aes256ctr_setblk(&ret, blk); 67 | 68 | return ret; 69 | } // aes255ctr_init 70 | 71 | 72 | // ----------------------------------------------------------------------------- 73 | uint8_t 74 | aes256ctr_encrypt(aes256ctr_ctx_t *ctx, uint8_t *buf, size_t size) 75 | { 76 | if ((NULL != ctx) && (NULL != buf)) { 77 | aes256_blk_t ctrkey; 78 | size_t j = sizeof(ctrkey); 79 | 80 | for (size_t i = 0; i < size; i++) { 81 | if (j == sizeof(ctrkey)) { 82 | j = _clock_keystream(ctx, &ctrkey); 83 | } 84 | buf[i] ^= ctrkey.raw[j++]; 85 | ctrkey.raw[j - 1] = 0; 86 | } 87 | return AES_SUCCESS; 88 | } 89 | 90 | return AES_ERROR; 91 | } // aes256ctr_encrypt 92 | 93 | 94 | // ----------------------------------------------------------------------------- 95 | uint8_t 96 | aes256ctr_done(aes256ctr_ctx_t *ctx) 97 | { 98 | return (NULL == ctx) ? AES_ERROR : aes256_done(&ctx->ecb); 99 | } // aes256ctr_done 100 | 101 | 102 | #if 0 103 | #pragma mark - Self Test 104 | #endif 105 | 106 | #ifdef AES256CTR_SELF_TEST__ 107 | #include 108 | #include 109 | 110 | int 111 | main(void) 112 | { 113 | static const uint8_t kav[] = { // RFC3686 Test Vector #9 114 | 0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46, 115 | 0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07, 116 | 0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8 117 | }; 118 | uint8_t buf[] = { 119 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 120 | 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 121 | 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23 122 | }; 123 | aes256_key_t key = {.raw = { 124 | 0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 125 | 0x2F, 0x43, 0x58, 0x1D, 0xE2, 0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 126 | 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D 127 | } 128 | }; 129 | rfc3686_blk_t ctr = { 130 | .nonce = {0x00, 0x1C, 0xC5, 0xB7}, 131 | .iv = {0x51, 0xA5, 0x1D, 0x70, 0xA1, 0xC1, 0x11, 0x48}, 132 | .ctr = {0x00, 0x00, 0x00, 0x01} 133 | }; 134 | 135 | uint8_t ref[sizeof(buf)]; 136 | memcpy(ref, buf, sizeof(ref)); 137 | 138 | aes256ctr_ctx_t ctx = aes256ctr_init(&key, &ctr); 139 | aes256ctr_encrypt(&ctx, buf, sizeof(buf)); 140 | if ((sizeof(buf) != sizeof(kav)) || (0 != memcmp(buf, kav, sizeof(buf)))) { 141 | printf("Encrypt failed\n"); 142 | return -1; 143 | } 144 | 145 | aes256ctr_setblk(&ctx, &ctr); 146 | aes256ctr_decrypt(&ctx, buf, sizeof(buf)); 147 | if (0 != memcmp(buf, ref, sizeof(buf))) { 148 | printf("Decrypt failed\n"); 149 | return -1; 150 | } 151 | 152 | printf("Success\n"); 153 | return 0; 154 | } 155 | #endif // AES256CTR_SELF_TEST__ 156 | -------------------------------------------------------------------------------- /demo.c: -------------------------------------------------------------------------------- 1 | // 2 | // A compact byte-oriented AES-256 implementation. 3 | // This demo uses a few known-answer tests from FIPS-197 Appendix C.3, 4 | // NIST documents SP800-38A and AESAVS. 5 | // 6 | // Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 7 | // 8 | // Permission to use, copy, modify, and distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | 20 | #include 21 | #include 22 | #include "aes256.h" 23 | 24 | static struct { 25 | aes256_key_t key; 26 | uint8_t pt[16]; 27 | uint8_t ct[16]; 28 | } test[] = { 29 | { 30 | .key.raw = { 31 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 32 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 33 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 34 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f 35 | }, 36 | .pt = { 37 | 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 38 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff 39 | }, 40 | .ct = { 41 | 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 42 | 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 43 | }, 44 | }, 45 | { 46 | .key.raw = { 47 | 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 48 | 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, 49 | 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, 50 | 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 51 | }, 52 | .pt = { 53 | 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 54 | 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A 55 | }, 56 | .ct = { 57 | 0xF3, 0xEE, 0xD1, 0xBD, 0xB5, 0xD2, 0xA0, 0x3C, 58 | 0x06, 0x4B, 0x5A, 0x7E, 0x3D, 0xB1, 0x81, 0xF8 59 | }, 60 | }, 61 | { 62 | .key.raw = { 63 | 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 64 | 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, 65 | 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, 66 | 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 67 | }, 68 | .pt = { 69 | 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, 70 | 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 71 | }, 72 | .ct = { 73 | 0x59, 0x1C, 0xCB, 0x10, 0xD4, 0x10, 0xED, 0x26, 74 | 0xDC, 0x5B, 0xA7, 0x4A, 0x31, 0x36, 0x28, 0x70 75 | }, 76 | }, 77 | { 78 | .key.raw = { 79 | 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 80 | 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, 81 | 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, 82 | 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 83 | }, 84 | .pt = { 85 | 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 86 | 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF 87 | }, 88 | .ct = { 89 | 0xB6, 0xED, 0x21, 0xB9, 0x9C, 0xA6, 0xF4, 0xF9, 90 | 0xF1, 0x53, 0xE7, 0xB1, 0xBE, 0xAF, 0xED, 0x1D 91 | }, 92 | }, 93 | { 94 | .key.raw = { 95 | 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, 96 | 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, 97 | 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, 98 | 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 99 | }, 100 | .pt = { 101 | 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, 102 | 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 103 | }, 104 | .ct = { 105 | 0x23, 0x30, 0x4B, 0x7A, 0x39, 0xF9, 0xF3, 0xFF, 106 | 0x06, 0x7D, 0x8D, 0x8F, 0x9E, 0x24, 0xEC, 0xC7 107 | }, 108 | }, 109 | { 110 | .key.raw = { 111 | 0xc4, 0x7b, 0x02, 0x94, 0xdb, 0xbb, 0xee, 0x0f, 112 | 0xec, 0x47, 0x57, 0xf2, 0x2f, 0xfe, 0xee, 0x35, 113 | 0x87, 0xca, 0x47, 0x30, 0xc3, 0xd3, 0x3b, 0x69, 114 | 0x1d, 0xf3, 0x8b, 0xab, 0x07, 0x6b, 0xc5, 0x58 115 | }, 116 | .pt = {0}, 117 | .ct = { 118 | 0x46, 0xf2, 0xfb, 0x34, 0x2d, 0x6f, 0x0a, 0xb4, 119 | 0x77, 0x47, 0x6f, 0xc5, 0x01, 0x24, 0x2c, 0x5f 120 | }, 121 | }, 122 | { 123 | .key.raw = { 124 | 0xfc, 0xa0, 0x2f, 0x3d, 0x50, 0x11, 0xcf, 0xc5, 125 | 0xc1, 0xe2, 0x31, 0x65, 0xd4, 0x13, 0xa0, 0x49, 126 | 0xd4, 0x52, 0x6a, 0x99, 0x18, 0x27, 0x42, 0x4d, 127 | 0x89, 0x6f, 0xe3, 0x43, 0x5e, 0x0b, 0xf6, 0x8e 128 | }, 129 | .pt = {0}, 130 | .ct = { 131 | 0x17, 0x9a, 0x49, 0xc7, 0x12, 0x15, 0x4b, 0xbf, 132 | 0xfb, 0xe6, 0xe7, 0xa8, 0x4a, 0x18, 0xe2, 0x20 133 | }, 134 | }, 135 | { 136 | .key.raw = { 137 | 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 139 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 141 | }, 142 | .pt = {0}, 143 | .ct = { 144 | 0x9c, 0xf4, 0x89, 0x3e, 0xca, 0xfa, 0x0a, 0x02, 145 | 0x47, 0xa8, 0x98, 0xe0, 0x40, 0x69, 0x15, 0x59 146 | }, 147 | }, 148 | }; 149 | 150 | static const uint8_t total_tests = 0x7f & (sizeof(test) / sizeof(test[0])); 151 | 152 | 153 | int 154 | main(void) 155 | { 156 | aes256_context_t ctx; 157 | aes256_blk_t buf; 158 | 159 | for (uint8_t n = 0; n < total_tests; n++) { 160 | aes256_init(&ctx, &test[n].key); 161 | memcpy(&buf, test[n].pt, sizeof(buf)); 162 | 163 | aes256_encrypt_ecb(&ctx, &buf); 164 | if (0 != memcmp(&buf, test[n].ct, sizeof(buf))) { 165 | printf("FAILED (case %d/encrypt)\n", n); 166 | return 1; 167 | } 168 | 169 | aes256_decrypt_ecb(&ctx, &buf); 170 | if (0 != memcmp(&buf, test[n].pt, sizeof(buf))) { 171 | printf("FAILED (case %d/decrypt)\n", n); 172 | return 2; 173 | } 174 | 175 | aes256_done(&ctx); 176 | } 177 | 178 | printf("Success\n"); 179 | return 0; 180 | } // main 181 | -------------------------------------------------------------------------------- /aes256.c: -------------------------------------------------------------------------------- 1 | // 2 | // A compact byte-oriented AES-256 implementation. 3 | // All lookup tables replaced with 'on the fly' calculations. 4 | // 5 | // Copyright (c) 2007-2011 Literatecode, http://www.literatecode.com 6 | // Copyright (c) 2022 Ilia Levin (ilia@levin.sg) 7 | // 8 | // Other contributors: Hal Finney. 9 | // 10 | // Permission to use, copy, modify, and distribute this software for any 11 | // purpose with or without fee is hereby granted, provided that the above 12 | // copyright notice and this permission notice appear in all copies. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 20 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | 22 | #include "aes256.h" 23 | #ifndef NULL 24 | #define NULL ((void *)0) 25 | #endif 26 | 27 | // We use the compact version with runtime calculations by default. You may 28 | // want to define BACK_TO_TABLES for a pre-calculated faster version. 29 | 30 | // #define BACK_TO_TABLES 31 | 32 | #ifdef _MSC_VER 33 | #define __attribute__(...) 34 | #endif 35 | #define GFC_FN_ static uint8_t __attribute__((const)) 36 | #define AES_CORE_FN_ static void __attribute__((nonnull)) 37 | 38 | // ----------------------------------------------------------------------------- 39 | GFC_FN_ 40 | rj_xtime(uint8_t x) 41 | { 42 | uint8_t y = 0xff & (x << 1); 43 | return (x & 0x80) ? (y ^ 0x1b) : y; 44 | } // rj_xtime 45 | 46 | #ifdef BACK_TO_TABLES // use pre-calculated tables 47 | 48 | static const uint8_t sbox[256] = { 49 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 50 | 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 51 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 52 | 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 53 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 54 | 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 55 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 56 | 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 57 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 58 | 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 59 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 60 | 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 61 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 62 | 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 63 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 64 | 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 65 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 66 | 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 67 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 68 | 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 69 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 70 | 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 71 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 72 | 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 73 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 74 | 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 75 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 76 | 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 77 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 78 | 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 79 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 80 | 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 81 | }; 82 | static const uint8_t sboxinv[256] = { 83 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 84 | 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 85 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 86 | 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 87 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 88 | 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 89 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 90 | 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 91 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 92 | 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 93 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 94 | 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 95 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 96 | 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 97 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 98 | 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 99 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 100 | 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 101 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 102 | 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 103 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 104 | 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 105 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 106 | 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 107 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 108 | 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 109 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 110 | 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 111 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 112 | 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 113 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 114 | 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d 115 | }; 116 | 117 | #define rj_sbox(x) sbox[(x)] 118 | #define rj_sbox_inv(x) sboxinv[(x)] 119 | 120 | #else // use tableless subroutines 121 | 122 | #define SHL8(x, n) ((0xff & ((x) << (n))) | ((x) >> (8 - (n)))) 123 | 124 | // ----------------------------------------------------------------------------- 125 | GFC_FN_ 126 | gf_alog(uint8_t x) // calculate anti-logarithm gen 3 127 | { 128 | uint8_t y = 1; 129 | 130 | for (uint8_t i = 0; (x < 0xff) && (i < x); i++) { 131 | y ^= rj_xtime(y); 132 | } 133 | 134 | return y; 135 | } // gf_alog 136 | 137 | // ----------------------------------------------------------------------------- 138 | GFC_FN_ 139 | gf_log(uint8_t x) // calculate logarithm gen 3 140 | { 141 | uint8_t y = 1, i = 0; 142 | 143 | if (0 != x) { 144 | do { 145 | y ^= rj_xtime(y); 146 | } while ((++i != 0xff) && (y != x)); 147 | } 148 | 149 | return i; 150 | } // gf_log 151 | 152 | // ----------------------------------------------------------------------------- 153 | GFC_FN_ 154 | gf_mulinv(uint8_t x) // calculate multiplicative inverse 155 | { 156 | return ((x) ? gf_alog(255 - gf_log(x)) : 0); 157 | } // gf_mulinv 158 | 159 | // ----------------------------------------------------------------------------- 160 | GFC_FN_ 161 | rj_sbox(uint8_t x) 162 | { 163 | uint8_t y = gf_mulinv(x), sb = y; 164 | 165 | sb ^= y = SHL8(y, 1); 166 | sb ^= y = SHL8(y, 1); 167 | sb ^= y = SHL8(y, 1); 168 | 169 | return (sb ^ SHL8(y, 1) ^ 0x63); 170 | } // rj_sbox 171 | 172 | // ----------------------------------------------------------------------------- 173 | GFC_FN_ 174 | rj_sbox_inv(uint8_t x) 175 | { 176 | uint8_t y = (x ^ 0x63), sb = y = SHL8(y, 1); 177 | 178 | sb ^= y = SHL8(y, 2); 179 | 180 | return gf_mulinv(sb ^ SHL8(y, 3)); 181 | } // rj_sbox_inv 182 | 183 | #endif // BACK_TO_TABLES 184 | 185 | 186 | // ----------------------------------------------------------------------------- 187 | AES_CORE_FN_ 188 | subBytes(uint8_t *buf) 189 | { 190 | for (uint8_t i = 0; i < 16; i++) { 191 | buf[i] = rj_sbox(buf[i]); 192 | } 193 | } // subBytes 194 | 195 | // ----------------------------------------------------------------------------- 196 | AES_CORE_FN_ 197 | subBytes_inv(uint8_t *buf) 198 | { 199 | for (uint8_t i = 0; i < 16; i++) { 200 | buf[i] = rj_sbox_inv(buf[i]); 201 | } 202 | } // subBytes_inv 203 | 204 | // ----------------------------------------------------------------------------- 205 | AES_CORE_FN_ 206 | addRoundKey(uint8_t *buf, uint8_t *key) 207 | { 208 | for (uint8_t i = 0; i < 16; i++) { 209 | buf[i] ^= key[i]; 210 | } 211 | } // addRoundKey 212 | 213 | // ----------------------------------------------------------------------------- 214 | AES_CORE_FN_ 215 | addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk) 216 | { 217 | for (uint8_t i = 0; i < 16; i++) { 218 | buf[i] ^= (cpk[i] = key[i]); 219 | cpk[16 + i] = key[16 + i]; 220 | } 221 | } // addRoundKey_cpy 222 | 223 | // ----------------------------------------------------------------------------- 224 | AES_CORE_FN_ 225 | shiftRows(uint8_t *buf) 226 | { 227 | register uint8_t i, j; // to make it potentially parallelable :) 228 | 229 | i = buf[1]; 230 | buf[1] = buf[5]; 231 | buf[5] = buf[9]; 232 | buf[9] = buf[13]; 233 | buf[13] = i; 234 | 235 | i = buf[10]; 236 | buf[10] = buf[2]; 237 | buf[2] = i; 238 | 239 | j = buf[3]; 240 | buf[3] = buf[15]; 241 | buf[15] = buf[11]; 242 | buf[11] = buf[7]; 243 | buf[7] = j; 244 | 245 | j = buf[14]; 246 | buf[14] = buf[6]; 247 | buf[6] = j; 248 | } // shiftRows 249 | 250 | // ----------------------------------------------------------------------------- 251 | AES_CORE_FN_ 252 | shiftRows_inv(uint8_t *buf) 253 | { 254 | register uint8_t i, j; // similar to shiftRows :) 255 | 256 | i = buf[1]; 257 | buf[1] = buf[13]; 258 | buf[13] = buf[9]; 259 | buf[9] = buf[5]; 260 | buf[5] = i; 261 | 262 | i = buf[2]; 263 | buf[2] = buf[10]; 264 | buf[10] = i; 265 | 266 | j = buf[3]; 267 | buf[3] = buf[7]; 268 | buf[7] = buf[11]; 269 | buf[11] = buf[15]; 270 | buf[15] = j; 271 | 272 | j = buf[6]; 273 | buf[6] = buf[14]; 274 | buf[14] = j; 275 | } // shiftRows_inv 276 | 277 | // ----------------------------------------------------------------------------- 278 | AES_CORE_FN_ 279 | mixColumns(uint8_t *buf) 280 | { 281 | register uint8_t a, b, c, d, e; 282 | 283 | for (uint8_t i = 0; i < 16; i += 4) { 284 | a = buf[i]; 285 | b = buf[i + 1]; 286 | c = buf[i + 2]; 287 | d = buf[i + 3]; 288 | e = a ^ b ^ c ^ d; 289 | buf[i] ^= e ^ rj_xtime(a ^ b); 290 | buf[i + 1] ^= e ^ rj_xtime(b ^ c); 291 | buf[i + 2] ^= e ^ rj_xtime(c ^ d); 292 | buf[i + 3] ^= e ^ rj_xtime(d ^ a); 293 | } 294 | } // mixColumns 295 | 296 | // ----------------------------------------------------------------------------- 297 | AES_CORE_FN_ 298 | mixColumns_inv(uint8_t *buf) 299 | { 300 | register uint8_t a, b, c, d, e, x, y, z; 301 | 302 | for (uint8_t i = 0; i < 16; i += 4) { 303 | a = buf[i]; 304 | b = buf[i + 1]; 305 | c = buf[i + 2]; 306 | d = buf[i + 3]; 307 | e = a ^ b ^ c ^ d; 308 | z = rj_xtime(e); 309 | x = e ^ rj_xtime(rj_xtime(z ^ a ^ c)); 310 | y = e ^ rj_xtime(rj_xtime(z ^ b ^ d)); 311 | buf[i] ^= x ^ rj_xtime(a ^ b); 312 | buf[i + 1] ^= y ^ rj_xtime(b ^ c); 313 | buf[i + 2] ^= x ^ rj_xtime(c ^ d); 314 | buf[i + 3] ^= y ^ rj_xtime(d ^ a); 315 | } 316 | } // mixColumns_inv 317 | 318 | // ----------------------------------------------------------------------------- 319 | AES_CORE_FN_ 320 | expandEncKey(uint8_t *k, uint8_t *rc) 321 | { 322 | k[0] ^= rj_sbox(k[29]) ^ (*rc); 323 | k[1] ^= rj_sbox(k[30]); 324 | k[2] ^= rj_sbox(k[31]); 325 | k[3] ^= rj_sbox(k[28]); 326 | *rc = rj_xtime(*rc); 327 | 328 | for (uint8_t i = 4; i < 16; i += 4) { 329 | k[i] ^= k[i - 4]; 330 | k[i + 1] ^= k[i - 3]; 331 | k[i + 2] ^= k[i - 2]; 332 | k[i + 3] ^= k[i - 1]; 333 | } 334 | 335 | k[16] ^= rj_sbox(k[12]); 336 | k[17] ^= rj_sbox(k[13]); 337 | k[18] ^= rj_sbox(k[14]); 338 | k[19] ^= rj_sbox(k[15]); 339 | 340 | for (uint8_t i = 20; i < 32; i += 4) { 341 | k[i] ^= k[i - 4]; 342 | k[i + 1] ^= k[i - 3]; 343 | k[i + 2] ^= k[i - 2]; 344 | k[i + 3] ^= k[i - 1]; 345 | } 346 | } // expandEncKey 347 | 348 | // ----------------------------------------------------------------------------- 349 | AES_CORE_FN_ 350 | expandDecKey(uint8_t *k, uint8_t *rc) 351 | { 352 | for (uint8_t i = 28; i > 16; i -= 4) { 353 | k[i + 0] ^= k[i - 4]; 354 | k[i + 1] ^= k[i - 3]; 355 | k[i + 2] ^= k[i - 2]; 356 | k[i + 3] ^= k[i - 1]; 357 | } 358 | 359 | k[16] ^= rj_sbox(k[12]); 360 | k[17] ^= rj_sbox(k[13]); 361 | k[18] ^= rj_sbox(k[14]); 362 | k[19] ^= rj_sbox(k[15]); 363 | 364 | for (uint8_t i = 12; i > 0; i -= 4) { 365 | k[i + 0] ^= k[i - 4]; 366 | k[i + 1] ^= k[i - 3]; 367 | k[i + 2] ^= k[i - 2]; 368 | k[i + 3] ^= k[i - 1]; 369 | } 370 | 371 | *rc = (((*rc) >> 1) ^ (((*rc) & 1) ? 0x8d : 0)); 372 | k[0] ^= rj_sbox(k[29]) ^ (*rc); 373 | k[1] ^= rj_sbox(k[30]); 374 | k[2] ^= rj_sbox(k[31]); 375 | k[3] ^= rj_sbox(k[28]); 376 | } // expandDecKey 377 | 378 | // ----------------------------------------------------------------------------- 379 | uint8_t 380 | aes256_init(aes256_context_t *ctx, aes256_key_t *key) 381 | { 382 | if ((NULL == ctx) || (NULL == key)) { 383 | return AES_ERROR; 384 | } 385 | 386 | ctx->enckey = ctx->deckey = *key; 387 | 388 | for (uint8_t i = 0, rcon = 1; i < 7; i++) { 389 | expandEncKey(ctx->deckey.raw, &rcon); 390 | } 391 | 392 | return AES_SUCCESS; 393 | } // aes256_init 394 | 395 | 396 | // ----------------------------------------------------------------------------- 397 | uint8_t 398 | aes256_done(aes256_context_t *ctx) 399 | { 400 | const aes256_key_t zero = {0}; 401 | 402 | if (NULL != ctx) { 403 | ctx->key = ctx->enckey = ctx->deckey = zero; 404 | return AES_SUCCESS; 405 | } 406 | 407 | return AES_ERROR; 408 | } // aes256_done 409 | 410 | 411 | // ----------------------------------------------------------------------------- 412 | uint8_t 413 | aes256_encrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf) 414 | { 415 | if ((NULL == ctx) || (NULL == buf)) { 416 | return AES_ERROR; 417 | } 418 | 419 | uint8_t rcon = 1; 420 | addRoundKey_cpy(buf->raw, ctx->enckey.raw, ctx->key.raw); 421 | 422 | for (uint8_t i = 1; i < 14; ++i) { 423 | subBytes(buf->raw); 424 | shiftRows(buf->raw); 425 | mixColumns(buf->raw); 426 | if (1 == (i & 1)) { 427 | addRoundKey(buf->raw, &ctx->key.raw[16]); 428 | } else { 429 | expandEncKey(ctx->key.raw, &rcon); 430 | addRoundKey(buf->raw, ctx->key.raw); 431 | } 432 | } 433 | 434 | subBytes(buf->raw); 435 | shiftRows(buf->raw); 436 | expandEncKey(ctx->key.raw, &rcon); 437 | addRoundKey(buf->raw, ctx->key.raw); 438 | 439 | return AES_SUCCESS; 440 | } // aes256_encrypt 441 | 442 | // ----------------------------------------------------------------------------- 443 | uint8_t 444 | aes256_decrypt_ecb(aes256_context_t *ctx, aes256_blk_t *buf) 445 | { 446 | if ((NULL == ctx) || (NULL == buf)) { 447 | return AES_ERROR; 448 | } 449 | 450 | addRoundKey_cpy(buf->raw, ctx->deckey.raw, ctx->key.raw); 451 | shiftRows_inv(buf->raw); 452 | subBytes_inv(buf->raw); 453 | 454 | for (uint8_t i = 14, rcon = 0x80; --i;) { 455 | if (1 == (i & 1)) { 456 | expandDecKey(ctx->key.raw, &rcon); 457 | addRoundKey(buf->raw, &ctx->key.raw[16]); 458 | } else { 459 | addRoundKey(buf->raw, ctx->key.raw); 460 | } 461 | mixColumns_inv(buf->raw); 462 | shiftRows_inv(buf->raw); 463 | subBytes_inv(buf->raw); 464 | } 465 | 466 | addRoundKey(buf->raw, ctx->key.raw); 467 | 468 | return AES_SUCCESS; 469 | } // aes256_decrypt 470 | --------------------------------------------------------------------------------