From 351c5188013fff041c7217aed64478cfc7643480 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sat, 21 Dec 2019 13:33:50 +0300 Subject: restructure the project --- aes/CMakeLists.txt | 28 ++ aes/include/aes/aes.h | 541 +++++++++++++++++++++++++++++++++ aes/include/aes/algorithm.h | 23 ++ aes/include/aes/all.h | 21 ++ aes/include/aes/box.h | 81 +++++ aes/include/aes/box_aes.h | 21 ++ aes/include/aes/box_data.h | 153 ++++++++++ aes/include/aes/data.h | 122 ++++++++ aes/include/aes/error.h | 96 ++++++ aes/include/aes/mode.h | 166 ++++++++++ aes/include/aes/padding.h | 38 +++ aes/include/aes/workarounds.h | 16 + aes/src/aes.c | 384 ++++++++++++++++++++++++ aes/src/asm/aes128.asm | 203 +++++++++++++ aes/src/asm/aes192.asm | 249 +++++++++++++++ aes/src/asm/aes256.asm | 287 ++++++++++++++++++ aes/src/box.c | 683 ++++++++++++++++++++++++++++++++++++++++++ aes/src/box_aes.c | 331 ++++++++++++++++++++ aes/src/c/aes128.c | 98 ++++++ aes/src/c/aes192.c | 133 ++++++++ aes/src/c/aes256.c | 161 ++++++++++ aes/src/error.c | 251 ++++++++++++++++ aes/src/padding.c | 88 ++++++ 23 files changed, 4174 insertions(+) create mode 100644 aes/CMakeLists.txt create mode 100644 aes/include/aes/aes.h create mode 100644 aes/include/aes/algorithm.h create mode 100644 aes/include/aes/all.h create mode 100644 aes/include/aes/box.h create mode 100644 aes/include/aes/box_aes.h create mode 100644 aes/include/aes/box_data.h create mode 100644 aes/include/aes/data.h create mode 100644 aes/include/aes/error.h create mode 100644 aes/include/aes/mode.h create mode 100644 aes/include/aes/padding.h create mode 100644 aes/include/aes/workarounds.h create mode 100644 aes/src/aes.c create mode 100644 aes/src/asm/aes128.asm create mode 100644 aes/src/asm/aes192.asm create mode 100644 aes/src/asm/aes256.asm create mode 100644 aes/src/box.c create mode 100644 aes/src/box_aes.c create mode 100644 aes/src/c/aes128.c create mode 100644 aes/src/c/aes192.c create mode 100644 aes/src/c/aes256.c create mode 100644 aes/src/error.c create mode 100644 aes/src/padding.c (limited to 'aes') 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 +// 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 + +#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 +// 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 +// 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 +// 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 + +#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 +// 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 +// 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 + +#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 +// 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 +#include + +#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 +// 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 + +#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 +// 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 + +#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 +// 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 + +#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 +// 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 + * 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 + +#include +#include +#include + +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 +; 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 +; 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 +; 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 + * 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 + +#include +#include + +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 + * 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 + +#include +#include + +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, + ¶ms->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, + ¶ms->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, + ¶ms->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, + ¶ms->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, + ¶ms->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, + ¶ms->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 + * 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 + +#include +#include + +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 + * 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 + +#include +#include + +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 + * 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 + +#include +#include + +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 + * 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 + +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include + +#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 + +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 + * 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 + +#include +#include +#include + +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"); + } +} -- cgit v1.2.3