aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aes
diff options
context:
space:
mode:
Diffstat (limited to 'aes')
-rw-r--r--aes/CMakeLists.txt28
-rw-r--r--aes/include/aes/aes.h541
-rw-r--r--aes/include/aes/algorithm.h23
-rw-r--r--aes/include/aes/all.h21
-rw-r--r--aes/include/aes/box.h81
-rw-r--r--aes/include/aes/box_aes.h21
-rw-r--r--aes/include/aes/box_data.h153
-rw-r--r--aes/include/aes/data.h122
-rw-r--r--aes/include/aes/error.h96
-rw-r--r--aes/include/aes/mode.h166
-rw-r--r--aes/include/aes/padding.h38
-rw-r--r--aes/include/aes/workarounds.h16
-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
23 files changed, 4174 insertions, 0 deletions
diff --git a/aes/CMakeLists.txt b/aes/CMakeLists.txt
new file mode 100644
index 0000000..0ec262d
--- /dev/null
+++ b/aes/CMakeLists.txt
@@ -0,0 +1,28 @@
+option(AES_TOOLS_ASM "Use the assembly language implementation instead of the one in C")
+
+file(GLOB_RECURSE aes_include "include/*.h")
+
+if(MSVC AND AES_TOOLS_ASM)
+ enable_language(ASM_MASM)
+ file(GLOB aes_src_c "src/*.c")
+ file(GLOB aes_src_asm "src/asm/*.asm")
+ set(aes_src ${aes_src_asm} ${aes_src_c})
+ set_source_files_properties(${aes_src_asm} PROPERTIES COMPILE_FLAGS /safeseh)
+ # Setting CMAKE_ASM_MASM_FLAGS doesn't work: http://www.cmake.org/Bug/view.php?id=14711
+else()
+ file(GLOB_RECURSE aes_src "src/*.c")
+endif()
+
+add_library(aes ${aes_src} ${aes_include})
+target_include_directories(aes PUBLIC include/)
+
+if(MSVC)
+ target_compile_definitions(aes PRIVATE _CRT_SECURE_NO_WARNINGS)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
+ target_compile_options(aes PUBLIC -mssse3 -maes)
+endif()
+
+install(TARGETS aes ARCHIVE DESTINATION lib)
+install(DIRECTORY include/aes DESTINATION include)
diff --git a/aes/include/aes/aes.h b/aes/include/aes/aes.h
new file mode 100644
index 0000000..1108235
--- /dev/null
+++ b/aes/include/aes/aes.h
@@ -0,0 +1,541 @@
+// 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.
+
+#pragma once
+
+#include "data.h"
+#include "error.h"
+#include "mode.h"
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef AES_Block128 AES_AES_Block;
+typedef AES_AES_Block AES_AES128_Block;
+typedef AES_AES_Block AES_AES192_Block;
+typedef AES_AES_Block AES_AES256_Block;
+
+typedef struct
+{
+ AES_AES_Block key;
+}
+AES_AES128_Key;
+
+typedef struct
+{
+ AES_AES_Block hi;
+ AES_AES_Block lo;
+}
+AES_AES192_Key;
+
+typedef struct
+{
+ AES_AES_Block hi;
+ AES_AES_Block lo;
+}
+AES_AES256_Key;
+
+static __inline AES_AES_Block aes_AES_make_block(
+ int hi3, int hi2, int lo1, int lo0)
+{
+ return aes_make_block128(hi3, hi2, lo1, lo0);
+}
+
+static __inline AES_AES128_Block aes_AES128_make_block(
+ int hi3, int hi2, int lo1, int lo0)
+{
+ return aes_AES_make_block(hi3, hi2, lo1, lo0);
+}
+
+static __inline AES_AES192_Block aes_AES192_make_block(
+ int hi3, int hi2, int lo1, int lo0)
+{
+ return aes_AES_make_block(hi3, hi2, lo1, lo0);
+}
+
+static __inline AES_AES256_Block aes_AES256_make_block(
+ int hi3, int hi2, int lo1, int lo0)
+{
+ return aes_AES_make_block(hi3, hi2, lo1, lo0);
+}
+
+static __inline AES_AES128_Key aes_AES128_make_key(
+ int hi3, int hi2, int lo1, int lo0)
+{
+ AES_AES128_Key key;
+ key.key = aes_AES_make_block(hi3, hi2, lo1, lo0);
+ return key;
+}
+
+static __inline AES_AES192_Key aes_AES192_make_key(
+ int hi5, int hi4,
+ int lo3, int lo2, int lo1, int lo0)
+{
+ AES_AES192_Key key;
+ key.hi = aes_AES_make_block( 0, 0, hi5, hi4);
+ key.lo = aes_AES_make_block(lo3, lo2, lo1, lo0);
+ return key;
+}
+
+static __inline AES_AES256_Key aes_AES256_make_key(
+ int hi7, int hi6, int hi5, int hi4,
+ int lo3, int lo2, int lo1, int lo0)
+{
+ AES_AES256_Key key;
+ key.hi = aes_AES_make_block(hi7, hi6, hi5, hi4);
+ key.lo = aes_AES_make_block(lo3, lo2, lo1, lo0);
+ return key;
+}
+
+typedef struct { char str[33]; } AES_AES_BlockString;
+typedef AES_AES_BlockString AES_AES128_BlockString;
+typedef AES_AES_BlockString AES_AES192_BlockString;
+typedef AES_AES_BlockString AES_AES256_BlockString;
+
+typedef struct { char str[49]; } AES_AES_BlockMatrixString;
+typedef AES_AES_BlockMatrixString AES_AES128_BlockMatrixString;
+typedef AES_AES_BlockMatrixString AES_AES192_BlockMatrixString;
+typedef AES_AES_BlockMatrixString AES_AES256_BlockMatrixString;
+
+AES_StatusCode aes_AES_format_block(
+ AES_AES_BlockString*,
+ const AES_AES_Block*,
+ AES_ErrorDetails*);
+
+static __inline AES_StatusCode aes_AES128_format_block(
+ AES_AES128_BlockString* dest,
+ const AES_AES128_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES192_format_block(
+ AES_AES192_BlockString* dest,
+ const AES_AES192_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES256_format_block(
+ AES_AES256_BlockString* dest,
+ const AES_AES256_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block(dest, src, err_details);
+}
+
+AES_StatusCode aes_AES_format_block_as_matrix(
+ AES_AES_BlockMatrixString*,
+ const AES_AES_Block*,
+ AES_ErrorDetails*);
+
+static __inline AES_StatusCode aes_AES128_format_block_as_matrix(
+ AES_AES128_BlockMatrixString* dest,
+ const AES_AES128_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block_as_matrix(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES192_format_block_as_matrix(
+ AES_AES192_BlockMatrixString* dest,
+ const AES_AES192_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block_as_matrix(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES256_format_block_as_matrix(
+ AES_AES256_BlockMatrixString* dest,
+ const AES_AES256_Block* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_format_block_as_matrix(dest, src, err_details);
+}
+
+AES_StatusCode aes_AES_print_block(
+ const AES_AES_Block*,
+ AES_ErrorDetails*);
+
+static __inline AES_StatusCode aes_AES128_print_block(
+ const AES_AES128_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block(block, err_details);
+}
+
+static __inline AES_StatusCode aes_AES192_print_block(
+ const AES_AES192_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block(block, err_details);
+}
+
+static __inline AES_StatusCode aes_AES256_print_block(
+ const AES_AES256_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block(block, err_details);
+}
+
+AES_StatusCode aes_AES_print_block_as_matrix(
+ const AES_AES_Block*,
+ AES_ErrorDetails*);
+
+static __inline AES_StatusCode aes_AES128_print_block_as_matrix(
+ const AES_AES128_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block_as_matrix(block, err_details);
+}
+
+static __inline AES_StatusCode aes_AES192_print_block_as_matrix(
+ const AES_AES192_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block_as_matrix(block, err_details);
+}
+
+static __inline AES_StatusCode aes_AES256_print_block_as_matrix(
+ const AES_AES256_Block* block,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_print_block_as_matrix(block, err_details);
+}
+
+AES_StatusCode aes_AES_parse_block(
+ AES_AES_Block* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+static __inline AES_StatusCode aes_AES128_parse_block(
+ AES_AES128_Block* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_parse_block(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES192_parse_block(
+ AES_AES192_Block* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_parse_block(dest, src, err_details);
+}
+
+static __inline AES_StatusCode aes_AES256_parse_block(
+ AES_AES256_Block* dest,
+ const char* src,
+ AES_ErrorDetails* err_details)
+{
+ return aes_AES_parse_block(dest, src, err_details);
+}
+
+typedef struct { char str[33]; } AES_AES128_KeyString;
+typedef struct { char str[49]; } AES_AES192_KeyString;
+typedef struct { char str[65]; } AES_AES256_KeyString;
+
+AES_StatusCode aes_AES128_format_key(
+ AES_AES128_KeyString*,
+ const AES_AES128_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES192_format_key(
+ AES_AES192_KeyString*,
+ const AES_AES192_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES256_format_key(
+ AES_AES256_KeyString*,
+ const AES_AES256_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES128_print_key(
+ const AES_AES128_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES192_print_key(
+ const AES_AES192_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES256_print_key(
+ const AES_AES256_Key*,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_AES128_parse_key(
+ AES_AES128_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_AES192_parse_key(
+ AES_AES192_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_AES256_parse_key(
+ AES_AES256_Key* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+typedef struct
+{
+ AES_AES_Block keys[11];
+}
+AES_AES128_RoundKeys;
+
+typedef struct
+{
+ AES_AES_Block keys[13];
+}
+AES_AES192_RoundKeys;
+
+typedef struct
+{
+ AES_AES_Block keys[15];
+}
+AES_AES256_RoundKeys;
+
+void __fastcall aes_AES128_expand_key_(
+ AES_AES_Block key,
+ AES_AES128_RoundKeys* encryption_keys);
+
+void __fastcall aes_AES192_expand_key_(
+ AES_AES_Block key_lo,
+ AES_AES_Block key_hi,
+ AES_AES192_RoundKeys* encryption_keys);
+
+void __fastcall aes_AES256_expand_key_(
+ AES_AES_Block key_lo,
+ AES_AES_Block key_hi,
+ AES_AES256_RoundKeys* encryption_keys);
+
+void __fastcall aes_AES128_derive_decryption_keys_(
+ const AES_AES128_RoundKeys* encryption_keys,
+ AES_AES128_RoundKeys* decryption_keys);
+
+void __fastcall aes_AES192_derive_decryption_keys_(
+ const AES_AES192_RoundKeys* encryption_keys,
+ AES_AES192_RoundKeys* decryption_keys);
+
+void __fastcall aes_AES256_derive_decryption_keys_(
+ const AES_AES256_RoundKeys* encryption_keys,
+ AES_AES256_RoundKeys* decryption_keys);
+
+AES_AES_Block __fastcall aes_AES128_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES128_RoundKeys*);
+
+AES_AES_Block __fastcall aes_AES192_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES192_RoundKeys*);
+
+AES_AES_Block __fastcall aes_AES256_encrypt_block_(
+ AES_AES_Block plaintext,
+ const AES_AES256_RoundKeys*);
+
+AES_AES_Block __fastcall aes_AES128_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES128_RoundKeys*);
+
+AES_AES_Block __fastcall aes_AES192_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES192_RoundKeys*);
+
+AES_AES_Block __fastcall aes_AES256_decrypt_block_(
+ AES_AES_Block ciphertext,
+ const AES_AES256_RoundKeys*);
+
+static __inline AES_AES_Block __fastcall aes_AES_xor_blocks(
+ AES_AES_Block a,
+ AES_AES_Block b)
+{
+ return aes_xor_block128(a, b);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES128_xor_blocks(
+ AES_AES128_Block a,
+ AES_AES128_Block b)
+{
+ return aes_AES_xor_blocks(a, b);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES192_xor_blocks(
+ AES_AES192_Block a,
+ AES_AES192_Block b)
+{
+ return aes_AES_xor_blocks(a, b);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES256_xor_blocks(
+ AES_AES256_Block a,
+ AES_AES256_Block b)
+{
+ return aes_AES_xor_blocks(a, b);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES_inc_block(
+ AES_AES_Block block)
+{
+ block = aes_reverse_byte_order_block128(block);
+ block = aes_inc_block128(block);
+ return aes_reverse_byte_order_block128(block);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES128_inc_block(
+ AES_AES128_Block block)
+{
+ return aes_AES_inc_block(block);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES192_inc_block(
+ AES_AES192_Block block)
+{
+ return aes_AES_inc_block(block);
+}
+
+static __inline AES_AES_Block __fastcall aes_AES256_inc_block(
+ AES_AES256_Block block)
+{
+ return aes_AES_inc_block(block);
+}
+
+AES_ENCRYPT_BLOCK_ECB(AES128);
+AES_DECRYPT_BLOCK_ECB(AES128);
+AES_ENCRYPT_BLOCK_CBC(AES128);
+AES_DECRYPT_BLOCK_CBC(AES128);
+AES_ENCRYPT_BLOCK_CFB(AES128);
+AES_DECRYPT_BLOCK_CFB(AES128);
+AES_ENCRYPT_BLOCK_OFB(AES128);
+AES_DECRYPT_BLOCK_OFB(AES128);
+AES_ENCRYPT_BLOCK_CTR(AES128);
+AES_DECRYPT_BLOCK_CTR(AES128);
+
+AES_ENCRYPT_BLOCK_ECB(AES192);
+AES_DECRYPT_BLOCK_ECB(AES192);
+AES_ENCRYPT_BLOCK_CBC(AES192);
+AES_DECRYPT_BLOCK_CBC(AES192);
+AES_ENCRYPT_BLOCK_CFB(AES192);
+AES_DECRYPT_BLOCK_CFB(AES192);
+AES_ENCRYPT_BLOCK_OFB(AES192);
+AES_DECRYPT_BLOCK_OFB(AES192);
+AES_ENCRYPT_BLOCK_CTR(AES192);
+AES_DECRYPT_BLOCK_CTR(AES192);
+
+AES_ENCRYPT_BLOCK_ECB(AES256);
+AES_DECRYPT_BLOCK_ECB(AES256);
+AES_ENCRYPT_BLOCK_CBC(AES256);
+AES_DECRYPT_BLOCK_CBC(AES256);
+AES_ENCRYPT_BLOCK_CFB(AES256);
+AES_DECRYPT_BLOCK_CFB(AES256);
+AES_ENCRYPT_BLOCK_OFB(AES256);
+AES_DECRYPT_BLOCK_OFB(AES256);
+AES_ENCRYPT_BLOCK_CTR(AES256);
+AES_DECRYPT_BLOCK_CTR(AES256);
+
+/**
+ * \brief Expands an AES-128 key into 10 encryption round keys.
+ *
+ * \param[in] key The AES-128 key.
+ * \param[out] encryption_keys The AES-128 encryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES128_expand_key(
+ const AES_AES128_Key* key,
+ AES_AES128_RoundKeys* encryption_keys)
+{
+ assert(encryption_keys);
+
+ aes_AES128_expand_key_(key->key, encryption_keys);
+}
+
+/**
+ * \brief Derives AES-128 decryption round keys from AES-128 encryption round keys.
+ *
+ * \param[in] encryption_keys The AES-128 encryption round keys. Must not be `NULL`.
+ * \param[out] decryption_keys The AES-128 decryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES128_derive_decryption_keys(
+ const AES_AES128_RoundKeys* encryption_keys,
+ AES_AES128_RoundKeys* decryption_keys)
+{
+ assert(encryption_keys);
+ assert(decryption_keys);
+
+ aes_AES128_derive_decryption_keys_(encryption_keys, decryption_keys);
+}
+
+/**
+ * \brief Expands an AES-192 key into 12 encryption round keys.
+ *
+ * \param[in] key The AES-192 key.
+ * \param[out] encryption_keys The AES-192 encryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES192_expand_key(
+ const AES_AES192_Key* key,
+ AES_AES192_RoundKeys* encryption_keys)
+{
+ assert(key);
+ assert(encryption_keys);
+
+ aes_AES192_expand_key_(key->lo, key->hi, encryption_keys);
+}
+
+/**
+ * \brief Derives AES-192 decryption round keys from AES-192 encryption round keys.
+ *
+ * \param[in] encryption_keys The AES-192 encryption round keys. Must not be `NULL`.
+ * \param[out] decryption_keys The AES-192 decryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES192_derive_decryption_keys(
+ const AES_AES192_RoundKeys* encryption_keys,
+ AES_AES192_RoundKeys* decryption_keys)
+{
+ assert(encryption_keys);
+ assert(decryption_keys);
+
+ aes_AES192_derive_decryption_keys_(encryption_keys, decryption_keys);
+}
+
+/**
+ * \brief Expands an AES-256 key into 14 encryption round keys.
+ *
+ * \param[in] key The AES-256 key.
+ * \param[out] encryption_keys The AES-256 encryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES256_expand_key(
+ const AES_AES256_Key* key,
+ AES_AES256_RoundKeys* encryption_keys)
+{
+ assert(key);
+ assert(encryption_keys);
+
+ aes_AES256_expand_key_(key->lo, key->hi, encryption_keys);
+}
+
+/**
+ * \brief Derives AES-256 decryption round keys from AES-256 encryption round keys.
+ *
+ * \param[in] encryption_keys The AES-256 encryption round keys. Must not be `NULL`.
+ * \param[out] decryption_keys The AES-256 decryption round keys. Must not be `NULL`.
+ */
+static __inline void __fastcall aes_AES256_derive_decryption_keys(
+ const AES_AES256_RoundKeys* encryption_keys,
+ AES_AES256_RoundKeys* decryption_keys)
+{
+ assert(encryption_keys);
+ assert(decryption_keys);
+
+ aes_AES256_derive_decryption_keys_(encryption_keys, decryption_keys);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/algorithm.h b/aes/include/aes/algorithm.h
new file mode 100644
index 0000000..d88cf59
--- /dev/null
+++ b/aes/include/aes/algorithm.h
@@ -0,0 +1,23 @@
+// 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.
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum
+{
+ AES_AES128,
+ AES_AES192,
+ AES_AES256,
+}
+AES_Algorithm;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/all.h b/aes/include/aes/all.h
new file mode 100644
index 0000000..ff27c18
--- /dev/null
+++ b/aes/include/aes/all.h
@@ -0,0 +1,21 @@
+// 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.
+
+#pragma once
+
+/**
+ * \defgroup aes AES
+ */
+
+#include "aes.h"
+#include "algorithm.h"
+#include "box.h"
+#include "box_aes.h"
+#include "box_data.h"
+#include "data.h"
+#include "error.h"
+#include "mode.h"
+#include "padding.h"
+#include "workarounds.h"
diff --git a/aes/include/aes/box.h b/aes/include/aes/box.h
new file mode 100644
index 0000000..2051d3d
--- /dev/null
+++ b/aes/include/aes/box.h
@@ -0,0 +1,81 @@
+// 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.
+
+#pragma once
+
+#include "algorithm.h"
+#include "box_data.h"
+#include "error.h"
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+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 aes_box_parse_key(
+ AES_BoxKey* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_box_parse_block(
+ AES_BoxBlock* dest,
+ AES_Algorithm algorithm,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_box_format_key(
+ AES_BoxKeyString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_box_format_block(
+ AES_BoxBlockString* dest,
+ AES_Algorithm algorithm,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_box_encrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* plaintext,
+ AES_BoxBlock* ciphertext,
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_box_decrypt_block(
+ AES_Box* box,
+ const AES_BoxBlock* ciphertext,
+ AES_BoxBlock* plaintext,
+ AES_ErrorDetails* err_details);
+
+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 aes_box_decrypt_buffer(
+ AES_Box* box,
+ const void* src,
+ size_t src_size,
+ void* dest,
+ size_t* dest_size,
+ AES_ErrorDetails* err_details);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/box_aes.h b/aes/include/aes/box_aes.h
new file mode 100644
index 0000000..c92d883
--- /dev/null
+++ b/aes/include/aes/box_aes.h
@@ -0,0 +1,21 @@
+// 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.
+
+#pragma once
+
+#include "box_data.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+extern AES_BoxAlgorithmInterface aes_box_algorithm_aes128;
+extern AES_BoxAlgorithmInterface aes_box_algorithm_aes192;
+extern AES_BoxAlgorithmInterface aes_box_algorithm_aes256;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/box_data.h b/aes/include/aes/box_data.h
new file mode 100644
index 0000000..e2315eb
--- /dev/null
+++ b/aes/include/aes/box_data.h
@@ -0,0 +1,153 @@
+// 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.
+
+#pragma once
+
+#include "aes.h"
+#include "error.h"
+#include "mode.h"
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef union
+{
+ AES_AES128_Key aes128_key;
+ AES_AES192_Key aes192_key;
+ AES_AES256_Key aes256_key;
+}
+AES_BoxKey;
+
+typedef union
+{
+ AES_AES128_RoundKeys aes128_encryption_keys;
+ AES_AES192_RoundKeys aes192_encryption_keys;
+ AES_AES256_RoundKeys aes256_encryption_keys;
+}
+AES_BoxEncryptionRoundKeys;
+
+typedef union
+{
+ AES_AES128_RoundKeys aes128_decryption_keys;
+ AES_AES192_RoundKeys aes192_decryption_keys;
+ AES_AES256_RoundKeys aes256_decryption_keys;
+}
+AES_BoxDecryptionRoundKeys;
+
+typedef union
+{
+ AES_AES128_KeyString aes128;
+ AES_AES192_KeyString aes192;
+ AES_AES256_KeyString aes256;
+}
+AES_BoxKeyString;
+
+typedef union
+{
+ AES_AES_Block aes_block;
+}
+AES_BoxBlock;
+
+typedef union
+{
+ AES_AES_BlockString aes;
+}
+AES_BoxBlockString;
+
+typedef AES_StatusCode (*AES_BoxCalculateRoundKeys)(
+ const AES_BoxKey* params,
+ AES_BoxEncryptionRoundKeys*,
+ AES_BoxDecryptionRoundKeys*,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxParseBlock)(
+ AES_BoxBlock* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxParseKey)(
+ AES_BoxKey* dest,
+ const char* src,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxFormatBlock)(
+ AES_BoxBlockString* dest,
+ const AES_BoxBlock* src,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxFormatKey)(
+ AES_BoxKeyString* dest,
+ const AES_BoxKey* src,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxEncryptBlock)(
+ const AES_BoxBlock* plaintext,
+ const AES_BoxEncryptionRoundKeys* params,
+ AES_BoxBlock* ciphertext,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxDecryptBlock)(
+ const AES_BoxBlock* ciphertext,
+ const AES_BoxDecryptionRoundKeys* params,
+ AES_BoxBlock* plaintext,
+ AES_ErrorDetails* err_details);
+
+typedef AES_StatusCode (*AES_BoxXorBlock)(
+ AES_BoxBlock*,
+ const AES_BoxBlock*,
+ AES_ErrorDetails*);
+
+typedef AES_StatusCode (*AES_BoxIncBlock)(
+ AES_BoxBlock*,
+ AES_ErrorDetails*);
+
+typedef AES_StatusCode (*AES_BoxGetBlockSize)(
+ size_t*,
+ AES_ErrorDetails*);
+
+typedef AES_StatusCode (*AES_BoxStoreBlock)(
+ void*,
+ const AES_BoxBlock*,
+ AES_ErrorDetails*);
+
+typedef AES_StatusCode (*AES_BoxLoadBlock)(
+ AES_BoxBlock*,
+ const void*,
+ AES_ErrorDetails*);
+
+typedef struct
+{
+ AES_BoxCalculateRoundKeys calc_round_keys;
+ AES_BoxParseBlock parse_block;
+ AES_BoxParseKey parse_key;
+ AES_BoxFormatBlock format_block;
+ AES_BoxFormatKey format_key;
+ AES_BoxEncryptBlock encrypt_block;
+ AES_BoxDecryptBlock decrypt_block;
+ AES_BoxXorBlock xor_block;
+ AES_BoxIncBlock inc_block;
+ AES_BoxGetBlockSize get_block_size;
+ AES_BoxStoreBlock store_block;
+ AES_BoxLoadBlock load_block;
+}
+AES_BoxAlgorithmInterface;
+
+typedef struct
+{
+ const AES_BoxAlgorithmInterface* algorithm;
+ AES_BoxEncryptionRoundKeys encryption_keys;
+ AES_BoxDecryptionRoundKeys decryption_keys;
+ AES_Mode mode;
+ AES_BoxBlock iv;
+}
+AES_Box;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/data.h b/aes/include/aes/data.h
new file mode 100644
index 0000000..a441939
--- /dev/null
+++ b/aes/include/aes/data.h
@@ -0,0 +1,122 @@
+// 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.
+
+#pragma once
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * \brief Represents a 128-bit block.
+ */
+typedef __m128i AES_Block128;
+
+/**
+ * \brief Loads a 128-bit block from a memory location.
+ *
+ * \param[in] src The pointer to a memory location. Must not be `NULL`.
+ *
+ * \return The loaded 128-bit block.
+ */
+static __inline AES_Block128 aes_load_block128(const void* src)
+{
+ return _mm_loadu_si128((AES_Block128*) src);
+}
+
+/**
+ * \brief Loads a 128-bit block from a 16-byte aligned memory location.
+ *
+ * \param[in] src The pointer to a 16-byte aligned memory location. Must not be `NULL`.
+ *
+ * \return The loaded 128-bit block.
+ */
+static __inline AES_Block128 aes_load_block128_aligned(const void* src)
+{
+ return _mm_load_si128((AES_Block128*) src);
+}
+
+/**
+ * \brief Stores a 128-bit block in a memory location.
+ *
+ * \param[out] dest The pointer to a memory location. Must not be `NULL`.
+ *
+ * \param[in] block The block to be stored.
+ */
+static __inline void __fastcall aes_store_block128(
+ void* dest,
+ AES_Block128 block)
+{
+ _mm_storeu_si128((AES_Block128*) dest, block);
+}
+
+/**
+ * \brief Stores a 128-bit block in a 16-byte aligned memory location.
+ *
+ * \param[out] dest The pointer to a 16-byte aligned memory location. Must not be `NULL`.
+ *
+ * \param[in] block The block to be stored.
+ */
+static __inline void __fastcall aes_store_block128_aligned(
+ void* dest,
+ AES_Block128 block)
+{
+ _mm_store_si128((AES_Block128*) dest, block);
+}
+
+/**
+ * \brief XORs two 128-bit blocks.
+ *
+ * \param[in] a The first XOR operand.
+ * \param[in] b The second XOR operand.
+ *
+ * \return `a^b`.
+ */
+static __inline AES_Block128 __fastcall aes_xor_block128(
+ AES_Block128 a,
+ AES_Block128 b)
+{
+ return _mm_xor_si128(a, b);
+}
+
+/**
+ * \brief Builds a 128-bit block from four 4-byte values.
+ *
+ * Builds a 128-bit block like this:
+ *
+ * * dest[127:96] = hi3
+ * * dest[95:64] = hi2
+ * * dest[63:32] = lo1
+ * * dest[31:0] = lo0
+ *
+ * \param[in] hi3 The most significant 4-byte value.
+ * \param[in] hi2 The more significant 4-byte value.
+ * \param[in] lo1 The less significant 4-byte value.
+ * \param[in] lo0 The least significant 4-byte value.
+ *
+ * \return The built 128-bit block.
+ */
+static __inline AES_Block128 __fastcall aes_make_block128(int hi3, int hi2, int lo1, int lo0)
+{
+ return _mm_set_epi32(hi3, hi2, lo1, lo0);
+}
+
+static __inline AES_Block128 __fastcall aes_reverse_byte_order_block128(AES_Block128 block)
+{
+ return _mm_shuffle_epi8(block, aes_make_block128(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f));
+}
+
+static __inline AES_Block128 __fastcall aes_inc_block128(AES_Block128 x)
+{
+ return _mm_add_epi32(x, aes_make_block128(0, 0, 0, 1));
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/error.h b/aes/include/aes/error.h
new file mode 100644
index 0000000..e094f8a
--- /dev/null
+++ b/aes/include/aes/error.h
@@ -0,0 +1,96 @@
+// 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.
+
+#pragma once
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum
+{
+ AES_SUCCESS,
+ AES_NULL_ARGUMENT_ERROR,
+ AES_PARSE_ERROR,
+ AES_INVALID_PKCS7_PADDING_ERROR,
+ AES_NOT_IMPLEMENTED_ERROR,
+ AES_MISSING_PADDING_ERROR,
+ AES_MEMORY_ALLOCATION_ERROR,
+}
+AES_StatusCode;
+
+static __inline int aes_is_error(AES_StatusCode ec)
+{
+ return ec != AES_SUCCESS;
+}
+
+const char* aes_strerror(AES_StatusCode ec);
+
+#define AES_MAX_CALL_STACK_LENGTH 32
+
+typedef struct
+{
+ AES_StatusCode ec; ///< Error code
+
+ union
+ {
+ struct { char param_name[32]; } null_arg;
+ struct
+ {
+ char src[128];
+ char what[32];
+ }
+ parse_error;
+ struct { char what[128]; } not_implemented;
+ }
+ params;
+
+ void* call_stack[AES_MAX_CALL_STACK_LENGTH];
+ size_t call_stack_len;
+}
+AES_ErrorDetails;
+
+static __inline AES_StatusCode aes_get_error_code(
+ const AES_ErrorDetails* err_details)
+{
+ return err_details->ec;
+}
+
+size_t aes_format_error(
+ const AES_ErrorDetails* err_details,
+ char* dest,
+ size_t dest_size);
+
+AES_StatusCode aes_success(
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_error_null_argument(
+ AES_ErrorDetails* err_details,
+ const char* param_name);
+
+AES_StatusCode aes_error_parse(
+ AES_ErrorDetails* err_details,
+ const char* src,
+ const char* what);
+
+AES_StatusCode aes_error_invalid_pkcs7_padding(
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_error_not_implemented(
+ AES_ErrorDetails* err_details,
+ const char* what);
+
+AES_StatusCode aes_error_missing_padding(
+ AES_ErrorDetails* err_details);
+
+AES_StatusCode aes_error_memory_allocation(
+ AES_ErrorDetails* err_details);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/mode.h b/aes/include/aes/mode.h
new file mode 100644
index 0000000..090628b
--- /dev/null
+++ b/aes/include/aes/mode.h
@@ -0,0 +1,166 @@
+// 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.
+
+#pragma once
+
+#include <assert.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum
+{
+ AES_ECB,
+ AES_CBC,
+ AES_CFB,
+ AES_OFB,
+ AES_CTR,
+}
+AES_Mode;
+
+#define AES_ENCRYPT_BLOCK_ECB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_encrypt_block_ECB( \
+ AES_## prefix ##_Block plaintext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys) \
+{ \
+ assert(encryption_keys); \
+\
+ return aes_## prefix ##_encrypt_block_(plaintext, encryption_keys); \
+}
+
+#define AES_DECRYPT_BLOCK_ECB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_decrypt_block_ECB( \
+ AES_## prefix ##_Block ciphertext, \
+ const AES_## prefix ##_RoundKeys* decryption_keys) \
+{ \
+ assert(decryption_keys); \
+\
+ return aes_## prefix ##_decrypt_block_(ciphertext, decryption_keys); \
+}
+
+#define AES_ENCRYPT_BLOCK_CBC(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_encrypt_block_CBC( \
+ AES_## prefix ##_Block plaintext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ return *next_init_vector = aes_## prefix ##_encrypt_block_( \
+ aes_## prefix ##_xor_blocks(plaintext, init_vector), encryption_keys); \
+}
+
+#define AES_DECRYPT_BLOCK_CBC(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_decrypt_block_CBC( \
+ AES_## prefix ##_Block ciphertext, \
+ const AES_## prefix ##_RoundKeys* decryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(decryption_keys); \
+ assert(next_init_vector); \
+\
+ AES_## prefix ##_Block plaintext = aes_## prefix ##_xor_blocks( \
+ aes_## prefix ##_decrypt_block_(ciphertext, decryption_keys), init_vector); \
+ *next_init_vector = ciphertext; \
+ return plaintext; \
+}
+
+#define AES_ENCRYPT_BLOCK_CFB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_encrypt_block_CFB( \
+ AES_## prefix ##_Block plaintext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ return *next_init_vector = aes_## prefix ##_xor_blocks( \
+ aes_## prefix ##_encrypt_block_(init_vector, encryption_keys), plaintext); \
+}
+
+#define AES_DECRYPT_BLOCK_CFB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_decrypt_block_CFB( \
+ AES_## prefix ##_Block ciphertext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ AES_## prefix ##_Block plaintext = aes_## prefix ##_xor_blocks( \
+ aes_## prefix ##_encrypt_block_(init_vector, encryption_keys), ciphertext); \
+ *next_init_vector = ciphertext; \
+ return plaintext; \
+}
+
+#define AES_ENCRYPT_BLOCK_OFB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_encrypt_block_OFB( \
+ AES_## prefix ##_Block plaintext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ AES_## prefix ##_Block tmp = aes_## prefix ##_encrypt_block_(init_vector, encryption_keys); \
+ *next_init_vector = tmp; \
+ return aes_## prefix ##_xor_blocks(tmp, plaintext); \
+}
+
+#define AES_DECRYPT_BLOCK_OFB(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_decrypt_block_OFB( \
+ AES_## prefix ##_Block ciphertext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ return aes_## prefix ##_encrypt_block_OFB( \
+ ciphertext, encryption_keys, init_vector, next_init_vector); \
+}
+
+#define AES_ENCRYPT_BLOCK_CTR(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_encrypt_block_CTR( \
+ AES_## prefix ##_Block plaintext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ AES_## prefix ##_Block ciphertext = aes_## prefix ##_xor_blocks( \
+ plaintext, aes_## prefix ##_encrypt_block_(init_vector, encryption_keys)); \
+ *next_init_vector = aes_## prefix ##_inc_block(init_vector); \
+ return ciphertext; \
+}
+
+#define AES_DECRYPT_BLOCK_CTR(prefix) \
+static __inline AES_## prefix ##_Block __fastcall aes_## prefix ##_decrypt_block_CTR( \
+ AES_## prefix ##_Block ciphertext, \
+ const AES_## prefix ##_RoundKeys* encryption_keys, \
+ AES_## prefix ##_Block init_vector, \
+ AES_## prefix ##_Block* next_init_vector) \
+{ \
+ assert(encryption_keys); \
+ assert(next_init_vector); \
+\
+ return aes_## prefix ##_encrypt_block_CTR( \
+ ciphertext, encryption_keys, init_vector, next_init_vector); \
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/padding.h b/aes/include/aes/padding.h
new file mode 100644
index 0000000..ba316f5
--- /dev/null
+++ b/aes/include/aes/padding.h
@@ -0,0 +1,38 @@
+// 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.
+
+#pragma once
+
+#include "error.h"
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef enum
+{
+ AES_PADDING_PKCS7,
+}
+AES_PaddingMethod;
+
+AES_StatusCode aes_extract_padding_size(
+ AES_PaddingMethod,
+ const void* src,
+ size_t src_size,
+ size_t* padding_size,
+ AES_ErrorDetails*);
+
+AES_StatusCode aes_fill_with_padding(
+ AES_PaddingMethod,
+ void* dest,
+ size_t padding_size,
+ AES_ErrorDetails*);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/aes/include/aes/workarounds.h b/aes/include/aes/workarounds.h
new file mode 100644
index 0000000..914bd21
--- /dev/null
+++ b/aes/include/aes/workarounds.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2016 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.
+
+#pragma once
+
+#if defined(_MSC_VER)
+#define AES_ALIGN(t, x) __declspec(align(x)) t
+#elif defined(__GNUC__) || defined(__MINGW32__)
+#define AES_ALIGN(t, x) t __attribute__((aligned(x)))
+#else
+#warning "couldn't determine alignment attribute"
+#endif
+
+#define AES_UNUSED_PARAMETER(...) (void) (__VA_ARGS__)
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");
+ }
+}