aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aes/src
diff options
context:
space:
mode:
Diffstat (limited to 'aes/src')
-rw-r--r--aes/src/aes.c384
-rw-r--r--aes/src/asm/aes128.asm203
-rw-r--r--aes/src/asm/aes192.asm249
-rw-r--r--aes/src/asm/aes256.asm287
-rw-r--r--aes/src/box.c683
-rw-r--r--aes/src/box_aes.c331
-rw-r--r--aes/src/c/aes128.c98
-rw-r--r--aes/src/c/aes192.c133
-rw-r--r--aes/src/c/aes256.c161
-rw-r--r--aes/src/error.c251
-rw-r--r--aes/src/padding.c88
11 files changed, 2868 insertions, 0 deletions
diff --git a/aes/src/aes.c b/aes/src/aes.c
new file mode 100644
index 0000000..1f7da13
--- /dev/null
+++ b/aes/src/aes.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+AES_StatusCode aes_AES_format_block(
+ AES_AES_BlockString* str,
+ const AES_AES_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ assert(str);
+ assert(block);
+
+ if (str == NULL)
+ return aes_error_null_argument(err_details, "str");
+ if (block == NULL)
+ return aes_error_null_argument(err_details, "block");
+
+ char* cursor = str->str;
+
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, *block);
+
+ for (int i = 0; i < 16; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+
+ *cursor = '\0';
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES_format_block_as_matrix(
+ AES_AES_BlockMatrixString* str,
+ const AES_AES_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ assert(str);
+ assert(block);
+
+ if (str == NULL)
+ return aes_error_null_argument(err_details, "str");
+ if (block == NULL)
+ return aes_error_null_argument(err_details, "block");
+
+ char* cursor = str->str;
+
+ AES_ALIGN(unsigned char, 16) bytes[4][4];
+ aes_store_block128_aligned(bytes, *block);
+
+ for (int i = 0; i < 4; ++i, cursor += 3)
+ {
+ for (int j = 0; j < 3; ++j, cursor += 3)
+ sprintf(cursor, "%02x ", bytes[j][i]);
+ sprintf(cursor, "%02x\n", bytes[3][i]);
+ }
+
+ *cursor = '\0';
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES_print_block(
+ const AES_AES_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ assert(block);
+
+ if (block == NULL)
+ return aes_error_null_argument(err_details, "block");
+
+ AES_StatusCode ec = AES_SUCCESS;
+ AES_AES_BlockString str;
+
+ if (aes_is_error(ec = aes_AES_format_block(&str, block, err_details)))
+ return ec;
+
+ printf("%s\n", str.str);
+ return ec;
+}
+
+AES_StatusCode aes_AES_print_block_as_matrix(
+ const AES_AES_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ assert(block);
+
+ if (block == NULL)
+ return aes_error_null_argument(err_details, "block");
+
+ AES_StatusCode ec = AES_SUCCESS;
+ AES_AES_BlockMatrixString str;
+
+ if (aes_is_error(ec = aes_AES_format_block_as_matrix(&str, block, err_details)))
+ return ec;
+
+ printf("%s", str.str);
+ return ec;
+}
+
+AES_StatusCode aes_AES_parse_block(
+ AES_AES_Block* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ assert(dest);
+ assert(src);
+
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ const char* cursor = src;
+
+ AES_ALIGN(unsigned char, 16) bytes[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int n;
+ unsigned int byte;
+ if (sscanf(cursor, "%2x%n", &byte, &n) != 1)
+ return aes_error_parse(err_details, src, "a 128-bit block");
+ bytes[i] = (unsigned char) byte;
+ cursor += n;
+ }
+
+ *dest = aes_load_block128_aligned(bytes);
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES128_format_key(
+ AES_AES128_KeyString* str,
+ const AES_AES128_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ assert(str);
+ assert(key);
+
+ if (str == NULL)
+ return aes_error_null_argument(err_details, "str");
+ if (key == NULL)
+ return aes_error_null_argument(err_details, "key");
+
+ char* cursor = str->str;
+
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, key->key);
+
+ for (int i = 0; i < 16; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+
+ *cursor = '\0';
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES192_format_key(
+ AES_AES192_KeyString* str,
+ const AES_AES192_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ assert(str);
+ assert(key);
+
+ if (str == NULL)
+ return aes_error_null_argument(err_details, "str");
+ if (key == NULL)
+ return aes_error_null_argument(err_details, "key");
+
+ char* cursor = str->str;
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, key->lo);
+
+ for (int i = 0; i < 16; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+ }
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, key->hi);
+
+ for (int i = 0; i < 8; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+ }
+
+ *cursor = '\0';
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES256_format_key(
+ AES_AES256_KeyString* str,
+ const AES_AES256_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ assert(str);
+ assert(key);
+
+ if (str == NULL)
+ return aes_error_null_argument(err_details, "str");
+ if (key == NULL)
+ return aes_error_null_argument(err_details, "key");
+
+ char* cursor = str->str;
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, key->lo);
+
+ for (int i = 0; i < 16; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+ }
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+ aes_store_block128_aligned(bytes, key->hi);
+
+ for (int i = 0; i < 16; ++i, cursor += 2)
+ sprintf(cursor, "%02x", bytes[i]);
+ }
+
+ *cursor = '\0';
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES128_print_key(
+ const AES_AES128_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block(&key->key, err_details);
+}
+
+AES_StatusCode aes_AES192_print_key(
+ const AES_AES192_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ assert(key);
+
+ if (key == NULL)
+ return aes_error_null_argument(err_details, "key");
+
+ AES_StatusCode ec = AES_SUCCESS;
+ AES_AES192_KeyString str;
+
+ if (aes_is_error(ec = aes_AES192_format_key(&str, key, err_details)))
+ return ec;
+
+ printf("%s\n", str.str);
+ return ec;
+}
+
+AES_StatusCode aes_AES256_print_key(
+ const AES_AES256_Key* key,
+ AES_ErrorDetails* err_details)
+{
+ assert(key);
+
+ if (key == NULL)
+ return aes_error_null_argument(err_details, "key");
+
+ AES_StatusCode ec = AES_SUCCESS;
+ AES_AES256_KeyString str;
+
+ if (aes_is_error(ec = aes_AES256_format_key(&str, key, err_details)))
+ return ec;
+
+ printf("%s\n", str.str);
+ return ec;
+}
+
+AES_StatusCode aes_AES128_parse_key(
+ AES_AES128_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_parse_block(&dest->key, src, err_details);
+}
+
+AES_StatusCode aes_AES192_parse_key(
+ AES_AES192_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ assert(dest);
+ assert(src);
+
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ const char* cursor = src;
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int n;
+ unsigned int byte;
+ if (sscanf(cursor, "%2x%n", &byte, &n) != 1)
+ return aes_error_parse(err_details, src, "a 192-bit block");
+ bytes[i] = (unsigned char) byte;
+ cursor += n;
+ }
+
+ dest->lo = aes_load_block128_aligned(bytes);
+ }
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+
+ for (int i = 0; i < 8; ++i)
+ {
+ int n;
+ unsigned int byte;
+ if (sscanf(cursor, "%2x%n", &byte, &n) != 1)
+ return aes_error_parse(err_details, src, "a 192-bit block");
+ bytes[i] = (unsigned char) byte;
+ cursor += n;
+ }
+
+ memset(bytes + 8, 0x00, 8);
+ dest->hi = aes_load_block128_aligned(bytes);
+ }
+
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_AES256_parse_key(
+ AES_AES256_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ assert(dest);
+ assert(src);
+
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ const char* cursor = src;
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int n;
+ unsigned int byte;
+ if (sscanf(cursor, "%2x%n", &byte, &n) != 1)
+ return aes_error_parse(err_details, src, "a 256-bit block");
+ bytes[i] = (unsigned char) byte;
+ cursor += n;
+ }
+
+ dest->lo = aes_load_block128_aligned(bytes);
+ }
+
+ {
+ AES_ALIGN(unsigned char, 16) bytes[16];
+
+ for (int i = 0; i < 16; ++i)
+ {
+ int n;
+ unsigned int byte;
+ if (sscanf(cursor, "%2x%n", &byte, &n) != 1)
+ return aes_error_parse(err_details, src, "a 256-bit block");
+ bytes[i] = (unsigned char) byte;
+ cursor += n;
+ }
+
+ dest->hi = aes_load_block128_aligned(bytes);
+ }
+
+ return AES_SUCCESS;
+}
diff --git a/aes/src/asm/aes128.asm b/aes/src/asm/aes128.asm
new file mode 100644
index 0000000..80be57c
--- /dev/null
+++ b/aes/src/asm/aes128.asm
@@ -0,0 +1,203 @@
+; Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+; This file is part of the "AES tools" project.
+; For details, see https://github.com/egor-tensin/aes-tools.
+; Distributed under the MIT License.
+
+.586
+.xmm
+.model flat
+
+.code
+
+@aes_AES128_encrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesenc xmm0, [ecx + 10h]
+ aesenc xmm0, [ecx + 20h]
+ aesenc xmm0, [ecx + 30h]
+ aesenc xmm0, [ecx + 40h]
+ aesenc xmm0, [ecx + 50h]
+ aesenc xmm0, [ecx + 60h]
+ aesenc xmm0, [ecx + 70h]
+ aesenc xmm0, [ecx + 80h]
+ aesenc xmm0, [ecx + 90h]
+ aesenclast xmm0, [ecx + 0A0h]
+ ret
+@aes_AES128_encrypt_block_@20 endp
+
+@aes_AES128_decrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesdec xmm0, [ecx + 10h]
+ aesdec xmm0, [ecx + 20h]
+ aesdec xmm0, [ecx + 30h]
+ aesdec xmm0, [ecx + 40h]
+ aesdec xmm0, [ecx + 50h]
+ aesdec xmm0, [ecx + 60h]
+ aesdec xmm0, [ecx + 70h]
+ aesdec xmm0, [ecx + 80h]
+ aesdec xmm0, [ecx + 90h]
+ aesdeclast xmm0, [ecx + 0A0h]
+ ret
+@aes_AES128_decrypt_block_@20 endp
+
+@aes_AES128_expand_key_@20 proc
+ ; A "word" (in terms of the FIPS 187 standard) is a 32-bit block.
+ ; Words are denoted by `w[N]`.
+ ;
+ ; A key schedule is composed of 10 "regular" keys and a dumb key for
+ ; the "whitening" step.
+ ;
+ ; A key schedule is thus composed of 44 "words".
+ ; The FIPS standard includes an algorithm to calculate these words via
+ ; a simple loop:
+ ;
+ ; i = 4
+ ; while i < 44:
+ ; temp = w[i - 1]
+ ; if i % 4 == 0:
+ ; temp = SubWord(RotWord(temp))^Rcon
+ ; w[i] = w[i - 4]^temp
+ ; i = i + 1
+ ;
+ ; The loop above may be unrolled like this:
+ ;
+ ; w[4] = SubWord(RotWord(w[3]))^Rcon^w[0]
+ ; w[5] = w[4]^w[1]
+ ; = SubWord(RotWord(w[3]))^Rcon^w[1]^w[0]
+ ; w[6] = w[5]^w[2]
+ ; = SubWord(RotWord(w[3]))^Rcon^w[2]^w[1]^w[0]
+ ; w[7] = w[6]^w[3]
+ ; = SubWord(RotWord(w[3]))^Rcon^w[3]^w[2]^w[1]^w[0]
+ ; w[8] = SubWord(RotWord(w[7]))^Rcon^w[4]
+ ; w[9] = w[8]^w[5]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[5]^w[4]
+ ; w[10] = w[9]^w[6]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[6]^w[5]^w[4]
+ ; w[11] = w[10]^w[7]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[7]^w[6]^w[5]^w[4]
+ ;
+ ; ... and so on.
+ ;
+ ; The Intel AES-NI instruction set facilitates calculating SubWord
+ ; and RotWord using `aeskeygenassist`, which is used in this routine.
+ ;
+ ; Preconditions:
+ ; * xmm0[127:96] == w[3],
+ ; * xmm0[95:64] == w[2],
+ ; * xmm0[63:32] == w[1],
+ ; * xmm0[31:0] == w[0].
+
+ movdqa [ecx], xmm0 ; sets w[0], w[1], w[2], w[3]
+ add ecx, 10h ; ecx = &w[4]
+
+ aeskeygenassist xmm5, xmm0, 01h ; xmm5[127:96] = RotWord(SubWord(w[3]))^Rcon
+ call aes128_keygen_assist ; sets w[4], w[5], w[6], w[7]
+ aeskeygenassist xmm5, xmm0, 02h ; xmm5[127:96] = RotWord(SubWord(w[7]))^Rcon
+ call aes128_keygen_assist ; sets w[8], w[9], w[10], w[11]
+ aeskeygenassist xmm5, xmm0, 04h ; xmm5[127:96] = RotWord(SubWord(w[11]))^Rcon
+ call aes128_keygen_assist ; sets w[12], w[13], w[14], w[15]
+ aeskeygenassist xmm5, xmm0, 08h ; xmm5[127:96] = RotWord(SubWord(w[15]))^Rcon
+ call aes128_keygen_assist ; sets w[16], w[17], w[18], w[19]
+ aeskeygenassist xmm5, xmm0, 10h ; xmm5[127:96] = RotWord(SubWord(w[19]))^Rcon
+ call aes128_keygen_assist ; sets w[20], w[21], w[22], w[23]
+ aeskeygenassist xmm5, xmm0, 20h ; xmm5[127:96] = RotWord(SubWord(w[23]))^Rcon
+ call aes128_keygen_assist ; sets w[24], w[25], w[26], w[27]
+ aeskeygenassist xmm5, xmm0, 40h ; xmm5[127:96] = RotWord(SubWord(w[27]))^Rcon
+ call aes128_keygen_assist ; sets w[28], w[29], w[30], w[31]
+ aeskeygenassist xmm5, xmm0, 80h ; xmm5[127:96] = RotWord(SubWord(w[31]))^Rcon
+ call aes128_keygen_assist ; sets w[32], w[33], w[34], w[35]
+ aeskeygenassist xmm5, xmm0, 1Bh ; xmm5[127:96] = RotWord(SubWord(w[35]))^Rcon
+ call aes128_keygen_assist ; sets w[36], w[37], w[38], w[39]
+ aeskeygenassist xmm5, xmm0, 36h ; xmm5[127:96] = RotWord(SubWord(w[39]))^Rcon
+ call aes128_keygen_assist ; sets w[40], w[41], w[42], w[43]
+
+ ret
+
+aes128_keygen_assist:
+ ; Preconditions:
+ ; * xmm0[127:96] == w[i+3],
+ ; * xmm0[95:64] == w[i+2],
+ ; * xmm0[63:32] == w[i+1],
+ ; * xmm0[31:0] == w[i],
+ ; * xmm5[127:96] == RotWord(SubWord(w[i+3]))^Rcon,
+ ; * ecx == &w[i+4].
+ ;
+ ; Postconditions:
+ ; * xmm0[127:96] == w[i+7] == RotWord(SubWord(w[i+3]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; * xmm0[95:64] == w[i+6] == RotWord(SubWord(w[i+3]))^Rcon^w[i+2]^w[i+1]^w[i],
+ ; * xmm0[63:32] == w[i+5] == RotWord(SubWord(w[i+3]))^Rcon^w[i+1]^w[i],
+ ; * xmm0[31:0] == w[i+4] == RotWord(SubWord(w[i+3]))^Rcon^w[i],
+ ; * ecx == &w[i+8],
+ ; * the value in xmm4 is also modified.
+
+ ; Calculate
+ ; w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+2]^w[i+1]^w[i],
+ ; w[i+1]^w[i] and
+ ; w[i].
+ movdqa xmm4, xmm0 ; xmm4 = xmm0
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ ; xmm0[127:96] == w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+1]^w[i]
+ ; xmm0[31:0] == w[i]
+
+ ; Calculate
+ ; w[i+7] == RotWord(SubWord(w[i+3]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+6] == RotWord(SubWord(w[i+3]))^Rcon^w[i+2]^w[i+1]^w[i],
+ ; w[i+5] == RotWord(SubWord(w[i+3]))^Rcon^w[i+1]^w[i] and
+ ; w[i+4] == RotWord(SubWord(w[i+3]))^Rcon^w[i].
+ pshufd xmm4, xmm5, 0FFh ; xmm4[127:96] = xmm4[95:64] = xmm4[63:32] = xmm4[31:0] = xmm5[127:96]
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ ; xmm0[127:96] == w[i+7] == RotWord(SubWord(w[i+3]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+6] == RotWord(SubWord(w[i+3]))^Rcon^w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+5] == RotWord(SubWord(w[i+3]))^Rcon^w[i+1]^w[i]
+ ; xmm0[31:0] == w[i+4] == RotWord(SubWord(w[i+3]))^Rcon^w[i]
+
+ ; Set w[i+4], w[i+5], w[i+6] and w[i+7].
+ movdqa [ecx], xmm0 ; w[i+7] = RotWord(SubWord(w[i+3]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; w[i+6] = RotWord(SubWord(w[i+3]))^Rcon^w[i+2]^w[i+1]^w[i]
+ ; w[i+5] = RotWord(SubWord(w[i+3]))^Rcon^w[i+1]^w[i]
+ ; w[i+4] = RotWord(SubWord(w[i+3]))^Rcon^w[i]
+ add ecx, 10h ; ecx = &w[i+8]
+
+ ret
+@aes_AES128_expand_key_@20 endp
+
+@aes_AES128_derive_decryption_keys_@8 proc
+ movdqa xmm5, [ecx]
+ movdqa xmm4, [ecx + 0A0h]
+ movdqa [edx], xmm4
+ movdqa [edx + 0A0h], xmm5
+
+ aesimc xmm5, [ecx + 10h]
+ aesimc xmm4, [ecx + 90h]
+ movdqa [edx + 10h], xmm4
+ movdqa [edx + 90h], xmm5
+
+ aesimc xmm5, [ecx + 20h]
+ aesimc xmm4, [ecx + 80h]
+ movdqa [edx + 20h], xmm4
+ movdqa [edx + 80h], xmm5
+
+ aesimc xmm5, [ecx + 30h]
+ aesimc xmm4, [ecx + 70h]
+ movdqa [edx + 30h], xmm4
+ movdqa [edx + 70h], xmm5
+
+ aesimc xmm5, [ecx + 40h]
+ aesimc xmm4, [ecx + 60h]
+ movdqa [edx + 40h], xmm4
+ movdqa [edx + 60h], xmm5
+
+ aesimc xmm5, [ecx + 50h]
+ movdqa [edx + 50h], xmm5
+
+ ret
+@aes_AES128_derive_decryption_keys_@8 endp
+
+end
diff --git a/aes/src/asm/aes192.asm b/aes/src/asm/aes192.asm
new file mode 100644
index 0000000..6a41243
--- /dev/null
+++ b/aes/src/asm/aes192.asm
@@ -0,0 +1,249 @@
+; Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+; This file is part of the "AES tools" project.
+; For details, see https://github.com/egor-tensin/aes-tools.
+; Distributed under the MIT License.
+
+.586
+.xmm
+.model flat
+
+.code
+
+@aes_AES192_encrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesenc xmm0, [ecx + 10h]
+ aesenc xmm0, [ecx + 20h]
+ aesenc xmm0, [ecx + 30h]
+ aesenc xmm0, [ecx + 40h]
+ aesenc xmm0, [ecx + 50h]
+ aesenc xmm0, [ecx + 60h]
+ aesenc xmm0, [ecx + 70h]
+ aesenc xmm0, [ecx + 80h]
+ aesenc xmm0, [ecx + 90h]
+ aesenc xmm0, [ecx + 0A0h]
+ aesenc xmm0, [ecx + 0B0h]
+ aesenclast xmm0, [ecx + 0C0h]
+ ret
+@aes_AES192_encrypt_block_@20 endp
+
+@aes_AES192_decrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesdec xmm0, [ecx + 10h]
+ aesdec xmm0, [ecx + 20h]
+ aesdec xmm0, [ecx + 30h]
+ aesdec xmm0, [ecx + 40h]
+ aesdec xmm0, [ecx + 50h]
+ aesdec xmm0, [ecx + 60h]
+ aesdec xmm0, [ecx + 70h]
+ aesdec xmm0, [ecx + 80h]
+ aesdec xmm0, [ecx + 90h]
+ aesdec xmm0, [ecx + 0A0h]
+ aesdec xmm0, [ecx + 0B0h]
+ aesdeclast xmm0, [ecx + 0C0h]
+ ret
+@aes_AES192_decrypt_block_@20 endp
+
+@aes_AES192_expand_key_@36 proc
+ ; A "word" (in terms of the FIPS 187 standard) is a 32-bit block.
+ ; Words are denoted by `w[N]`.
+ ;
+ ; A key schedule is composed of 12 "regular" keys and a dumb key for
+ ; the "whitening" step.
+ ;
+ ; A key schedule is thus composed of 52 "words".
+ ; The FIPS standard includes an algorithm to calculate these words via
+ ; a simple loop:
+ ;
+ ; i = 6
+ ; while i < 52:
+ ; temp = w[i - 1]
+ ; if i % 6 == 0:
+ ; temp = SubWord(RotWord(temp))^Rcon
+ ; w[i] = w[i - 6]^temp
+ ; i = i + 1
+ ;
+ ; The loop above may be unrolled like this:
+ ;
+ ; w[6] = SubWord(RotWord(w[5]))^Rcon^w[0]
+ ; w[7] = w[6]^w[1]
+ ; = SubWord(RotWord(w[5]))^Rcon^w[0]^w[1]
+ ; w[8] = w[7]^w[2]
+ ; = SubWord(RotWord(w[5]))^Rcon^w[0]^w[1]^w[2]
+ ; w[9] = w[8]^w[3]
+ ; = SubWord(RotWord(w[5]))^Rcon^w[0]^w[1]^w[2]^w[3]
+ ; w[10] = w[9]^w[4]
+ ; = SubWord(RotWord(w[5]))^Rcon^w[0]^w[1]^w[2]^w[3]^w[4]
+ ; w[11] = w[10]^w[5]
+ ; = SubWord(RotWord(w[5]))^Rcon^w[0]^w[1]^w[2]^w[3]^w[4]^w[5]
+ ; w[12] = SubWord(RotWord(w[11]))^Rcon^w[6]
+ ; w[13] = w[12]^w[7]
+ ; = SubWord(RotWord(w[11]))^Rcon^w[6]^w[7]
+ ; w[14] = w[13]^w[8]
+ ; = SubWord(RotWord(w[11]))^Rcon^w[6]^w[7]^w[8]
+ ; w[15] = w[14]^w[9]
+ ; = SubWord(RotWord(w[11]))^Rcon^w[6]^w[7]^w[8]^w[9]
+ ; w[16] = w[15]^w[10]
+ ; = SubWord(RotWord(w[11]))^Rcon^w[6]^w[7]^w[8]^w[9]^w[10]
+ ; w[17] = w[16]^w[11]
+ ; = SubWort(RotWord(w[11]))^Rcon^w[6]^w[7]^w[8]^w[9]^w[10]^w[11]
+ ;
+ ; ... and so on.
+ ;
+ ; The Intel AES-NI instruction set facilitates calculating SubWord
+ ; and RotWord using `aeskeygenassist`, which is used in this routine.
+ ;
+ ; Preconditions:
+ ; * xmm1[63:32] == w[5],
+ ; * xmm1[31:0] == w[4],
+ ; * xmm0[127:96] == w[3],
+ ; * xmm0[95:64] == w[2],
+ ; * xmm0[63:32] == w[1],
+ ; * xmm0[31:0] == w[0].
+
+ movdqa [ecx], xmm0 ; sets w[0], w[1], w[2], w[3]
+ movq qword ptr [ecx + 10h], xmm1 ; sets w[4], w[5]
+
+ aeskeygenassist xmm5, xmm1, 1 ; xmm5[63:32] = RotWord(SubWord(w[5]))^Rcon,
+ call aes192_keygen_assist
+ movdqu [ecx + 18h], xmm0
+ movq qword ptr [ecx + 28h], xmm1
+ aeskeygenassist xmm5, xmm1, 2 ; xmm5[63:32] = RotWord(SubWord(w[11]))^Rcon
+ call aes192_keygen_assist
+ movdqa [ecx + 30h], xmm0
+ movq qword ptr [ecx + 40h], xmm1
+ aeskeygenassist xmm5, xmm1, 4 ; xmm5[63:32] = RotWord(SubWord(w[17]))^Rcon
+ call aes192_keygen_assist
+ movdqu [ecx + 48h], xmm0
+ movq qword ptr [ecx + 58h], xmm1
+ aeskeygenassist xmm5, xmm1, 8 ; xmm5[63:32] = RotWord(SubWord(w[23]))^Rcon
+ call aes192_keygen_assist
+ movdqa [ecx + 60h], xmm0
+ movq qword ptr [ecx + 70h], xmm1
+ aeskeygenassist xmm5, xmm1, 10h ; xmm5[63:32] = RotWord(SubWord(w[29]))^Rcon
+ call aes192_keygen_assist
+ movdqu [ecx + 78h], xmm0
+ movq qword ptr [ecx + 88h], xmm1
+ aeskeygenassist xmm5, xmm1, 20h ; xmm5[63:32] = RotWord(SubWord(w[35]))^Rcon
+ call aes192_keygen_assist
+ movdqa [ecx + 90h], xmm0
+ movq qword ptr [ecx + 0a0h], xmm1
+ aeskeygenassist xmm5, xmm1, 40h ; xmm5[63:32] = RotWord(SubWord(w[41]))^Rcon
+ call aes192_keygen_assist
+ movdqu [ecx + 0a8h], xmm0
+ movq qword ptr [ecx + 0b8h], xmm1
+ aeskeygenassist xmm5, xmm1, 80h ; xmm5[63:32] = RotWord(SubWord(w[49]))^Rcon
+ call aes192_keygen_assist
+ movdqa [ecx + 0c0h], xmm0
+
+ ret
+
+aes192_keygen_assist:
+ ; Preconditions:
+ ; * xmm1[127:96] == 0,
+ ; * xmm1[95:64] == 0,
+ ; * xmm1[63:32] == w[i+5],
+ ; * xmm1[31:0] == w[i+4],
+ ; * xmm0[127:96] == w[i+3],
+ ; * xmm0[95:64] == w[i+2],
+ ; * xmm0[63:32] == w[i+1],
+ ; * xmm0[31:0] == w[i],
+ ; * xmm5[63:32] == RotWord(SubWord(w[i+5]))^Rcon.
+ ;
+ ; Postconditions:
+ ; * xmm1[127:96] == 0,
+ ; * xmm1[95:64] == 0,
+ ; * xmm1[63:32] == w[i+11] == RotWord(SubWord(w[i+5]))^Rcon^w[i+5]^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; * xmm1[31:0] == w[i+10] == RotWord(SubWord(w[i+5]))^Rcon^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; * xmm0[127:96] == w[i+9] == RotWord(SubWord(w[i+5]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; * xmm0[95:64] == w[i+8] == RotWord(SubWord(w[i+5]))^Rcon^w[i+2]^w[i+1]^w[i],
+ ; * xmm0[63:32] == w[i+7] == RotWord(SubWord(w[i+5]))^Rcon^w[i+1]^w[i],
+ ; * xmm0[31:0] == w[i+6] == RotWord(SubWord(w[i+5]))^Rcon^w[i],
+ ; * the value in xmm4 is also modified.
+
+ ; Calculate
+ ; w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+2]^w[i+1]^w[i],
+ ; w[i+1]^w[i] and
+ ; w[i].
+ movdqa xmm4, xmm0 ; xmm4 = xmm0
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ ; xmm0[127:96] == w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+1]^w[i]
+ ; xmm0[31:0] == w[i]
+
+ ; Calculate
+ ; w[i+9] == RotWord(SubWord(w[i+5]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+8] == RotWord(SubWord(w[i+5]))^Rcon^w[i+2]^w[i+1]^w[i],
+ ; w[i+7] == RotWord(SubWord(w[i+5]))^Rcon^w[i+1]^w[i] and
+ ; w[i+6] == RotWord(SubWord(w[i+5]))^Rcon^w[i].
+ pshufd xmm4, xmm5, 55h ; xmm4[127:96] = xmm4[95:64] = xmm4[63:32] = xmm4[31:0] = xmm5[63:32]
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ ; xmm0[127:96] == w[i+9] == RotWord(SubWord(w[i+5]))^Rcon^w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+8] == RotWord(SubWord(w[i+5]))^Rcon^w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+7] == RotWord(SubWord(w[i+5]))^Rcon^w[i+1]^w[i]
+ ; xmm0[31:0] == w[i+6] == RotWord(SubWord(w[i+5]))^Rcon^w[i]
+
+ ; Calculate
+ ; w[i+5]^w[i+4],
+ ; w[i+4].
+ pshufd xmm4, xmm1, 0F3h ; xmm4 = xmm1[31:0] << 32
+ pxor xmm1, xmm4 ; xmm1 ^= xmm5
+ ; xmm1[63:32] == w[i+5]^w[i+4]
+ ; xmm1[31:0] == w[i+4]
+
+ ; Calculate
+ ; w[i+10] == RotWord(SubWord(w[i+5]))^Rcon^w[i+5]^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+11] == RotWord(SubWord(w[i+5]))^Rcon^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i].
+ pshufd xmm4, xmm0, 0FFh ; xmm4[127:96] = xmm4[95:64] = xmm4[63:32] = xmm4[31:0] = xmm0[127:96]
+ psrldq xmm4, 8 ; xmm4 >>= 64
+ pxor xmm1, xmm4 ; xmm1 ^= xmm4
+ ; xmm1[63:32] == w[i+11] == RotWord(SubWord(w[i+5]))^Rcon^w[i+5]^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm1[31:0] == w[i+10] == RotWord(SubWord(w[i+5]))^Rcon^w[i+4]^w[i+3]^w[i+2]^w[i+1]^w[i]
+
+ ret
+@aes_AES192_expand_key_@36 endp
+
+@aes_AES192_derive_decryption_keys_@8 proc
+ movdqa xmm5, [ecx]
+ movdqa xmm4, [ecx + 0C0h]
+ movdqa [edx], xmm4
+ movdqa [edx + 0C0h], xmm5
+
+ aesimc xmm5, [ecx + 10h]
+ aesimc xmm4, [ecx + 0B0h]
+ movdqa [edx + 10h], xmm4
+ movdqa [edx + 0B0h], xmm5
+
+ aesimc xmm5, [ecx + 20h]
+ aesimc xmm4, [ecx + 0A0h]
+ movdqa [edx + 20h], xmm4
+ movdqa [edx + 0A0h], xmm5
+
+ aesimc xmm5, [ecx + 30h]
+ aesimc xmm4, [ecx + 90h]
+ movdqa [edx + 30h], xmm4
+ movdqa [edx + 90h], xmm5
+
+ aesimc xmm5, [ecx + 40h]
+ aesimc xmm4, [ecx + 80h]
+ movdqa [edx + 40h], xmm4
+ movdqa [edx + 80h], xmm5
+
+ aesimc xmm5, [ecx + 50h]
+ aesimc xmm4, [ecx + 70h]
+ movdqa [edx + 50h], xmm4
+ movdqa [edx + 70h], xmm5
+
+ aesimc xmm5, [ecx + 60h]
+ movdqa [edx + 60h], xmm5
+
+ ret
+@aes_AES192_derive_decryption_keys_@8 endp
+
+end
diff --git a/aes/src/asm/aes256.asm b/aes/src/asm/aes256.asm
new file mode 100644
index 0000000..82f5f6f
--- /dev/null
+++ b/aes/src/asm/aes256.asm
@@ -0,0 +1,287 @@
+; Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+; This file is part of the "AES tools" project.
+; For details, see https://github.com/egor-tensin/aes-tools.
+; Distributed under the MIT License.
+
+.586
+.xmm
+.model flat
+
+.code
+
+@aes_AES256_encrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesenc xmm0, [ecx + 10h]
+ aesenc xmm0, [ecx + 20h]
+ aesenc xmm0, [ecx + 30h]
+ aesenc xmm0, [ecx + 40h]
+ aesenc xmm0, [ecx + 50h]
+ aesenc xmm0, [ecx + 60h]
+ aesenc xmm0, [ecx + 70h]
+ aesenc xmm0, [ecx + 80h]
+ aesenc xmm0, [ecx + 90h]
+ aesenc xmm0, [ecx + 0A0h]
+ aesenc xmm0, [ecx + 0B0h]
+ aesenc xmm0, [ecx + 0C0h]
+ aesenc xmm0, [ecx + 0D0h]
+ aesenclast xmm0, [ecx + 0E0h]
+ ret
+@aes_AES256_encrypt_block_@20 endp
+
+@aes_AES256_decrypt_block_@20 proc
+ pxor xmm0, [ecx]
+ aesdec xmm0, [ecx + 10h]
+ aesdec xmm0, [ecx + 20h]
+ aesdec xmm0, [ecx + 30h]
+ aesdec xmm0, [ecx + 40h]
+ aesdec xmm0, [ecx + 50h]
+ aesdec xmm0, [ecx + 60h]
+ aesdec xmm0, [ecx + 70h]
+ aesdec xmm0, [ecx + 80h]
+ aesdec xmm0, [ecx + 90h]
+ aesdec xmm0, [ecx + 0A0h]
+ aesdec xmm0, [ecx + 0B0h]
+ aesdec xmm0, [ecx + 0C0h]
+ aesdec xmm0, [ecx + 0D0h]
+ aesdeclast xmm0, [ecx + 0E0h]
+ ret
+@aes_AES256_decrypt_block_@20 endp
+
+@aes_AES256_expand_key_@36 proc
+ ; A "word" (in terms of the FIPS 187 standard) is a 32-bit block.
+ ; Words are denoted by `w[N]`.
+ ;
+ ; A key schedule is composed of 14 "regular" keys and a dumb key for
+ ; the "whitening" step.
+ ;
+ ; A key schedule is thus composed of 60 "words".
+ ; The FIPS standard includes an algorithm to calculate these words via
+ ; a simple loop:
+ ;
+ ; i = 8
+ ; while i < 60:
+ ; temp = w[i - 1]
+ ; if i % 8 == 0:
+ ; temp = SubWord(RotWord(temp))^Rcon
+ ; elif i % 8 == 4:
+ ; temp = SubWord(temp)
+ ; w[i] = w[i - 8]^temp
+ ; i = i + 1
+ ;
+ ; The loop above may be unrolled like this:
+ ;
+ ; w[8] = SubWord(RotWord(w[7]))^Rcon^w[0]
+ ; w[9] = w[8]^w[1]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[1]^w[0]
+ ; w[10] = w[9]^w[2]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[2]^w[1]^w[0]
+ ; w[11] = w[10]^w[3]
+ ; = SubWord(RotWord(w[7]))^Rcon^w[3]^w[2]^w[1]^w[0]
+ ; w[12] = SubWord(w[11])^w[4]
+ ; w[13] = w[12]^w[5]
+ ; = SubWord(w[11])^w[5]^w[4]
+ ; w[14] = w[13]^w[6]
+ ; = SubWord(w[11])^w[6]^w[5]^w[4]
+ ; w[15] = w[14]^w[7]
+ ; = SubWord(w[11])^w[7]^w[6]^w[5]^w[4]
+ ; w[16] = SubWord(RotWord(w[15]))^Rcon^w[8]
+ ; w[17] = w[16]^w[9]
+ ; = SubWord(RotWord(w[15]))^Rcon^w[9]^w[8]
+ ; w[18] = w[17]^w[10]
+ ; = SubWord(RotWord(w[15]))^Rcon^w[10]^w[9]^w[8]
+ ; w[19] = w[18]^w[11]
+ ; = SubWord(RotWord(w[15]))^Rcon^w[11]^w[10]^w[9]^w[8]
+ ; w[20] = SubWord(w[19])^w[12]
+ ; w[21] = w[20]^w[13]
+ ; = SubWord(w[19])^w[13]^w[12]
+ ; w[22] = w[21]^w[14]
+ ; = SubWord(w[19])^w[14]^w[13]^w[12]
+ ; w[23] = w[22]^w[15]
+ ; = SubWord(w[19])^w[15]^w[14]^w[13]^w[12]
+ ;
+ ; ... and so on.
+ ;
+ ; The Intel AES-NI instruction set facilitates calculating SubWord
+ ; and RotWord using `aeskeygenassist`, which is used in this routine.
+ ;
+ ; Preconditions:
+ ; * xmm1[127:96] == w[7],
+ ; * xmm1[95:64] == w[6],
+ ; * xmm1[63:32] == w[5],
+ ; * xmm1[31:0] == w[4],
+ ; * xmm0[127:96] == w[3],
+ ; * xmm0[95:64] == w[2],
+ ; * xmm0[63:32] == w[1],
+ ; * xmm0[31:0] == w[0].
+
+ movdqa [ecx], xmm0 ; sets w[0], w[1], w[2], w[3]
+ movdqa [ecx + 10h], xmm1 ; sets w[4], w[5], w[6], w[7]
+ lea ecx, [ecx + 20h] ; ecx = &w[8]
+
+ aeskeygenassist xmm5, xmm1, 1h ; xmm5[127:96] = RotWord(SubWord(w[7]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[8], w[9], w[10], w[11]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[11])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[12], w[13], w[14], w[15]
+
+ aeskeygenassist xmm5, xmm1, 2h ; xmm5[127:96] = RotWord(SubWord(w[15]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[16], w[17], w[18], w[19]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[19])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[20], w[21], w[22], w[23]
+
+ aeskeygenassist xmm5, xmm1, 4h ; xmm5[127:96] = RotWord(SubWord(w[23]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[24], w[25], w[26], w[27]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[27])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[28], w[29], w[30], w[31]
+
+ aeskeygenassist xmm5, xmm1, 8h ; xmm5[127:96] = RotWord(SubWord(w[31]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[32], w[33], w[34], w[35]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[35])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[36], w[37], w[38], w[39]
+
+ aeskeygenassist xmm5, xmm1, 10h ; xmm5[127:96] = RotWord(SubWord(w[39]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[40], w[41], w[42], w[43]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[43])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[44], w[45], w[46], w[47]
+
+ aeskeygenassist xmm5, xmm1, 20h ; xmm5[127:96] = RotWord(SubWord(w[47]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[48], w[49], w[50], w[51]
+
+ aeskeygenassist xmm5, xmm1, 0 ; xmm5[95:64] = SubWord(w[51])
+ pshufd xmm5, xmm5, 0AAh ; xmm5[127:96] = xmm5[63:32] = xmm5[31:0] = xmm5[95:64]
+ call aes256_keygen_assist ; sets w[52], w[53], w[54], w[55]
+
+ aeskeygenassist xmm5, xmm1, 40h ; xmm5[127:96] = RotWord(SubWord(w[55]))^Rcon
+ pshufd xmm5, xmm5, 0FFh ; xmm5[95:64] = xmm5[63:32] = xmm5[31:0] = xmm5[127:96]
+ call aes256_keygen_assist ; sets w[56], w[57], w[58], w[59]
+
+ ret
+
+aes256_keygen_assist:
+ ; Preconditions:
+ ; * xmm1[127:96] == w[i+7],
+ ; * xmm1[95:64] == w[i+6],
+ ; * xmm1[63:32] == w[i+5],
+ ; * xmm1[31:0] == w[i+4],
+ ; * xmm0[127:96] == w[i+3],
+ ; * xmm0[95:64] == w[i+2],
+ ; * xmm0[63:32] == w[i+1],
+ ; * xmm0[31:0] == w[i],
+ ; * xmm5[127:96] == xmm5[95:64] == xmm5[63:32] == xmm5[31:0] == HWGEN,
+ ; where HWGEN is either RotWord(SubWord(w[i+7]))^Rcon or SubWord(w[i+7]),
+ ; depending on the number of the round being processed,
+ ; * ecx == &w[i+8].
+ ;
+ ; Postconditions:
+ ; * xmm1[127:96] == w[i+11] == HWGEN^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; * xmm1[95:64] == w[i+10] == HWGEN^w[i+2]^w[i+1]^w[i],
+ ; * xmm1[63:32] == w[i+9] == HWGEN^w[i+1]^w[i],
+ ; * xmm1[31:0] == w[i+8] == HWGEN^w[i],
+ ; * xmm0[127:96] == w[i+7],
+ ; * xmm0[95:64] == w[i+6],
+ ; * xmm0[63:32] == w[i+5],
+ ; * xmm0[31:0] == w[i+4],
+ ; * ecx == &w[i+12],
+ ; * the value in xmm4 is also modified.
+
+ ; Calculate
+ ; w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; w[i+2]^w[i+1]^w[i],
+ ; w[i+1]^w[i] and
+ ; w[i].
+ movdqa xmm4, xmm0 ; xmm4 = xmm0
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ pslldq xmm4, 4 ; xmm4 <<= 32
+ pxor xmm0, xmm4 ; xmm0 ^= xmm4
+ ; xmm0[127:96] == w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+1]^w[i]
+ ; xmm0[31:0] == w[i]
+
+ ; Calculate
+ ; HWGEN^w[i+3]^w[i+2]^w[i+1]^w[i],
+ ; HWGEN^w[i+2]^w[i+1]^w[i],
+ ; HWGEN^w[i+1]^w[i] and
+ ; HWGEN^w[i].
+ pxor xmm0, xmm5 ; xmm0 ^= xmm5
+ ; xmm0[127:96] == w[i+11] == HWGEN^w[i+3]^w[i+2]^w[i+1]^w[i]
+ ; xmm0[95:64] == w[i+10] == HWGEN^w[i+2]^w[i+1]^w[i]
+ ; xmm0[63:32] == w[i+9] == HWGEN^w[i+1]^w[i]
+ ; xmm0[31:0] == w[i+8] == HWGEN^w[i]
+
+ ; Set w[i+8], w[i+9], w[i+10] and w[i+11].
+ movdqa [ecx], xmm0 ; w[i+8] = HWGEN^w[i]
+ ; w[i+9] = HWGEN^w[i+1]^w[i]
+ ; w[i+10] = HWGEN^w[i+2]^w[i+1]^w[i]
+ ; w[i+11] = HWGEN^w[i+3]^w[i+2]^w[i+1]^w[i]
+ add ecx, 10h ; ecx = &w[i+12]
+
+ ; Swap the values in xmm0 and xmm1.
+ pxor xmm0, xmm1
+ pxor xmm1, xmm0
+ pxor xmm0, xmm1
+
+ ret
+@aes_AES256_expand_key_@36 endp
+
+@aes_AES256_derive_decryption_keys_@8 proc
+ movdqa xmm5, [ecx]
+ movdqa xmm4, [ecx + 0E0h]
+ movdqa [edx], xmm4
+ movdqa [edx + 0E0h], xmm5
+
+ aesimc xmm5, [ecx + 10h]
+ aesimc xmm4, [ecx + 0D0h]
+ movdqa [edx + 10h], xmm4
+ movdqa [edx + 0D0h], xmm5
+
+ aesimc xmm5, [ecx + 20h]
+ aesimc xmm4, [ecx + 0C0h]
+ movdqa [edx + 20h], xmm4
+ movdqa [edx + 0C0h], xmm5
+
+ aesimc xmm5, [ecx + 30h]
+ aesimc xmm4, [ecx + 0B0h]
+ movdqa [edx + 30h], xmm4
+ movdqa [edx + 0B0h], xmm5
+
+ aesimc xmm5, [ecx + 40h]
+ aesimc xmm4, [ecx + 0A0h]
+ movdqa [edx + 40h], xmm4
+ movdqa [edx + 0A0h], xmm5
+
+ aesimc xmm5, [ecx + 50h]
+ aesimc xmm4, [ecx + 90h]
+ movdqa [edx + 50h], xmm4
+ movdqa [edx + 90h], xmm5
+
+ aesimc xmm5, [ecx + 60h]
+ aesimc xmm4, [ecx + 80h]
+ movdqa [edx + 60h], xmm4
+ movdqa [edx + 80h], xmm5
+
+ aesimc xmm5, [ecx + 70h]
+ movdqa [edx + 70h], xmm5
+
+ ret
+@aes_AES256_derive_decryption_keys_@8 endp
+
+end
diff --git a/aes/src/box.c b/aes/src/box.c
new file mode 100644
index 0000000..c7e1e90
--- /dev/null
+++ b/aes/src/box.c
@@ -0,0 +1,683 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static const AES_BoxAlgorithmInterface* aes_box_algorithms[] =
+{
+ &aes_box_algorithm_aes128,
+ &aes_box_algorithm_aes192,
+ &aes_box_algorithm_aes256,
+};
+
+AES_StatusCode aes_box_init(
+ AES_Box* box,
+ AES_Algorithm algorithm,
+ const AES_BoxKey* box_key,
+ AES_Mode mode,
+ const AES_BoxBlock* iv,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ box->algorithm = aes_box_algorithms[algorithm];
+
+ if (aes_is_error(status = box->algorithm->calc_round_keys(
+ box_key,
+ &box->encryption_keys,
+ &box->decryption_keys,
+ err_details)))
+ return status;
+
+ box->mode = mode;
+ if (iv != NULL)
+ box->iv = *iv;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ecb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return box->algorithm->encrypt_block(
+ input, &box->encryption_keys, output, err_details);
+}
+
+static AES_StatusCode aes_box_encrypt_block_cbc(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+ AES_BoxBlock xored_input = *input;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ &xored_input, &box->iv, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &xored_input, &box->encryption_keys, output, err_details)))
+ return status;
+
+ box->iv = *output;
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_cfb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ box->iv = *output;
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ofb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, &box->iv, err_details)))
+ return status;
+
+ *output = box->iv;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_block_ctr(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->inc_block(
+ &box->iv, err_details)))
+ return status;
+
+ return status;
+}
+
+typedef AES_StatusCode (*AES_BoxEncryptBlockInMode)(
+ AES_Box*,
+ const AES_BoxBlock*,
+ AES_BoxBlock*,
+ AES_ErrorDetails*);
+
+static AES_BoxEncryptBlockInMode aes_box_encrypt_block_in_mode[] =
+{
+ &aes_box_encrypt_block_ecb,
+ &aes_box_encrypt_block_cbc,
+ &aes_box_encrypt_block_cfb,
+ &aes_box_encrypt_block_ofb,
+ &aes_box_encrypt_block_ctr,
+};
+
+AES_StatusCode aes_box_encrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return aes_box_encrypt_block_in_mode[box->mode](
+ box, input, output, err_details);
+}
+
+static AES_StatusCode aes_box_decrypt_block_ecb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return box->algorithm->decrypt_block(
+ input, &box->decryption_keys, output, err_details);
+}
+
+static AES_StatusCode aes_box_decrypt_block_cbc(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->decrypt_block(
+ input, &box->decryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, &box->iv, err_details)))
+ return status;
+
+ box->iv = *input;
+ return status;
+}
+
+static AES_StatusCode aes_box_decrypt_block_cfb(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (aes_is_error(status = box->algorithm->encrypt_block(
+ &box->iv, &box->encryption_keys, output, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->xor_block(
+ output, input, err_details)))
+ return status;
+
+ box->iv = *input;
+ return status;
+}
+
+typedef AES_BoxEncryptBlockInMode AES_BoxDecryptBlockInMode;
+
+static AES_BoxDecryptBlockInMode aes_box_decrypt_block_in_mode[] =
+{
+ &aes_box_decrypt_block_ecb,
+ &aes_box_decrypt_block_cbc,
+ &aes_box_decrypt_block_cfb,
+ &aes_box_encrypt_block_ofb,
+ &aes_box_encrypt_block_ctr,
+};
+
+AES_StatusCode aes_box_decrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* input,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ return aes_box_decrypt_block_in_mode[box->mode](
+ box, input, output, err_details);
+}
+
+static AES_StatusCode aes_box_get_encrypted_buffer_size(
+ AES_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AES_ECB:
+ case AES_CBC:
+ {
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ *padding_size = block_size - src_size % block_size;
+ *dest_size = src_size + *padding_size;
+ return status;
+ }
+
+ case AES_CFB:
+ case AES_OFB:
+ case AES_CTR:
+ *dest_size = src_size;
+ *padding_size = 0;
+ return status;
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported mode of operation");
+ }
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_block(
+ AES_Box* box,
+ const void* src,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ AES_BoxBlock plaintext;
+
+ if (aes_is_error(status = box->algorithm->load_block(
+ &plaintext, src, err_details)))
+ return status;
+
+ AES_BoxBlock ciphertext;
+
+ if (aes_is_error(status = aes_box_encrypt_block(
+ box, &plaintext, &ciphertext, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->store_block(
+ dest, &ciphertext, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_partial_block_with_padding(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memcpy(plaintext_buf, src, src_size);
+
+ if (aes_is_error(status = aes_fill_with_padding(
+ AES_PADDING_PKCS7,
+ (char*) plaintext_buf + src_size,
+ padding_size,
+ err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, plaintext_buf, dest, err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+ return status;
+}
+
+static AES_StatusCode aes_box_encrypt_buffer_partial_block(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (src_size == 0)
+ return status;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memset(plaintext_buf, 0x00, block_size);
+ memcpy(plaintext_buf, src, src_size);
+
+ void* ciphertext_buf = malloc(block_size);
+
+ if (ciphertext_buf == NULL)
+ {
+ status = aes_error_memory_allocation(err_details);
+ goto FREE_PLAINTEXT_BUF;
+ }
+
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, plaintext_buf, ciphertext_buf, err_details)))
+ goto FREE_CIPHERTEXT_BUF;
+
+ memcpy(dest, ciphertext_buf, src_size);
+
+FREE_CIPHERTEXT_BUF:
+ free(ciphertext_buf);
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+ return status;
+}
+
+AES_StatusCode aes_box_encrypt_buffer(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (box == NULL)
+ return aes_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aes_error_null_argument(err_details, "dest_size");
+
+ size_t padding_size = 0;
+
+ if (aes_is_error(status = aes_box_get_encrypted_buffer_size(
+ box, src_size, dest_size, &padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AES_SUCCESS;
+ if (src == NULL && src_size != 0)
+ return aes_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ const size_t src_len = src_size / block_size;
+
+ for (size_t i = 0; i < src_len; ++i)
+ {
+ if (aes_is_error(status = aes_box_encrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ src = (char*) src + block_size;
+ dest = (char*) dest + block_size;
+ }
+
+ if (padding_size == 0)
+ return aes_box_encrypt_buffer_partial_block(
+ box, src, src_size % block_size, dest, err_details);
+ else
+ return aes_box_encrypt_buffer_partial_block_with_padding(
+ box, src, src_size % block_size, dest, padding_size, err_details);
+}
+
+static AES_StatusCode aes_box_get_decrypted_buffer_size(
+ AES_Box* box,
+ size_t src_size,
+ size_t* dest_size,
+ size_t* max_padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ switch (box->mode)
+ {
+ case AES_ECB:
+ case AES_CBC:
+ {
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ if (src_size == 0 || src_size % block_size != 0)
+ return aes_error_missing_padding(err_details);
+
+ *dest_size = src_size;
+ *max_padding_size = block_size;
+ return status;
+ }
+
+ case AES_CFB:
+ case AES_OFB:
+ case AES_CTR:
+ *dest_size = src_size;
+ *max_padding_size = 0;
+ return status;
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported mode of operation");
+ }
+}
+
+static AES_StatusCode aes_box_decrypt_buffer_block(
+ AES_Box* box,
+ const void* src,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ AES_BoxBlock ciphertext;
+
+ if (aes_is_error(status = box->algorithm->load_block(
+ &ciphertext, src, err_details)))
+ return status;
+
+ AES_BoxBlock plaintext;
+
+ if (aes_is_error(status = aes_box_decrypt_block(
+ box, &ciphertext, &plaintext, err_details)))
+ return status;
+
+ if (aes_is_error(status = box->algorithm->store_block(
+ dest, &plaintext, err_details)))
+ return status;
+
+ return status;
+}
+
+static AES_StatusCode aes_box_decrypt_buffer_partial_block(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ AES_ErrorDetails* err_details)
+{
+ AES_StatusCode status = AES_SUCCESS;
+
+ if (src_size == 0)
+ return status;
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ void* ciphertext_buf = malloc(block_size);
+
+ if (ciphertext_buf == NULL)
+ return status = aes_error_memory_allocation(err_details);
+
+ memset(ciphertext_buf, 0x00, block_size);
+ memcpy(ciphertext_buf, src, src_size);
+
+ void* plaintext_buf = malloc(block_size);
+
+ if (plaintext_buf == NULL)
+ {
+ status = aes_error_memory_allocation(err_details);
+ goto FREE_CIPHERTEXT_BUF;
+ }
+
+ if (aes_is_error(status = aes_box_decrypt_buffer_block(
+ box, ciphertext_buf, plaintext_buf, err_details)))
+ goto FREE_PLAINTEXT_BUF;
+
+ memcpy(dest, plaintext_buf, src_size);
+
+FREE_PLAINTEXT_BUF:
+ free(plaintext_buf);
+
+FREE_CIPHERTEXT_BUF:
+ free(ciphertext_buf);
+
+ return status;
+}
+
+AES_StatusCode aes_box_decrypt_buffer(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AES_ErrorDetails* err_details)
+{
+ if (box == NULL)
+ return aes_error_null_argument(err_details, "box");
+ if (dest_size == NULL)
+ return aes_error_null_argument(err_details, "dest_size");
+
+ AES_StatusCode status = AES_SUCCESS;
+ size_t max_padding_size = 0;
+
+ if (aes_is_error(status = aes_box_get_decrypted_buffer_size(
+ box, src_size, dest_size, &max_padding_size, err_details)))
+ return status;
+
+ if (dest == NULL)
+ return AES_SUCCESS;
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ size_t block_size;
+
+ if (aes_is_error(status = box->algorithm->get_block_size(
+ &block_size, err_details)))
+ return status;
+
+ const size_t src_len = src_size / block_size;
+
+ for (size_t i = 0; i < src_len; ++i)
+ {
+ if (aes_is_error(status = aes_box_decrypt_buffer_block(
+ box, src, dest, err_details)))
+ return status;
+
+ src = (char*) src + block_size;
+ dest = (char*) dest + block_size;
+ }
+
+ if (max_padding_size == 0)
+ {
+ return aes_box_decrypt_buffer_partial_block(
+ box, src, src_size % block_size, dest, err_details);
+ }
+ else
+ {
+ size_t padding_size;
+
+ if (aes_is_error(status = aes_extract_padding_size(
+ AES_PADDING_PKCS7,
+ (char*) dest - block_size,
+ block_size,
+ &padding_size,
+ err_details)))
+ return status;
+
+ *dest_size -= padding_size;
+ return status;
+ }
+}
+
+AES_StatusCode aes_box_parse_block(
+ AES_BoxBlock* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->parse_block(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_parse_key(
+ AES_BoxKey* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->parse_key(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_format_block(
+ AES_BoxBlockString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->format_block(
+ dest, src, err_details);
+}
+
+AES_StatusCode aes_box_format_key(
+ AES_BoxKeyString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_box_algorithms[algorithm]->format_key(
+ dest, src, err_details);
+}
diff --git a/aes/src/box_aes.c b/aes/src/box_aes.c
new file mode 100644
index 0000000..4d08d10
--- /dev/null
+++ b/aes/src/box_aes.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+static AES_StatusCode aes_box_derive_params_aes128(
+ const AES_BoxKey* box_key,
+ AES_BoxEncryptionRoundKeys* encryption_keys,
+ AES_BoxDecryptionRoundKeys* decryption_keys,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ aes_AES128_expand_key_(
+ box_key->aes128_key.key,
+ &encryption_keys->aes128_encryption_keys);
+ aes_AES128_derive_decryption_keys_(
+ &encryption_keys->aes128_encryption_keys,
+ &decryption_keys->aes128_decryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_derive_params_aes192(
+ const AES_BoxKey* box_key,
+ AES_BoxEncryptionRoundKeys* encryption_keys,
+ AES_BoxDecryptionRoundKeys* decryption_keys,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ aes_AES192_expand_key_(
+ box_key->aes192_key.lo,
+ box_key->aes192_key.hi,
+ &encryption_keys->aes192_encryption_keys);
+ aes_AES192_derive_decryption_keys_(
+ &encryption_keys->aes192_encryption_keys,
+ &decryption_keys->aes192_decryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_derive_params_aes256(
+ const AES_BoxKey* box_key,
+ AES_BoxEncryptionRoundKeys* encryption_keys,
+ AES_BoxDecryptionRoundKeys* decryption_keys,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ aes_AES256_expand_key_(
+ box_key->aes256_key.lo,
+ box_key->aes256_key.hi,
+ &encryption_keys->aes256_encryption_keys);
+ aes_AES256_derive_decryption_keys_(
+ &encryption_keys->aes256_encryption_keys,
+ &decryption_keys->aes256_decryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_parse_block_aes(
+ AES_BoxBlock* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+
+ return aes_AES_parse_block(&dest->aes_block, src, err_details);
+}
+
+static AES_StatusCode aes_box_parse_key_aes128(
+ AES_BoxKey* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+
+ return aes_AES128_parse_key(&dest->aes128_key, src, err_details);
+}
+
+static AES_StatusCode aes_box_parse_key_aes192(
+ AES_BoxKey* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+
+ return aes_AES192_parse_key(&dest->aes192_key, src, err_details);
+}
+
+static AES_StatusCode aes_box_parse_key_aes256(
+ AES_BoxKey* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+
+ return aes_AES256_parse_key(&dest->aes256_key, src, err_details);
+}
+
+static AES_StatusCode aes_box_format_block_aes(
+ AES_BoxBlockString* dest,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_AES128_format_block(&dest->aes, &src->aes_block, err_details);
+}
+
+static AES_StatusCode aes_box_format_key_aes128(
+ AES_BoxKeyString* dest,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_AES128_format_key(&dest->aes128, &src->aes128_key, err_details);
+}
+
+static AES_StatusCode aes_box_format_key_aes192(
+ AES_BoxKeyString* dest,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_AES192_format_key(&dest->aes192, &src->aes192_key, err_details);
+}
+
+static AES_StatusCode aes_box_format_key_aes256(
+ AES_BoxKeyString* dest,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details)
+{
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+
+ return aes_AES256_format_key(&dest->aes256, &src->aes256_key, err_details);
+}
+
+static AES_StatusCode aes_box_xor_block_aes(
+ AES_BoxBlock* dest,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ dest->aes_block = aes_AES_xor_blocks(dest->aes_block, src->aes_block);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_inc_block_aes(
+ AES_BoxBlock* ctr,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ ctr->aes_block = aes_AES_inc_block(ctr->aes_block);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_get_block_size_aes(
+ size_t* block_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ *block_size = 16;
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_store_block_aes(
+ void* dest,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ aes_store_block128(dest, src->aes_block);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_load_block_aes(
+ AES_BoxBlock* dest,
+ const void* src,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ dest->aes_block = aes_load_block128(src);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_encrypt_block_aes128(
+ const AES_BoxBlock* input,
+ const AES_BoxEncryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES128_encrypt_block_(
+ input->aes_block,
+ &params->aes128_encryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_decrypt_block_aes128(
+ const AES_BoxBlock* input,
+ const AES_BoxDecryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES128_decrypt_block_(
+ input->aes_block,
+ &params->aes128_decryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_encrypt_block_aes192(
+ const AES_BoxBlock* input,
+ const AES_BoxEncryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES192_encrypt_block_(
+ input->aes_block,
+ &params->aes192_encryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_decrypt_block_aes192(
+ const AES_BoxBlock* input,
+ const AES_BoxDecryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES192_decrypt_block_(
+ input->aes_block,
+ &params->aes192_decryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_encrypt_block_aes256(
+ const AES_BoxBlock* input,
+ const AES_BoxEncryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES256_encrypt_block_(
+ input->aes_block,
+ &params->aes256_encryption_keys);
+ return AES_SUCCESS;
+}
+
+static AES_StatusCode aes_box_decrypt_block_aes256(
+ const AES_BoxBlock* input,
+ const AES_BoxDecryptionRoundKeys* params,
+ AES_BoxBlock* output,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ output->aes_block = aes_AES256_decrypt_block_(
+ input->aes_block,
+ &params->aes256_decryption_keys);
+ return AES_SUCCESS;
+}
+
+AES_BoxAlgorithmInterface aes_box_algorithm_aes128 =
+{
+ &aes_box_derive_params_aes128,
+ &aes_box_parse_block_aes,
+ &aes_box_parse_key_aes128,
+ &aes_box_format_block_aes,
+ &aes_box_format_key_aes128,
+ &aes_box_encrypt_block_aes128,
+ &aes_box_decrypt_block_aes128,
+ &aes_box_xor_block_aes,
+ &aes_box_inc_block_aes,
+ &aes_box_get_block_size_aes,
+ &aes_box_store_block_aes,
+ &aes_box_load_block_aes,
+};
+
+AES_BoxAlgorithmInterface aes_box_algorithm_aes192 =
+{
+ &aes_box_derive_params_aes192,
+ &aes_box_parse_block_aes,
+ &aes_box_parse_key_aes192,
+ &aes_box_format_block_aes,
+ &aes_box_format_key_aes192,
+ &aes_box_encrypt_block_aes192,
+ &aes_box_decrypt_block_aes192,
+ &aes_box_xor_block_aes,
+ &aes_box_inc_block_aes,
+ &aes_box_get_block_size_aes,
+ &aes_box_store_block_aes,
+ &aes_box_load_block_aes,
+};
+
+AES_BoxAlgorithmInterface aes_box_algorithm_aes256 =
+{
+ &aes_box_derive_params_aes256,
+ &aes_box_parse_block_aes,
+ &aes_box_parse_key_aes256,
+ &aes_box_format_block_aes,
+ &aes_box_format_key_aes256,
+ &aes_box_encrypt_block_aes256,
+ &aes_box_decrypt_block_aes256,
+ &aes_box_xor_block_aes,
+ &aes_box_inc_block_aes,
+ &aes_box_get_block_size_aes,
+ &aes_box_store_block_aes,
+ &aes_box_load_block_aes,
+};
diff --git a/aes/src/c/aes128.c b/aes/src/c/aes128.c
new file mode 100644
index 0000000..a1bad40
--- /dev/null
+++ b/aes/src/c/aes128.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <emmintrin.h>
+#include <wmmintrin.h>
+
+AES_AES_Block __fastcall aes_AES128_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES128_RoundKeys* encryption_keys)
+{
+ plaintext = _mm_xor_si128(plaintext, encryption_keys->keys[0]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[1]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[2]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[3]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[4]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[5]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[6]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[7]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[8]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[9]);
+ return _mm_aesenclast_si128(plaintext, encryption_keys->keys[10]);
+}
+
+AES_AES_Block __fastcall aes_AES128_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES128_RoundKeys* decryption_keys)
+{
+ ciphertext = _mm_xor_si128(ciphertext, decryption_keys->keys[0]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[1]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[2]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[3]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[4]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[5]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[6]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[7]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[8]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[9]);
+ return _mm_aesdeclast_si128(ciphertext, decryption_keys->keys[10]);
+}
+
+static AES_AES_Block __fastcall aes_aes128_expand_key_assist(
+ AES_AES_Block prev,
+ AES_AES_Block hwgen)
+{
+ AES_AES_Block tmp = prev;
+
+ tmp = _mm_slli_si128(tmp, 4);
+ prev = _mm_xor_si128(prev, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ prev = _mm_xor_si128(prev, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ prev = _mm_xor_si128(prev, tmp);
+
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ prev = _mm_xor_si128(prev, hwgen);
+
+ return prev;
+}
+
+void __fastcall aes_AES128_expand_key_(
+ AES_AES_Block key,
+ AES_AES128_RoundKeys* encryption_keys)
+{
+ AES_Block128 prev = encryption_keys->keys[0] = key;
+ prev = encryption_keys->keys[1] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x01));
+ prev = encryption_keys->keys[2] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x02));
+ prev = encryption_keys->keys[3] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x04));
+ prev = encryption_keys->keys[4] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x08));
+ prev = encryption_keys->keys[5] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x10));
+ prev = encryption_keys->keys[6] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x20));
+ prev = encryption_keys->keys[7] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x40));
+ prev = encryption_keys->keys[8] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x80));
+ prev = encryption_keys->keys[9] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x1b));
+ prev = encryption_keys->keys[10] = aes_aes128_expand_key_assist(prev, _mm_aeskeygenassist_si128(prev, 0x36));
+}
+
+void __fastcall aes_AES128_derive_decryption_keys_(
+ const AES_AES128_RoundKeys* encryption_keys,
+ AES_AES128_RoundKeys* decryption_keys)
+{
+ decryption_keys->keys[0] = encryption_keys->keys[10];
+ decryption_keys->keys[1] = _mm_aesimc_si128(encryption_keys->keys[9]);
+ decryption_keys->keys[2] = _mm_aesimc_si128(encryption_keys->keys[8]);
+ decryption_keys->keys[3] = _mm_aesimc_si128(encryption_keys->keys[7]);
+ decryption_keys->keys[4] = _mm_aesimc_si128(encryption_keys->keys[6]);
+ decryption_keys->keys[5] = _mm_aesimc_si128(encryption_keys->keys[5]);
+ decryption_keys->keys[6] = _mm_aesimc_si128(encryption_keys->keys[4]);
+ decryption_keys->keys[7] = _mm_aesimc_si128(encryption_keys->keys[3]);
+ decryption_keys->keys[8] = _mm_aesimc_si128(encryption_keys->keys[2]);
+ decryption_keys->keys[9] = _mm_aesimc_si128(encryption_keys->keys[1]);
+ decryption_keys->keys[10] = encryption_keys->keys[0];
+}
diff --git a/aes/src/c/aes192.c b/aes/src/c/aes192.c
new file mode 100644
index 0000000..d661b78
--- /dev/null
+++ b/aes/src/c/aes192.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <emmintrin.h>
+#include <wmmintrin.h>
+
+AES_AES_Block __fastcall aes_AES192_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES192_RoundKeys* encryption_keys)
+{
+ plaintext = _mm_xor_si128(plaintext, encryption_keys->keys[0]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[1]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[2]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[3]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[4]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[5]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[6]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[7]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[8]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[9]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[10]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[11]);
+ return _mm_aesenclast_si128(plaintext, encryption_keys->keys[12]);
+}
+
+AES_AES_Block __fastcall aes_AES192_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES192_RoundKeys* decryption_keys)
+{
+ ciphertext = _mm_xor_si128(ciphertext, decryption_keys->keys[0]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[1]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[2]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[3]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[4]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[5]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[6]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[7]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[8]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[9]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[10]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[11]);
+ return _mm_aesdeclast_si128(ciphertext, decryption_keys->keys[12]);
+}
+
+static void __fastcall aes_aes192_expand_key_assist(
+ AES_AES_Block* prev_lo,
+ AES_AES_Block* prev_hi,
+ AES_AES_Block hwgen)
+{
+ AES_AES_Block tmp = *prev_lo;
+
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+
+ hwgen = _mm_shuffle_epi32(hwgen, 0x55);
+ *prev_lo = _mm_xor_si128(*prev_lo, hwgen);
+
+ tmp = _mm_shuffle_epi32(*prev_hi, 0xf3);
+ *prev_hi = _mm_xor_si128(*prev_hi, tmp);
+
+ tmp = _mm_shuffle_epi32(*prev_lo, 0xff);
+ tmp = _mm_srli_si128(tmp, 8);
+ *prev_hi = _mm_xor_si128(*prev_hi, tmp);
+}
+
+void __fastcall aes_AES192_expand_key_(
+ AES_AES_Block key_lo,
+ AES_AES_Block key_hi,
+ AES_AES192_RoundKeys* encryption_keys)
+{
+ encryption_keys->keys[0] = key_lo;
+ encryption_keys->keys[1] = key_hi;
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x01));
+ encryption_keys->keys[1] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(encryption_keys->keys[1]), _mm_castsi128_pd(key_lo), 0));
+ encryption_keys->keys[2] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_lo), _mm_castsi128_pd(key_hi), 1));
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x02));
+ encryption_keys->keys[3] = key_lo;
+ encryption_keys->keys[4] = key_hi;
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x04));
+ encryption_keys->keys[4] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(encryption_keys->keys[4]), _mm_castsi128_pd(key_lo), 0));
+ encryption_keys->keys[5] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_lo), _mm_castsi128_pd(key_hi), 1));
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x08));
+ encryption_keys->keys[6] = key_lo;
+ encryption_keys->keys[7] = key_hi;
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x10));
+ encryption_keys->keys[7] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(encryption_keys->keys[7]), _mm_castsi128_pd(key_lo), 0));
+ encryption_keys->keys[8] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_lo), _mm_castsi128_pd(key_hi), 1));
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x20));
+ encryption_keys->keys[9] = key_lo;
+ encryption_keys->keys[10] = key_hi;
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x40));
+ encryption_keys->keys[10] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(encryption_keys->keys[10]), _mm_castsi128_pd(key_lo), 0));
+ encryption_keys->keys[11] = _mm_castpd_si128(_mm_shuffle_pd(_mm_castsi128_pd(key_lo), _mm_castsi128_pd(key_hi), 1));
+
+ aes_aes192_expand_key_assist(&key_lo, &key_hi, _mm_aeskeygenassist_si128(key_hi, 0x80));
+ encryption_keys->keys[12] = key_lo;
+}
+
+void __fastcall aes_AES192_derive_decryption_keys_(
+ const AES_AES192_RoundKeys* encryption_keys,
+ AES_AES192_RoundKeys* decryption_keys)
+{
+ decryption_keys->keys[0] = encryption_keys->keys[12];
+ decryption_keys->keys[1] = _mm_aesimc_si128(encryption_keys->keys[11]);
+ decryption_keys->keys[2] = _mm_aesimc_si128(encryption_keys->keys[10]);
+ decryption_keys->keys[3] = _mm_aesimc_si128(encryption_keys->keys[9]);
+ decryption_keys->keys[4] = _mm_aesimc_si128(encryption_keys->keys[8]);
+ decryption_keys->keys[5] = _mm_aesimc_si128(encryption_keys->keys[7]);
+ decryption_keys->keys[6] = _mm_aesimc_si128(encryption_keys->keys[6]);
+ decryption_keys->keys[7] = _mm_aesimc_si128(encryption_keys->keys[5]);
+ decryption_keys->keys[8] = _mm_aesimc_si128(encryption_keys->keys[4]);
+ decryption_keys->keys[9] = _mm_aesimc_si128(encryption_keys->keys[3]);
+ decryption_keys->keys[10] = _mm_aesimc_si128(encryption_keys->keys[2]);
+ decryption_keys->keys[11] = _mm_aesimc_si128(encryption_keys->keys[1]);
+ decryption_keys->keys[12] = encryption_keys->keys[0];
+}
diff --git a/aes/src/c/aes256.c b/aes/src/c/aes256.c
new file mode 100644
index 0000000..2190322
--- /dev/null
+++ b/aes/src/c/aes256.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <emmintrin.h>
+#include <wmmintrin.h>
+
+AES_AES_Block __fastcall aes_AES256_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES256_RoundKeys* encryption_keys)
+{
+ plaintext = _mm_xor_si128(plaintext, encryption_keys->keys[0]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[1]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[2]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[3]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[4]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[5]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[6]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[7]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[8]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[9]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[10]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[11]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[12]);
+ plaintext = _mm_aesenc_si128(plaintext, encryption_keys->keys[13]);
+ return _mm_aesenclast_si128(plaintext, encryption_keys->keys[14]);
+}
+
+AES_AES_Block __fastcall aes_AES256_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES256_RoundKeys* decryption_keys)
+{
+ ciphertext = _mm_xor_si128(ciphertext, decryption_keys->keys[0]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[1]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[2]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[3]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[4]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[5]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[6]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[7]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[8]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[9]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[10]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[11]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[12]);
+ ciphertext = _mm_aesdec_si128(ciphertext, decryption_keys->keys[13]);
+ return _mm_aesdeclast_si128(ciphertext, decryption_keys->keys[14]);
+}
+
+static AES_AES_Block __fastcall aes_aes256_expand_key_assist(
+ AES_AES_Block* prev_lo,
+ AES_AES_Block* prev_hi,
+ AES_AES_Block hwgen)
+{
+ AES_AES_Block tmp = *prev_lo;
+
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+ tmp = _mm_slli_si128(tmp, 4);
+ *prev_lo = _mm_xor_si128(*prev_lo, tmp);
+
+ *prev_lo = _mm_xor_si128(*prev_lo, hwgen);
+
+ *prev_hi = _mm_xor_si128(*prev_hi, *prev_lo);
+ *prev_lo = _mm_xor_si128(*prev_lo, *prev_hi);
+ *prev_hi = _mm_xor_si128(*prev_hi, *prev_lo);
+
+ return *prev_hi;
+}
+
+void __fastcall aes_AES256_expand_key_(
+ AES_AES_Block key_lo,
+ AES_AES_Block key_hi,
+ AES_AES256_RoundKeys* encryption_keys)
+{
+ AES_AES_Block prev_lo, prev_hi;
+ AES_AES_Block hwgen;
+
+ prev_lo = encryption_keys->keys[0] = key_lo;
+ prev_hi = encryption_keys->keys[1] = key_hi;
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x01);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[2] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[3] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x02);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[4] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[5] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x04);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[6] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[7] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x08);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[8] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[9] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x10);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[10] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[11] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x20);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[12] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xaa);
+ encryption_keys->keys[13] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+
+ hwgen = _mm_aeskeygenassist_si128(prev_hi, 0x40);
+ hwgen = _mm_shuffle_epi32(hwgen, 0xff);
+ encryption_keys->keys[14] = aes_aes256_expand_key_assist(&prev_lo, &prev_hi, hwgen);
+}
+
+void __fastcall aes_AES256_derive_decryption_keys_(
+ const AES_AES256_RoundKeys* encryption_keys,
+ AES_AES256_RoundKeys* decryption_keys)
+{
+ decryption_keys->keys[0] = encryption_keys->keys[14];
+ decryption_keys->keys[1] = _mm_aesimc_si128(encryption_keys->keys[13]);
+ decryption_keys->keys[2] = _mm_aesimc_si128(encryption_keys->keys[12]);
+ decryption_keys->keys[3] = _mm_aesimc_si128(encryption_keys->keys[11]);
+ decryption_keys->keys[4] = _mm_aesimc_si128(encryption_keys->keys[10]);
+ decryption_keys->keys[5] = _mm_aesimc_si128(encryption_keys->keys[9]);
+ decryption_keys->keys[6] = _mm_aesimc_si128(encryption_keys->keys[8]);
+ decryption_keys->keys[7] = _mm_aesimc_si128(encryption_keys->keys[7]);
+ decryption_keys->keys[8] = _mm_aesimc_si128(encryption_keys->keys[6]);
+ decryption_keys->keys[9] = _mm_aesimc_si128(encryption_keys->keys[5]);
+ decryption_keys->keys[10] = _mm_aesimc_si128(encryption_keys->keys[4]);
+ decryption_keys->keys[11] = _mm_aesimc_si128(encryption_keys->keys[3]);
+ decryption_keys->keys[12] = _mm_aesimc_si128(encryption_keys->keys[2]);
+ decryption_keys->keys[13] = _mm_aesimc_si128(encryption_keys->keys[1]);
+ decryption_keys->keys[14] = encryption_keys->keys[0];
+}
diff --git a/aes/src/error.c b/aes/src/error.c
new file mode 100644
index 0000000..d49c456
--- /dev/null
+++ b/aes/src/error.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdarg.h>
+
+#define snprintf c99_snprintf
+#define vsnprintf c99_vsnprintf
+
+static int c99_vsnprintf(char *dest, size_t dest_size, const char *fmt, va_list ap)
+{
+ int dest_len = -1;
+
+ if (dest_size != 0)
+ dest_len = _vsnprintf_s(dest, dest_size, _TRUNCATE, fmt, ap);
+ if (dest_len == -1)
+ dest_len = _vscprintf(fmt, ap);
+
+ return dest_len;
+}
+
+static int c99_snprintf(char *dest, size_t dest_size, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+
+ int dest_len = c99_vsnprintf(dest, dest_size, fmt, ap);
+
+ va_end(ap);
+ return dest_len;
+}
+
+#endif
+
+static void aes_fill_string(char* dest, size_t dest_size, const char* src)
+{
+ strncpy(dest, src, dest_size);
+ dest[dest_size - 1] = '\0';
+}
+
+static const char* aes_strerror_messages[] =
+{
+ "Success",
+ "Invalid argument value NULL",
+ "Couldn't parse",
+ "Invalid PKCS7 padding (wrong key?)",
+ "Not implemented",
+ "Missing padding",
+ "Couldn't allocate memory",
+};
+
+const char* aes_strerror(AES_StatusCode ec)
+{
+ return aes_strerror_messages[ec];
+}
+
+static size_t aes_format_error_strerror(
+ const AES_ErrorDetails* err_details,\
+ char* dest,
+ size_t dest_size)
+{
+ const AES_StatusCode ec = aes_get_error_code(err_details);
+ const char* const msg = aes_strerror(ec);
+
+ if (dest == NULL)
+ return strlen(msg) + 1;
+
+ aes_fill_string(dest, dest_size, msg);
+ return strlen(dest);
+}
+
+static size_t aes_format_null_argument_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Invalid argument value NULL for parameter '%s'";
+ const char* const param_name = err_details->params.null_arg.param_name;
+
+ if (dest == NULL && dest_size == 0)
+ return snprintf(NULL, 0, fmt, param_name) + 1;
+
+ snprintf(dest, dest_size, fmt, param_name);
+ return strlen(dest);
+}
+
+static size_t aes_format_parse_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Couldn't parse '%s' (possibly not complete input) as %s";
+ const char* const src = err_details->params.parse_error.src;
+ const char* const what = err_details->params.parse_error.what;
+
+ if (dest == NULL)
+ return snprintf(NULL, 0, fmt, src, what) + 1;
+
+ snprintf(dest, dest_size, fmt, src, what);
+ return strlen(dest);
+}
+
+static size_t aes_format_not_implemented_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ static const char* const fmt = "Not implemented: %s";
+ const char* const src = err_details->params.not_implemented.what;
+
+ if (dest == NULL)
+ return snprintf(NULL, 0, fmt, src) + 1;
+
+ snprintf(dest, dest_size, fmt, src);
+ return strlen(dest);
+}
+
+typedef size_t (*AES_ErrorFormatter)(const AES_ErrorDetails*, char*, size_t);
+
+static AES_ErrorFormatter err_formatters[] =
+{
+ &aes_format_error_strerror,
+ &aes_format_null_argument_error,
+ &aes_format_parse_error,
+ &aes_format_error_strerror,
+ &aes_format_not_implemented_error,
+ &aes_format_error_strerror,
+ &aes_format_error_strerror,
+};
+
+size_t aes_format_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size)
+{
+ assert(err_details);
+
+ return err_formatters[err_details->ec](err_details, dest, dest_size);
+}
+
+#ifdef WIN32
+#include <windows.h>
+
+static void aes_collect_call_stack(AES_ErrorDetails* err_details)
+{
+ err_details->call_stack_len = CaptureStackBackTrace(
+ 1, AES_MAX_CALL_STACK_LENGTH, err_details->call_stack, NULL);
+}
+#else
+static void aes_collect_call_stack(AES_ErrorDetails* err_details)
+{
+ err_details->call_stack_len = 0;
+}
+#endif
+
+static AES_StatusCode aes_make_error(
+ AES_ErrorDetails* err_details,
+ AES_StatusCode ec)
+{
+ if (err_details == NULL)
+ return ec;
+
+ if (aes_is_error(ec))
+ aes_collect_call_stack(err_details);
+
+ return err_details->ec = ec;
+}
+
+AES_StatusCode aes_success(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_SUCCESS);
+}
+
+AES_StatusCode aes_error_null_argument(
+ AES_ErrorDetails* err_details,
+ const char* param_name)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_NULL_ARGUMENT_ERROR);
+
+ if (err_details != NULL)
+ aes_fill_string(
+ err_details->params.null_arg.param_name,
+ sizeof(err_details->params.null_arg.param_name), param_name);
+
+ return status;
+}
+
+AES_StatusCode aes_error_parse(
+ AES_ErrorDetails* err_details,
+ const char* src,
+ const char* what)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_PARSE_ERROR);
+
+ if (err_details != NULL)
+ {
+ aes_fill_string(
+ err_details->params.parse_error.src,
+ sizeof(err_details->params.parse_error.src), src);
+ aes_fill_string(
+ err_details->params.parse_error.what,
+ sizeof(err_details->params.parse_error.what), what);
+ }
+
+ return status;
+}
+
+AES_StatusCode aes_error_invalid_pkcs7_padding(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_INVALID_PKCS7_PADDING_ERROR);
+}
+
+AES_StatusCode aes_error_not_implemented(
+ AES_ErrorDetails* err_details,
+ const char* what)
+{
+ AES_StatusCode status = aes_make_error(err_details, AES_NOT_IMPLEMENTED_ERROR);
+
+ if (err_details != NULL)
+ aes_fill_string(
+ err_details->params.not_implemented.what,
+ sizeof(err_details->params.not_implemented.what), what);
+
+ return status;
+}
+
+AES_StatusCode aes_error_missing_padding(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_MISSING_PADDING_ERROR);
+}
+
+AES_StatusCode aes_error_memory_allocation(
+ AES_ErrorDetails* err_details)
+{
+ return aes_make_error(err_details, AES_MEMORY_ALLOCATION_ERROR);
+}
diff --git a/aes/src/padding.c b/aes/src/padding.c
new file mode 100644
index 0000000..a161ec7
--- /dev/null
+++ b/aes/src/padding.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
+ * This file is part of the "AES tools" project.
+ * For details, see https://github.com/egor-tensin/aes-tools.
+ * Distributed under the MIT License.
+ */
+
+#include <aes/all.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+static AES_StatusCode aes_extract_padding_size_pkcs7(
+ const void* src,
+ size_t src_size,
+ size_t* padding_size,
+ AES_ErrorDetails* err_details)
+{
+ const unsigned char* cursor = (const unsigned char*) src + src_size - 1;
+ *padding_size = *cursor;
+
+ for (size_t i = 1; i < *padding_size; ++i)
+ if (cursor[0 - i] != *padding_size)
+ return aes_error_invalid_pkcs7_padding(err_details);
+
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_extract_padding_size(
+ AES_PaddingMethod method,
+ const void* src,
+ size_t src_size,
+ size_t* padding_size,
+ AES_ErrorDetails* err_details)
+{
+ assert(src);
+ assert(padding_size);
+
+ if (src == NULL)
+ return aes_error_null_argument(err_details, "src");
+ if (padding_size == NULL)
+ return aes_error_null_argument(err_details, "padding_size");
+
+ switch (method)
+ {
+ case AES_PADDING_PKCS7:
+ return aes_extract_padding_size_pkcs7(
+ src, src_size, padding_size, err_details);
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported padding method");
+ }
+}
+
+static AES_StatusCode aes_fill_with_padding_pkcs7(
+ void* dest,
+ size_t padding_size,
+ AES_ErrorDetails* err_details)
+{
+ AES_UNUSED_PARAMETER(err_details);
+ memset(dest, (int) padding_size, padding_size);
+ return AES_SUCCESS;
+}
+
+AES_StatusCode aes_fill_with_padding(
+ AES_PaddingMethod method,
+ void* dest,
+ size_t padding_size,
+ AES_ErrorDetails* err_details)
+{
+ assert(dest);
+
+ if (dest == NULL)
+ return aes_error_null_argument(err_details, "dest");
+
+ switch (method)
+ {
+ case AES_PADDING_PKCS7:
+ return aes_fill_with_padding_pkcs7(
+ dest, padding_size, err_details);
+
+ default:
+ return aes_error_not_implemented(
+ err_details, "unsupported padding method");
+ }
+}