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/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 +++++++ 11 files changed, 2868 insertions(+) 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/src') 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