diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 783ccd288..f67e649e1 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -58,6 +58,8 @@ add_library(common
string_util.h
thirdparty/SmallVector.cpp
thirdparty/SmallVector.h
+ thirdparty/aes.cpp
+ thirdparty/aes.h
threading.cpp
threading.h
timer.cpp
diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj
index 925c5486c..d08734283 100644
--- a/src/common/common.vcxproj
+++ b/src/common/common.vcxproj
@@ -41,6 +41,7 @@
+
@@ -69,6 +70,7 @@
+
diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters
index 6f329bd67..7e60a05f0 100644
--- a/src/common/common.vcxproj.filters
+++ b/src/common/common.vcxproj.filters
@@ -51,6 +51,7 @@
+
@@ -80,6 +81,7 @@
+
diff --git a/src/common/thirdparty/aes.cpp b/src/common/thirdparty/aes.cpp
new file mode 100644
index 000000000..974f700e5
--- /dev/null
+++ b/src/common/thirdparty/aes.cpp
@@ -0,0 +1,1173 @@
+/*********************************************************************
+* Filename: aes.c
+* Author: Brad Conte (brad AT bradconte.com)
+* Copyright:
+* Disclaimer: This code is presented "as is" without any guarantees.
+* Details: This code is the implementation of the AES algorithm and
+ the CTR, CBC, and CCM modes of operation it can be used in.
+ AES is, specified by the NIST in in publication FIPS PUB 197,
+ availible at:
+ * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf .
+ The CBC and CTR modes of operation are specified by
+ NIST SP 800-38 A, available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf .
+ The CCM mode of operation is specified by NIST SP80-38 C, available at:
+ * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
+*********************************************************************/
+
+/*************************** HEADER FILES ***************************/
+#include "aes.h"
+
+#include
+#include
+
+/****************************** MACROS ******************************/
+// The least significant byte of the word is rotated to the end.
+#define KE_ROTWORD(x) (((x) << 8) | ((x) >> 24))
+
+/**************************** DATA TYPES ****************************/
+#define AES_128_ROUNDS 10
+#define AES_192_ROUNDS 12
+#define AES_256_ROUNDS 14
+
+/*********************** FUNCTION DECLARATIONS **********************/
+#if 0
+static void ccm_prepare_first_ctr_blk(uint8_t counter[], const uint8_t nonce[], int nonce_len,
+ int payload_len_store_size);
+static void ccm_prepare_first_format_blk(uint8_t buf[], int assoc_len, int payload_len, int payload_len_store_size,
+ int mac_len, const uint8_t nonce[], int nonce_len);
+static void ccm_format_assoc_data(uint8_t buf[], int* end_of_buf, const uint8_t assoc[], int assoc_len);
+static void ccm_format_payload_data(uint8_t buf[], int* end_of_buf, const uint8_t payload[], int payload_len);
+#endif
+
+/**************************** VARIABLES *****************************/
+// This is the specified AES SBox. To look up a substitution value, put the first
+// nibble in the first index (row) and the second nibble in the second index (column).
+static const uint8_t aes_sbox[16][16] = {
+ {0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76},
+ {0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0},
+ {0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15},
+ {0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75},
+ {0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84},
+ {0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF},
+ {0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8},
+ {0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2},
+ {0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73},
+ {0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB},
+ {0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79},
+ {0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08},
+ {0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A},
+ {0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E},
+ {0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF},
+ {0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}};
+
+static const uint8_t aes_invsbox[16][16] = {
+ {0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB},
+ {0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB},
+ {0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E},
+ {0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25},
+ {0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92},
+ {0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84},
+ {0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06},
+ {0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B},
+ {0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73},
+ {0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E},
+ {0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B},
+ {0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4},
+ {0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F},
+ {0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF},
+ {0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61},
+ {0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D}};
+
+// This table stores pre-calculated values for all possible GF(2^8) calculations.This
+// table is only used by the (Inv)MixColumns steps.
+// USAGE: The second index (column) is the coefficient of multiplication. Only 7 different
+// coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by
+// 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one
+// of these coefficients, in the ascending order of value, from values 0x00 to 0xFF.
+static const uint8_t gf_mul[256][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e}, {0x04, 0x06, 0x12, 0x16, 0x1a, 0x1c},
+ {0x06, 0x05, 0x1b, 0x1d, 0x17, 0x12}, {0x08, 0x0c, 0x24, 0x2c, 0x34, 0x38}, {0x0a, 0x0f, 0x2d, 0x27, 0x39, 0x36},
+ {0x0c, 0x0a, 0x36, 0x3a, 0x2e, 0x24}, {0x0e, 0x09, 0x3f, 0x31, 0x23, 0x2a}, {0x10, 0x18, 0x48, 0x58, 0x68, 0x70},
+ {0x12, 0x1b, 0x41, 0x53, 0x65, 0x7e}, {0x14, 0x1e, 0x5a, 0x4e, 0x72, 0x6c}, {0x16, 0x1d, 0x53, 0x45, 0x7f, 0x62},
+ {0x18, 0x14, 0x6c, 0x74, 0x5c, 0x48}, {0x1a, 0x17, 0x65, 0x7f, 0x51, 0x46}, {0x1c, 0x12, 0x7e, 0x62, 0x46, 0x54},
+ {0x1e, 0x11, 0x77, 0x69, 0x4b, 0x5a}, {0x20, 0x30, 0x90, 0xb0, 0xd0, 0xe0}, {0x22, 0x33, 0x99, 0xbb, 0xdd, 0xee},
+ {0x24, 0x36, 0x82, 0xa6, 0xca, 0xfc}, {0x26, 0x35, 0x8b, 0xad, 0xc7, 0xf2}, {0x28, 0x3c, 0xb4, 0x9c, 0xe4, 0xd8},
+ {0x2a, 0x3f, 0xbd, 0x97, 0xe9, 0xd6}, {0x2c, 0x3a, 0xa6, 0x8a, 0xfe, 0xc4}, {0x2e, 0x39, 0xaf, 0x81, 0xf3, 0xca},
+ {0x30, 0x28, 0xd8, 0xe8, 0xb8, 0x90}, {0x32, 0x2b, 0xd1, 0xe3, 0xb5, 0x9e}, {0x34, 0x2e, 0xca, 0xfe, 0xa2, 0x8c},
+ {0x36, 0x2d, 0xc3, 0xf5, 0xaf, 0x82}, {0x38, 0x24, 0xfc, 0xc4, 0x8c, 0xa8}, {0x3a, 0x27, 0xf5, 0xcf, 0x81, 0xa6},
+ {0x3c, 0x22, 0xee, 0xd2, 0x96, 0xb4}, {0x3e, 0x21, 0xe7, 0xd9, 0x9b, 0xba}, {0x40, 0x60, 0x3b, 0x7b, 0xbb, 0xdb},
+ {0x42, 0x63, 0x32, 0x70, 0xb6, 0xd5}, {0x44, 0x66, 0x29, 0x6d, 0xa1, 0xc7}, {0x46, 0x65, 0x20, 0x66, 0xac, 0xc9},
+ {0x48, 0x6c, 0x1f, 0x57, 0x8f, 0xe3}, {0x4a, 0x6f, 0x16, 0x5c, 0x82, 0xed}, {0x4c, 0x6a, 0x0d, 0x41, 0x95, 0xff},
+ {0x4e, 0x69, 0x04, 0x4a, 0x98, 0xf1}, {0x50, 0x78, 0x73, 0x23, 0xd3, 0xab}, {0x52, 0x7b, 0x7a, 0x28, 0xde, 0xa5},
+ {0x54, 0x7e, 0x61, 0x35, 0xc9, 0xb7}, {0x56, 0x7d, 0x68, 0x3e, 0xc4, 0xb9}, {0x58, 0x74, 0x57, 0x0f, 0xe7, 0x93},
+ {0x5a, 0x77, 0x5e, 0x04, 0xea, 0x9d}, {0x5c, 0x72, 0x45, 0x19, 0xfd, 0x8f}, {0x5e, 0x71, 0x4c, 0x12, 0xf0, 0x81},
+ {0x60, 0x50, 0xab, 0xcb, 0x6b, 0x3b}, {0x62, 0x53, 0xa2, 0xc0, 0x66, 0x35}, {0x64, 0x56, 0xb9, 0xdd, 0x71, 0x27},
+ {0x66, 0x55, 0xb0, 0xd6, 0x7c, 0x29}, {0x68, 0x5c, 0x8f, 0xe7, 0x5f, 0x03}, {0x6a, 0x5f, 0x86, 0xec, 0x52, 0x0d},
+ {0x6c, 0x5a, 0x9d, 0xf1, 0x45, 0x1f}, {0x6e, 0x59, 0x94, 0xfa, 0x48, 0x11}, {0x70, 0x48, 0xe3, 0x93, 0x03, 0x4b},
+ {0x72, 0x4b, 0xea, 0x98, 0x0e, 0x45}, {0x74, 0x4e, 0xf1, 0x85, 0x19, 0x57}, {0x76, 0x4d, 0xf8, 0x8e, 0x14, 0x59},
+ {0x78, 0x44, 0xc7, 0xbf, 0x37, 0x73}, {0x7a, 0x47, 0xce, 0xb4, 0x3a, 0x7d}, {0x7c, 0x42, 0xd5, 0xa9, 0x2d, 0x6f},
+ {0x7e, 0x41, 0xdc, 0xa2, 0x20, 0x61}, {0x80, 0xc0, 0x76, 0xf6, 0x6d, 0xad}, {0x82, 0xc3, 0x7f, 0xfd, 0x60, 0xa3},
+ {0x84, 0xc6, 0x64, 0xe0, 0x77, 0xb1}, {0x86, 0xc5, 0x6d, 0xeb, 0x7a, 0xbf}, {0x88, 0xcc, 0x52, 0xda, 0x59, 0x95},
+ {0x8a, 0xcf, 0x5b, 0xd1, 0x54, 0x9b}, {0x8c, 0xca, 0x40, 0xcc, 0x43, 0x89}, {0x8e, 0xc9, 0x49, 0xc7, 0x4e, 0x87},
+ {0x90, 0xd8, 0x3e, 0xae, 0x05, 0xdd}, {0x92, 0xdb, 0x37, 0xa5, 0x08, 0xd3}, {0x94, 0xde, 0x2c, 0xb8, 0x1f, 0xc1},
+ {0x96, 0xdd, 0x25, 0xb3, 0x12, 0xcf}, {0x98, 0xd4, 0x1a, 0x82, 0x31, 0xe5}, {0x9a, 0xd7, 0x13, 0x89, 0x3c, 0xeb},
+ {0x9c, 0xd2, 0x08, 0x94, 0x2b, 0xf9}, {0x9e, 0xd1, 0x01, 0x9f, 0x26, 0xf7}, {0xa0, 0xf0, 0xe6, 0x46, 0xbd, 0x4d},
+ {0xa2, 0xf3, 0xef, 0x4d, 0xb0, 0x43}, {0xa4, 0xf6, 0xf4, 0x50, 0xa7, 0x51}, {0xa6, 0xf5, 0xfd, 0x5b, 0xaa, 0x5f},
+ {0xa8, 0xfc, 0xc2, 0x6a, 0x89, 0x75}, {0xaa, 0xff, 0xcb, 0x61, 0x84, 0x7b}, {0xac, 0xfa, 0xd0, 0x7c, 0x93, 0x69},
+ {0xae, 0xf9, 0xd9, 0x77, 0x9e, 0x67}, {0xb0, 0xe8, 0xae, 0x1e, 0xd5, 0x3d}, {0xb2, 0xeb, 0xa7, 0x15, 0xd8, 0x33},
+ {0xb4, 0xee, 0xbc, 0x08, 0xcf, 0x21}, {0xb6, 0xed, 0xb5, 0x03, 0xc2, 0x2f}, {0xb8, 0xe4, 0x8a, 0x32, 0xe1, 0x05},
+ {0xba, 0xe7, 0x83, 0x39, 0xec, 0x0b}, {0xbc, 0xe2, 0x98, 0x24, 0xfb, 0x19}, {0xbe, 0xe1, 0x91, 0x2f, 0xf6, 0x17},
+ {0xc0, 0xa0, 0x4d, 0x8d, 0xd6, 0x76}, {0xc2, 0xa3, 0x44, 0x86, 0xdb, 0x78}, {0xc4, 0xa6, 0x5f, 0x9b, 0xcc, 0x6a},
+ {0xc6, 0xa5, 0x56, 0x90, 0xc1, 0x64}, {0xc8, 0xac, 0x69, 0xa1, 0xe2, 0x4e}, {0xca, 0xaf, 0x60, 0xaa, 0xef, 0x40},
+ {0xcc, 0xaa, 0x7b, 0xb7, 0xf8, 0x52}, {0xce, 0xa9, 0x72, 0xbc, 0xf5, 0x5c}, {0xd0, 0xb8, 0x05, 0xd5, 0xbe, 0x06},
+ {0xd2, 0xbb, 0x0c, 0xde, 0xb3, 0x08}, {0xd4, 0xbe, 0x17, 0xc3, 0xa4, 0x1a}, {0xd6, 0xbd, 0x1e, 0xc8, 0xa9, 0x14},
+ {0xd8, 0xb4, 0x21, 0xf9, 0x8a, 0x3e}, {0xda, 0xb7, 0x28, 0xf2, 0x87, 0x30}, {0xdc, 0xb2, 0x33, 0xef, 0x90, 0x22},
+ {0xde, 0xb1, 0x3a, 0xe4, 0x9d, 0x2c}, {0xe0, 0x90, 0xdd, 0x3d, 0x06, 0x96}, {0xe2, 0x93, 0xd4, 0x36, 0x0b, 0x98},
+ {0xe4, 0x96, 0xcf, 0x2b, 0x1c, 0x8a}, {0xe6, 0x95, 0xc6, 0x20, 0x11, 0x84}, {0xe8, 0x9c, 0xf9, 0x11, 0x32, 0xae},
+ {0xea, 0x9f, 0xf0, 0x1a, 0x3f, 0xa0}, {0xec, 0x9a, 0xeb, 0x07, 0x28, 0xb2}, {0xee, 0x99, 0xe2, 0x0c, 0x25, 0xbc},
+ {0xf0, 0x88, 0x95, 0x65, 0x6e, 0xe6}, {0xf2, 0x8b, 0x9c, 0x6e, 0x63, 0xe8}, {0xf4, 0x8e, 0x87, 0x73, 0x74, 0xfa},
+ {0xf6, 0x8d, 0x8e, 0x78, 0x79, 0xf4}, {0xf8, 0x84, 0xb1, 0x49, 0x5a, 0xde}, {0xfa, 0x87, 0xb8, 0x42, 0x57, 0xd0},
+ {0xfc, 0x82, 0xa3, 0x5f, 0x40, 0xc2}, {0xfe, 0x81, 0xaa, 0x54, 0x4d, 0xcc}, {0x1b, 0x9b, 0xec, 0xf7, 0xda, 0x41},
+ {0x19, 0x98, 0xe5, 0xfc, 0xd7, 0x4f}, {0x1f, 0x9d, 0xfe, 0xe1, 0xc0, 0x5d}, {0x1d, 0x9e, 0xf7, 0xea, 0xcd, 0x53},
+ {0x13, 0x97, 0xc8, 0xdb, 0xee, 0x79}, {0x11, 0x94, 0xc1, 0xd0, 0xe3, 0x77}, {0x17, 0x91, 0xda, 0xcd, 0xf4, 0x65},
+ {0x15, 0x92, 0xd3, 0xc6, 0xf9, 0x6b}, {0x0b, 0x83, 0xa4, 0xaf, 0xb2, 0x31}, {0x09, 0x80, 0xad, 0xa4, 0xbf, 0x3f},
+ {0x0f, 0x85, 0xb6, 0xb9, 0xa8, 0x2d}, {0x0d, 0x86, 0xbf, 0xb2, 0xa5, 0x23}, {0x03, 0x8f, 0x80, 0x83, 0x86, 0x09},
+ {0x01, 0x8c, 0x89, 0x88, 0x8b, 0x07}, {0x07, 0x89, 0x92, 0x95, 0x9c, 0x15}, {0x05, 0x8a, 0x9b, 0x9e, 0x91, 0x1b},
+ {0x3b, 0xab, 0x7c, 0x47, 0x0a, 0xa1}, {0x39, 0xa8, 0x75, 0x4c, 0x07, 0xaf}, {0x3f, 0xad, 0x6e, 0x51, 0x10, 0xbd},
+ {0x3d, 0xae, 0x67, 0x5a, 0x1d, 0xb3}, {0x33, 0xa7, 0x58, 0x6b, 0x3e, 0x99}, {0x31, 0xa4, 0x51, 0x60, 0x33, 0x97},
+ {0x37, 0xa1, 0x4a, 0x7d, 0x24, 0x85}, {0x35, 0xa2, 0x43, 0x76, 0x29, 0x8b}, {0x2b, 0xb3, 0x34, 0x1f, 0x62, 0xd1},
+ {0x29, 0xb0, 0x3d, 0x14, 0x6f, 0xdf}, {0x2f, 0xb5, 0x26, 0x09, 0x78, 0xcd}, {0x2d, 0xb6, 0x2f, 0x02, 0x75, 0xc3},
+ {0x23, 0xbf, 0x10, 0x33, 0x56, 0xe9}, {0x21, 0xbc, 0x19, 0x38, 0x5b, 0xe7}, {0x27, 0xb9, 0x02, 0x25, 0x4c, 0xf5},
+ {0x25, 0xba, 0x0b, 0x2e, 0x41, 0xfb}, {0x5b, 0xfb, 0xd7, 0x8c, 0x61, 0x9a}, {0x59, 0xf8, 0xde, 0x87, 0x6c, 0x94},
+ {0x5f, 0xfd, 0xc5, 0x9a, 0x7b, 0x86}, {0x5d, 0xfe, 0xcc, 0x91, 0x76, 0x88}, {0x53, 0xf7, 0xf3, 0xa0, 0x55, 0xa2},
+ {0x51, 0xf4, 0xfa, 0xab, 0x58, 0xac}, {0x57, 0xf1, 0xe1, 0xb6, 0x4f, 0xbe}, {0x55, 0xf2, 0xe8, 0xbd, 0x42, 0xb0},
+ {0x4b, 0xe3, 0x9f, 0xd4, 0x09, 0xea}, {0x49, 0xe0, 0x96, 0xdf, 0x04, 0xe4}, {0x4f, 0xe5, 0x8d, 0xc2, 0x13, 0xf6},
+ {0x4d, 0xe6, 0x84, 0xc9, 0x1e, 0xf8}, {0x43, 0xef, 0xbb, 0xf8, 0x3d, 0xd2}, {0x41, 0xec, 0xb2, 0xf3, 0x30, 0xdc},
+ {0x47, 0xe9, 0xa9, 0xee, 0x27, 0xce}, {0x45, 0xea, 0xa0, 0xe5, 0x2a, 0xc0}, {0x7b, 0xcb, 0x47, 0x3c, 0xb1, 0x7a},
+ {0x79, 0xc8, 0x4e, 0x37, 0xbc, 0x74}, {0x7f, 0xcd, 0x55, 0x2a, 0xab, 0x66}, {0x7d, 0xce, 0x5c, 0x21, 0xa6, 0x68},
+ {0x73, 0xc7, 0x63, 0x10, 0x85, 0x42}, {0x71, 0xc4, 0x6a, 0x1b, 0x88, 0x4c}, {0x77, 0xc1, 0x71, 0x06, 0x9f, 0x5e},
+ {0x75, 0xc2, 0x78, 0x0d, 0x92, 0x50}, {0x6b, 0xd3, 0x0f, 0x64, 0xd9, 0x0a}, {0x69, 0xd0, 0x06, 0x6f, 0xd4, 0x04},
+ {0x6f, 0xd5, 0x1d, 0x72, 0xc3, 0x16}, {0x6d, 0xd6, 0x14, 0x79, 0xce, 0x18}, {0x63, 0xdf, 0x2b, 0x48, 0xed, 0x32},
+ {0x61, 0xdc, 0x22, 0x43, 0xe0, 0x3c}, {0x67, 0xd9, 0x39, 0x5e, 0xf7, 0x2e}, {0x65, 0xda, 0x30, 0x55, 0xfa, 0x20},
+ {0x9b, 0x5b, 0x9a, 0x01, 0xb7, 0xec}, {0x99, 0x58, 0x93, 0x0a, 0xba, 0xe2}, {0x9f, 0x5d, 0x88, 0x17, 0xad, 0xf0},
+ {0x9d, 0x5e, 0x81, 0x1c, 0xa0, 0xfe}, {0x93, 0x57, 0xbe, 0x2d, 0x83, 0xd4}, {0x91, 0x54, 0xb7, 0x26, 0x8e, 0xda},
+ {0x97, 0x51, 0xac, 0x3b, 0x99, 0xc8}, {0x95, 0x52, 0xa5, 0x30, 0x94, 0xc6}, {0x8b, 0x43, 0xd2, 0x59, 0xdf, 0x9c},
+ {0x89, 0x40, 0xdb, 0x52, 0xd2, 0x92}, {0x8f, 0x45, 0xc0, 0x4f, 0xc5, 0x80}, {0x8d, 0x46, 0xc9, 0x44, 0xc8, 0x8e},
+ {0x83, 0x4f, 0xf6, 0x75, 0xeb, 0xa4}, {0x81, 0x4c, 0xff, 0x7e, 0xe6, 0xaa}, {0x87, 0x49, 0xe4, 0x63, 0xf1, 0xb8},
+ {0x85, 0x4a, 0xed, 0x68, 0xfc, 0xb6}, {0xbb, 0x6b, 0x0a, 0xb1, 0x67, 0x0c}, {0xb9, 0x68, 0x03, 0xba, 0x6a, 0x02},
+ {0xbf, 0x6d, 0x18, 0xa7, 0x7d, 0x10}, {0xbd, 0x6e, 0x11, 0xac, 0x70, 0x1e}, {0xb3, 0x67, 0x2e, 0x9d, 0x53, 0x34},
+ {0xb1, 0x64, 0x27, 0x96, 0x5e, 0x3a}, {0xb7, 0x61, 0x3c, 0x8b, 0x49, 0x28}, {0xb5, 0x62, 0x35, 0x80, 0x44, 0x26},
+ {0xab, 0x73, 0x42, 0xe9, 0x0f, 0x7c}, {0xa9, 0x70, 0x4b, 0xe2, 0x02, 0x72}, {0xaf, 0x75, 0x50, 0xff, 0x15, 0x60},
+ {0xad, 0x76, 0x59, 0xf4, 0x18, 0x6e}, {0xa3, 0x7f, 0x66, 0xc5, 0x3b, 0x44}, {0xa1, 0x7c, 0x6f, 0xce, 0x36, 0x4a},
+ {0xa7, 0x79, 0x74, 0xd3, 0x21, 0x58}, {0xa5, 0x7a, 0x7d, 0xd8, 0x2c, 0x56}, {0xdb, 0x3b, 0xa1, 0x7a, 0x0c, 0x37},
+ {0xd9, 0x38, 0xa8, 0x71, 0x01, 0x39}, {0xdf, 0x3d, 0xb3, 0x6c, 0x16, 0x2b}, {0xdd, 0x3e, 0xba, 0x67, 0x1b, 0x25},
+ {0xd3, 0x37, 0x85, 0x56, 0x38, 0x0f}, {0xd1, 0x34, 0x8c, 0x5d, 0x35, 0x01}, {0xd7, 0x31, 0x97, 0x40, 0x22, 0x13},
+ {0xd5, 0x32, 0x9e, 0x4b, 0x2f, 0x1d}, {0xcb, 0x23, 0xe9, 0x22, 0x64, 0x47}, {0xc9, 0x20, 0xe0, 0x29, 0x69, 0x49},
+ {0xcf, 0x25, 0xfb, 0x34, 0x7e, 0x5b}, {0xcd, 0x26, 0xf2, 0x3f, 0x73, 0x55}, {0xc3, 0x2f, 0xcd, 0x0e, 0x50, 0x7f},
+ {0xc1, 0x2c, 0xc4, 0x05, 0x5d, 0x71}, {0xc7, 0x29, 0xdf, 0x18, 0x4a, 0x63}, {0xc5, 0x2a, 0xd6, 0x13, 0x47, 0x6d},
+ {0xfb, 0x0b, 0x31, 0xca, 0xdc, 0xd7}, {0xf9, 0x08, 0x38, 0xc1, 0xd1, 0xd9}, {0xff, 0x0d, 0x23, 0xdc, 0xc6, 0xcb},
+ {0xfd, 0x0e, 0x2a, 0xd7, 0xcb, 0xc5}, {0xf3, 0x07, 0x15, 0xe6, 0xe8, 0xef}, {0xf1, 0x04, 0x1c, 0xed, 0xe5, 0xe1},
+ {0xf7, 0x01, 0x07, 0xf0, 0xf2, 0xf3}, {0xf5, 0x02, 0x0e, 0xfb, 0xff, 0xfd}, {0xeb, 0x13, 0x79, 0x92, 0xb4, 0xa7},
+ {0xe9, 0x10, 0x70, 0x99, 0xb9, 0xa9}, {0xef, 0x15, 0x6b, 0x84, 0xae, 0xbb}, {0xed, 0x16, 0x62, 0x8f, 0xa3, 0xb5},
+ {0xe3, 0x1f, 0x5d, 0xbe, 0x80, 0x9f}, {0xe1, 0x1c, 0x54, 0xb5, 0x8d, 0x91}, {0xe7, 0x19, 0x4f, 0xa8, 0x9a, 0x83},
+ {0xe5, 0x1a, 0x46, 0xa3, 0x97, 0x8d}};
+
+/*********************** FUNCTION DEFINITIONS ***********************/
+// XORs the in and out buffers, storing the result in out. Length is in bytes.
+static void xor_buf(const uint8_t in[], uint8_t out[], size_t len)
+{
+ for (size_t idx = 0; idx < len; idx++)
+ out[idx] ^= in[idx];
+}
+
+/*******************
+ * AES - CBC
+ *******************/
+bool aes_encrypt_cbc(const uint8_t in[], size_t in_len, uint8_t out[], const uint32_t key[], int keysize,
+ const uint8_t iv[])
+{
+ uint8_t buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
+
+ if (in_len % AES_BLOCK_SIZE != 0)
+ return false;
+
+ const size_t blocks = in_len / AES_BLOCK_SIZE;
+
+ std::memcpy(iv_buf, iv, AES_BLOCK_SIZE);
+
+ for (size_t idx = 0; idx < blocks; idx++)
+ {
+ std::memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+ xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE);
+ aes_encrypt(buf_in, buf_out, key, keysize);
+ std::memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE);
+ std::memcpy(iv_buf, buf_out, AES_BLOCK_SIZE);
+ }
+
+ return true;
+}
+
+#if 0
+bool aes_encrypt_cbc_mac(const uint8_t in[], size_t in_len, uint8_t out[], const uint32_t key[], int keysize,
+ const uint8_t iv[])
+{
+ uint8_t buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
+
+ if (in_len % AES_BLOCK_SIZE != 0)
+ return false;
+
+ const size_t blocks = in_len / AES_BLOCK_SIZE;
+
+ std::memcpy(iv_buf, iv, AES_BLOCK_SIZE);
+
+ for (size_t idx = 0; idx < blocks; idx++)
+ {
+ std::memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+ xor_buf(iv_buf, buf_in, AES_BLOCK_SIZE);
+ aes_encrypt(buf_in, buf_out, key, keysize);
+ std::memcpy(iv_buf, buf_out, AES_BLOCK_SIZE);
+ // Do not output all encrypted blocks.
+ }
+
+ std::memcpy(out, buf_out, AES_BLOCK_SIZE); // Only output the last block.
+
+ return true;
+}
+#endif
+
+bool aes_decrypt_cbc(const uint8_t in[], size_t in_len, uint8_t out[], const uint32_t key[], int keysize,
+ const uint8_t iv[])
+{
+ uint8_t buf_in[AES_BLOCK_SIZE], buf_out[AES_BLOCK_SIZE], iv_buf[AES_BLOCK_SIZE];
+
+ if (in_len % AES_BLOCK_SIZE != 0)
+ return false;
+
+ const size_t blocks = in_len / AES_BLOCK_SIZE;
+
+ std::memcpy(iv_buf, iv, AES_BLOCK_SIZE);
+
+ for (size_t idx = 0; idx < blocks; idx++)
+ {
+ std::memcpy(buf_in, &in[idx * AES_BLOCK_SIZE], AES_BLOCK_SIZE);
+ aes_decrypt(buf_in, buf_out, key, keysize);
+ xor_buf(iv_buf, buf_out, AES_BLOCK_SIZE);
+ std::memcpy(&out[idx * AES_BLOCK_SIZE], buf_out, AES_BLOCK_SIZE);
+ std::memcpy(iv_buf, buf_in, AES_BLOCK_SIZE);
+ }
+
+ return true;
+}
+
+#if 0
+/*******************
+ * AES - CTR
+ *******************/
+void aes_increment_iv(uint8_t iv[], int counter_size)
+{
+ // Use counter_size bytes at the end of the IV as the big-endian integer to increment.
+ for (uint32_t idx = AES_BLOCK_SIZE - 1; idx >= AES_BLOCK_SIZE - counter_size; idx--)
+ {
+ iv[idx]++;
+ if (iv[idx] != 0 || idx == AES_BLOCK_SIZE - counter_size)
+ break;
+ }
+}
+
+// Performs the encryption in-place, the input and output buffers may be the same.
+// Input may be an arbitrary length (in bytes).
+void aes_encrypt_ctr(const uint8_t in[], size_t in_len, uint8_t out[], const uint32_t key[], int keysize,
+ const uint8_t iv[])
+{
+ size_t idx = 0, last_block_length;
+ uint8_t iv_buf[AES_BLOCK_SIZE], out_buf[AES_BLOCK_SIZE];
+
+ if (in != out)
+ std::memcpy(out, in, in_len);
+
+ std::memcpy(iv_buf, iv, AES_BLOCK_SIZE);
+ last_block_length = in_len - AES_BLOCK_SIZE;
+
+ if (in_len > AES_BLOCK_SIZE)
+ {
+ for (idx = 0; idx < last_block_length; idx += AES_BLOCK_SIZE)
+ {
+ aes_encrypt(iv_buf, out_buf, key, keysize);
+ xor_buf(out_buf, &out[idx], AES_BLOCK_SIZE);
+ aes_increment_iv(iv_buf, AES_BLOCK_SIZE);
+ }
+ }
+
+ aes_encrypt(iv_buf, out_buf, key, keysize);
+ xor_buf(out_buf, &out[idx], in_len - idx); // Use the Most Significant bytes.
+}
+
+void aes_decrypt_ctr(const uint8_t in[], size_t in_len, uint8_t out[], const uint32_t key[], int keysize,
+ const uint8_t iv[])
+{
+ // CTR encryption is its own inverse function.
+ aes_encrypt_ctr(in, in_len, out, key, keysize, iv);
+}
+
+/*******************
+ * AES - CCM
+ *******************/
+// out_len = payload_len + assoc_len
+bool aes_encrypt_ccm(const uint8_t payload[], uint32_t payload_len, const uint8_t assoc[], unsigned short assoc_len,
+ const uint8_t nonce[], unsigned short nonce_len, uint8_t out[], uint32_t* out_len,
+ uint32_t mac_len, const uint8_t key_str[], int keysize)
+{
+ uint8_t temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], *buf;
+ int end_of_buf, payload_len_store_size;
+ uint32_t key[60];
+
+ if (mac_len != 4 && mac_len != 6 && mac_len != 8 && mac_len != 10 && mac_len != 12 && mac_len != 14 && mac_len != 16)
+ return false;
+
+ if (nonce_len < 7 || nonce_len > 13)
+ return false;
+
+ if (assoc_len > 32768 /* = 2^15 */)
+ return false;
+
+ buf = (uint8_t*)malloc(payload_len + assoc_len +
+ 48 /*Round both payload and associated data up a block size and add an extra block.*/);
+ if (!buf)
+ return false;
+
+ // Prepare the key for usage.
+ aes_key_setup(key_str, key, keysize);
+
+ // Format the first block of the formatted data.
+ payload_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ ccm_prepare_first_format_blk(buf, assoc_len, payload_len, payload_len_store_size, mac_len, nonce, nonce_len);
+ end_of_buf = AES_BLOCK_SIZE;
+
+ // Format the Associated Data, aka, assoc[].
+ ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len);
+
+ // Format the Payload, aka payload[].
+ ccm_format_payload_data(buf, &end_of_buf, payload, payload_len);
+
+ // Create the first counter block.
+ ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, payload_len_store_size);
+
+ // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC.
+ std::memset(temp_iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_cbc_mac(buf, end_of_buf, mac, key, keysize, temp_iv);
+
+ // Copy the Payload and MAC to the output buffer.
+ std::memcpy(out, payload, payload_len);
+ std::memcpy(&out[payload_len], mac, mac_len);
+
+ // Encrypt the Payload with CTR mode with a counter starting at 1.
+ std::memcpy(temp_iv, counter, AES_BLOCK_SIZE);
+ aes_increment_iv(temp_iv,
+ AES_BLOCK_SIZE - 1 -
+ mac_len); // Last argument is the byte size of the counting portion of the counter block. /*BUG?*/
+ aes_encrypt_ctr(out, payload_len, out, key, keysize, temp_iv);
+
+ // Encrypt the MAC with CTR mode with a counter starting at 0.
+ aes_encrypt_ctr(&out[payload_len], mac_len, &out[payload_len], key, keysize, counter);
+
+ free(buf);
+ *out_len = payload_len + mac_len;
+
+ return true;
+}
+
+// plaintext_len = ciphertext_len - mac_len
+// Needs a flag for whether the MAC matches.
+bool aes_decrypt_ccm(const uint8_t ciphertext[], uint32_t ciphertext_len, const uint8_t assoc[],
+ unsigned short assoc_len, const uint8_t nonce[], unsigned short nonce_len, uint8_t plaintext[],
+ uint32_t* plaintext_len, uint32_t mac_len, int* mac_auth, const uint8_t key_str[], int keysize)
+{
+ uint8_t temp_iv[AES_BLOCK_SIZE], counter[AES_BLOCK_SIZE], mac[16], mac_buf[16], *buf;
+ int end_of_buf, plaintext_len_store_size;
+ uint32_t key[60];
+
+ if (ciphertext_len <= mac_len)
+ return false;
+
+ buf = (uint8_t*)malloc(assoc_len + ciphertext_len /*ciphertext_len = plaintext_len + mac_len*/ + 48);
+ if (!buf)
+ return false;
+
+ // Prepare the key for usage.
+ aes_key_setup(key_str, key, keysize);
+
+ // Copy the plaintext and MAC to the output buffers.
+ *plaintext_len = ciphertext_len - mac_len;
+ plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ std::memcpy(plaintext, ciphertext, *plaintext_len);
+ std::memcpy(mac, &ciphertext[*plaintext_len], mac_len);
+
+ // Prepare the first counter block for use in decryption.
+ ccm_prepare_first_ctr_blk(counter, nonce, nonce_len, plaintext_len_store_size);
+
+ // Decrypt the Payload with CTR mode with a counter starting at 1.
+ std::memcpy(temp_iv, counter, AES_BLOCK_SIZE);
+ aes_increment_iv(
+ temp_iv,
+ AES_BLOCK_SIZE - 1 -
+ mac_len); // (AES_BLOCK_SIZE - 1 - mac_len) is the byte size of the counting portion of the counter block.
+ aes_decrypt_ctr(plaintext, *plaintext_len, plaintext, key, keysize, temp_iv);
+
+ // Setting mac_auth to NULL disables the authentication check.
+ if (mac_auth != NULL)
+ {
+ // Decrypt the MAC with CTR mode with a counter starting at 0.
+ aes_decrypt_ctr(mac, mac_len, mac, key, keysize, counter);
+
+ // Format the first block of the formatted data.
+ plaintext_len_store_size = AES_BLOCK_SIZE - 1 - nonce_len;
+ ccm_prepare_first_format_blk(buf, assoc_len, *plaintext_len, plaintext_len_store_size, mac_len, nonce, nonce_len);
+ end_of_buf = AES_BLOCK_SIZE;
+
+ // Format the Associated Data into the authentication buffer.
+ ccm_format_assoc_data(buf, &end_of_buf, assoc, assoc_len);
+
+ // Format the Payload into the authentication buffer.
+ ccm_format_payload_data(buf, &end_of_buf, plaintext, *plaintext_len);
+
+ // Perform the CBC operation with an IV of zeros on the formatted buffer to calculate the MAC.
+ std::memset(temp_iv, 0, AES_BLOCK_SIZE);
+ aes_encrypt_cbc_mac(buf, end_of_buf, mac_buf, key, keysize, temp_iv);
+
+ // Compare the calculated MAC against the MAC embedded in the ciphertext to see if they are the same.
+ if (!memcmp(mac, mac_buf, mac_len))
+ {
+ *mac_auth = true;
+ }
+ else
+ {
+ *mac_auth = false;
+ std::memset(plaintext, 0, *plaintext_len);
+ }
+ }
+
+ free(buf);
+
+ return true;
+}
+
+// Creates the first counter block. First byte is flags, then the nonce, then the incremented part.
+void ccm_prepare_first_ctr_blk(uint8_t counter[], const uint8_t nonce[], int nonce_len, int payload_len_store_size)
+{
+ std::memset(counter, 0, AES_BLOCK_SIZE);
+ counter[0] = (payload_len_store_size - 1) & 0x07;
+ std::memcpy(&counter[1], nonce, nonce_len);
+}
+
+void ccm_prepare_first_format_blk(uint8_t buf[], int assoc_len, int payload_len, int payload_len_store_size,
+ int mac_len, const uint8_t nonce[], int nonce_len)
+{
+ // Set the flags for the first byte of the first block.
+ buf[0] = ((((mac_len - 2) / 2) & 0x07) << 3) | ((payload_len_store_size - 1) & 0x07);
+ if (assoc_len > 0)
+ buf[0] += 0x40;
+ // Format the rest of the first block, storing the nonce and the size of the payload.
+ std::memcpy(&buf[1], nonce, nonce_len);
+ std::memset(&buf[1 + nonce_len], 0, AES_BLOCK_SIZE - 1 - nonce_len);
+ buf[15] = payload_len & 0x000000FF;
+ buf[14] = (payload_len >> 8) & 0x000000FF;
+}
+
+void ccm_format_assoc_data(uint8_t buf[], int* end_of_buf, const uint8_t assoc[], int assoc_len)
+{
+ int pad;
+
+ buf[*end_of_buf + 1] = assoc_len & 0x00FF;
+ buf[*end_of_buf] = (assoc_len >> 8) & 0x00FF;
+ *end_of_buf += 2;
+ std::memcpy(&buf[*end_of_buf], assoc, assoc_len);
+ *end_of_buf += assoc_len;
+ pad = AES_BLOCK_SIZE - (*end_of_buf % AES_BLOCK_SIZE); /*BUG?*/
+ std::memset(&buf[*end_of_buf], 0, pad);
+ *end_of_buf += pad;
+}
+
+void ccm_format_payload_data(uint8_t buf[], int* end_of_buf, const uint8_t payload[], int payload_len)
+{
+ int pad;
+
+ std::memcpy(&buf[*end_of_buf], payload, payload_len);
+ *end_of_buf += payload_len;
+ pad = *end_of_buf % AES_BLOCK_SIZE;
+ if (pad != 0)
+ pad = AES_BLOCK_SIZE - pad;
+ std::memset(&buf[*end_of_buf], 0, pad);
+ *end_of_buf += pad;
+}
+#endif
+
+/*******************
+ * AES
+ *******************/
+/////////////////
+// KEY EXPANSION
+/////////////////
+
+// Substitutes a word using the AES S-Box.
+static uint32_t SubWord(uint32_t word)
+{
+ unsigned int result;
+
+ result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F];
+ result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8;
+ result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16;
+ result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24;
+ return (result);
+}
+
+// Performs the action of generating the keys that will be used in every round of
+// encryption. "key" is the user-supplied input key, "w" is the output key schedule,
+// "keysize" is the length in bits of "key", must be 128, 192, or 256.
+void aes_key_setup(const uint8_t key[], uint32_t w[], int keysize)
+{
+ int Nb = 4, Nr, Nk, idx;
+ uint32_t temp,
+ Rcon[] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000,
+ 0x1b000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000};
+
+ switch (keysize)
+ {
+ case 128:
+ Nr = 10;
+ Nk = 4;
+ break;
+ case 192:
+ Nr = 12;
+ Nk = 6;
+ break;
+ case 256:
+ Nr = 14;
+ Nk = 8;
+ break;
+ default:
+ return;
+ }
+
+ for (idx = 0; idx < Nk; ++idx)
+ {
+ w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) | ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3]));
+ }
+
+ for (idx = Nk; idx < Nb * (Nr + 1); ++idx)
+ {
+ temp = w[idx - 1];
+ if ((idx % Nk) == 0)
+ temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx - 1) / Nk];
+ else if (Nk > 6 && (idx % Nk) == 4)
+ temp = SubWord(temp);
+ w[idx] = w[idx - Nk] ^ temp;
+ }
+}
+
+/////////////////
+// ADD ROUND KEY
+/////////////////
+
+// Performs the AddRoundKey step. Each round has its own pre-generated 16-byte key in the
+// form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state.
+// Also performs the job of InvAddRoundKey(); since the function is a simple XOR process,
+// it is its own inverse.
+static void AddRoundKey(uint8_t state[][4], const uint32_t w[])
+{
+ uint8_t subkey[4];
+
+ // std::memcpy(subkey,&w[idx],4); // Not accurate for big endian machines
+ // Subkey 1
+ subkey[0] = static_cast(w[0] >> 24);
+ subkey[1] = static_cast(w[0] >> 16);
+ subkey[2] = static_cast(w[0] >> 8);
+ subkey[3] = static_cast(w[0]);
+ state[0][0] ^= subkey[0];
+ state[1][0] ^= subkey[1];
+ state[2][0] ^= subkey[2];
+ state[3][0] ^= subkey[3];
+ // Subkey 2
+ subkey[0] = static_cast(w[1] >> 24);
+ subkey[1] = static_cast(w[1] >> 16);
+ subkey[2] = static_cast(w[1] >> 8);
+ subkey[3] = static_cast(w[1]);
+ state[0][1] ^= subkey[0];
+ state[1][1] ^= subkey[1];
+ state[2][1] ^= subkey[2];
+ state[3][1] ^= subkey[3];
+ // Subkey 3
+ subkey[0] = static_cast(w[2] >> 24);
+ subkey[1] = static_cast(w[2] >> 16);
+ subkey[2] = static_cast(w[2] >> 8);
+ subkey[3] = static_cast(w[2]);
+ state[0][2] ^= subkey[0];
+ state[1][2] ^= subkey[1];
+ state[2][2] ^= subkey[2];
+ state[3][2] ^= subkey[3];
+ // Subkey 4
+ subkey[0] = static_cast(w[3] >> 24);
+ subkey[1] = static_cast(w[3] >> 16);
+ subkey[2] = static_cast(w[3] >> 8);
+ subkey[3] = static_cast(w[3]);
+ state[0][3] ^= subkey[0];
+ state[1][3] ^= subkey[1];
+ state[2][3] ^= subkey[2];
+ state[3][3] ^= subkey[3];
+}
+
+/////////////////
+// (Inv)SubBytes
+/////////////////
+
+// Performs the SubBytes step. All bytes in the state are substituted with a
+// pre-calculated value from a lookup table.
+static void SubBytes(uint8_t state[][4])
+{
+ state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F];
+ state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F];
+ state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F];
+ state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F];
+ state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F];
+ state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F];
+ state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F];
+ state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F];
+ state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F];
+ state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F];
+ state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F];
+ state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F];
+ state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F];
+ state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F];
+ state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F];
+ state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F];
+}
+
+static void InvSubBytes(uint8_t state[][4])
+{
+ state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F];
+ state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F];
+ state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F];
+ state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F];
+ state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F];
+ state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F];
+ state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F];
+ state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F];
+ state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F];
+ state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F];
+ state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F];
+ state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F];
+ state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F];
+ state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F];
+ state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F];
+ state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F];
+}
+
+/////////////////
+// (Inv)ShiftRows
+/////////////////
+
+// Performs the ShiftRows step. All rows are shifted cylindrically to the left.
+static void ShiftRows(uint8_t state[][4])
+{
+ int t;
+
+ // Shift left by 1
+ t = state[1][0];
+ state[1][0] = state[1][1];
+ state[1][1] = state[1][2];
+ state[1][2] = state[1][3];
+ state[1][3] = static_cast(t);
+ // Shift left by 2
+ t = state[2][0];
+ state[2][0] = state[2][2];
+ state[2][2] = static_cast(t);
+ t = state[2][1];
+ state[2][1] = state[2][3];
+ state[2][3] = static_cast(t);
+ // Shift left by 3
+ t = state[3][0];
+ state[3][0] = state[3][3];
+ state[3][3] = state[3][2];
+ state[3][2] = state[3][1];
+ state[3][1] = static_cast(t);
+}
+
+// All rows are shifted cylindrically to the right.
+static void InvShiftRows(uint8_t state[][4])
+{
+ int t;
+
+ // Shift right by 1
+ t = state[1][3];
+ state[1][3] = state[1][2];
+ state[1][2] = state[1][1];
+ state[1][1] = state[1][0];
+ state[1][0] = static_cast(t);
+ // Shift right by 2
+ t = state[2][3];
+ state[2][3] = state[2][1];
+ state[2][1] = static_cast(t);
+ t = state[2][2];
+ state[2][2] = state[2][0];
+ state[2][0] = static_cast(t);
+ // Shift right by 3
+ t = state[3][3];
+ state[3][3] = state[3][0];
+ state[3][0] = state[3][1];
+ state[3][1] = state[3][2];
+ state[3][2] = static_cast(t);
+}
+
+/////////////////
+// (Inv)MixColumns
+/////////////////
+
+// Performs the MixColums step. The state is multiplied by itself using matrix
+// multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table.
+// Addition is equivilent to XOR. (Must always make a copy of the column as the original
+// values will be destoyed.)
+static void MixColumns(uint8_t state[][4])
+{
+ uint8_t col[4];
+
+ // Column 1
+ col[0] = state[0][0];
+ col[1] = state[1][0];
+ col[2] = state[2][0];
+ col[3] = state[3][0];
+ state[0][0] = gf_mul[col[0]][0];
+ state[0][0] ^= gf_mul[col[1]][1];
+ state[0][0] ^= col[2];
+ state[0][0] ^= col[3];
+ state[1][0] = col[0];
+ state[1][0] ^= gf_mul[col[1]][0];
+ state[1][0] ^= gf_mul[col[2]][1];
+ state[1][0] ^= col[3];
+ state[2][0] = col[0];
+ state[2][0] ^= col[1];
+ state[2][0] ^= gf_mul[col[2]][0];
+ state[2][0] ^= gf_mul[col[3]][1];
+ state[3][0] = gf_mul[col[0]][1];
+ state[3][0] ^= col[1];
+ state[3][0] ^= col[2];
+ state[3][0] ^= gf_mul[col[3]][0];
+ // Column 2
+ col[0] = state[0][1];
+ col[1] = state[1][1];
+ col[2] = state[2][1];
+ col[3] = state[3][1];
+ state[0][1] = gf_mul[col[0]][0];
+ state[0][1] ^= gf_mul[col[1]][1];
+ state[0][1] ^= col[2];
+ state[0][1] ^= col[3];
+ state[1][1] = col[0];
+ state[1][1] ^= gf_mul[col[1]][0];
+ state[1][1] ^= gf_mul[col[2]][1];
+ state[1][1] ^= col[3];
+ state[2][1] = col[0];
+ state[2][1] ^= col[1];
+ state[2][1] ^= gf_mul[col[2]][0];
+ state[2][1] ^= gf_mul[col[3]][1];
+ state[3][1] = gf_mul[col[0]][1];
+ state[3][1] ^= col[1];
+ state[3][1] ^= col[2];
+ state[3][1] ^= gf_mul[col[3]][0];
+ // Column 3
+ col[0] = state[0][2];
+ col[1] = state[1][2];
+ col[2] = state[2][2];
+ col[3] = state[3][2];
+ state[0][2] = gf_mul[col[0]][0];
+ state[0][2] ^= gf_mul[col[1]][1];
+ state[0][2] ^= col[2];
+ state[0][2] ^= col[3];
+ state[1][2] = col[0];
+ state[1][2] ^= gf_mul[col[1]][0];
+ state[1][2] ^= gf_mul[col[2]][1];
+ state[1][2] ^= col[3];
+ state[2][2] = col[0];
+ state[2][2] ^= col[1];
+ state[2][2] ^= gf_mul[col[2]][0];
+ state[2][2] ^= gf_mul[col[3]][1];
+ state[3][2] = gf_mul[col[0]][1];
+ state[3][2] ^= col[1];
+ state[3][2] ^= col[2];
+ state[3][2] ^= gf_mul[col[3]][0];
+ // Column 4
+ col[0] = state[0][3];
+ col[1] = state[1][3];
+ col[2] = state[2][3];
+ col[3] = state[3][3];
+ state[0][3] = gf_mul[col[0]][0];
+ state[0][3] ^= gf_mul[col[1]][1];
+ state[0][3] ^= col[2];
+ state[0][3] ^= col[3];
+ state[1][3] = col[0];
+ state[1][3] ^= gf_mul[col[1]][0];
+ state[1][3] ^= gf_mul[col[2]][1];
+ state[1][3] ^= col[3];
+ state[2][3] = col[0];
+ state[2][3] ^= col[1];
+ state[2][3] ^= gf_mul[col[2]][0];
+ state[2][3] ^= gf_mul[col[3]][1];
+ state[3][3] = gf_mul[col[0]][1];
+ state[3][3] ^= col[1];
+ state[3][3] ^= col[2];
+ state[3][3] ^= gf_mul[col[3]][0];
+}
+
+static void InvMixColumns(uint8_t state[][4])
+{
+ uint8_t col[4];
+
+ // Column 1
+ col[0] = state[0][0];
+ col[1] = state[1][0];
+ col[2] = state[2][0];
+ col[3] = state[3][0];
+ state[0][0] = gf_mul[col[0]][5];
+ state[0][0] ^= gf_mul[col[1]][3];
+ state[0][0] ^= gf_mul[col[2]][4];
+ state[0][0] ^= gf_mul[col[3]][2];
+ state[1][0] = gf_mul[col[0]][2];
+ state[1][0] ^= gf_mul[col[1]][5];
+ state[1][0] ^= gf_mul[col[2]][3];
+ state[1][0] ^= gf_mul[col[3]][4];
+ state[2][0] = gf_mul[col[0]][4];
+ state[2][0] ^= gf_mul[col[1]][2];
+ state[2][0] ^= gf_mul[col[2]][5];
+ state[2][0] ^= gf_mul[col[3]][3];
+ state[3][0] = gf_mul[col[0]][3];
+ state[3][0] ^= gf_mul[col[1]][4];
+ state[3][0] ^= gf_mul[col[2]][2];
+ state[3][0] ^= gf_mul[col[3]][5];
+ // Column 2
+ col[0] = state[0][1];
+ col[1] = state[1][1];
+ col[2] = state[2][1];
+ col[3] = state[3][1];
+ state[0][1] = gf_mul[col[0]][5];
+ state[0][1] ^= gf_mul[col[1]][3];
+ state[0][1] ^= gf_mul[col[2]][4];
+ state[0][1] ^= gf_mul[col[3]][2];
+ state[1][1] = gf_mul[col[0]][2];
+ state[1][1] ^= gf_mul[col[1]][5];
+ state[1][1] ^= gf_mul[col[2]][3];
+ state[1][1] ^= gf_mul[col[3]][4];
+ state[2][1] = gf_mul[col[0]][4];
+ state[2][1] ^= gf_mul[col[1]][2];
+ state[2][1] ^= gf_mul[col[2]][5];
+ state[2][1] ^= gf_mul[col[3]][3];
+ state[3][1] = gf_mul[col[0]][3];
+ state[3][1] ^= gf_mul[col[1]][4];
+ state[3][1] ^= gf_mul[col[2]][2];
+ state[3][1] ^= gf_mul[col[3]][5];
+ // Column 3
+ col[0] = state[0][2];
+ col[1] = state[1][2];
+ col[2] = state[2][2];
+ col[3] = state[3][2];
+ state[0][2] = gf_mul[col[0]][5];
+ state[0][2] ^= gf_mul[col[1]][3];
+ state[0][2] ^= gf_mul[col[2]][4];
+ state[0][2] ^= gf_mul[col[3]][2];
+ state[1][2] = gf_mul[col[0]][2];
+ state[1][2] ^= gf_mul[col[1]][5];
+ state[1][2] ^= gf_mul[col[2]][3];
+ state[1][2] ^= gf_mul[col[3]][4];
+ state[2][2] = gf_mul[col[0]][4];
+ state[2][2] ^= gf_mul[col[1]][2];
+ state[2][2] ^= gf_mul[col[2]][5];
+ state[2][2] ^= gf_mul[col[3]][3];
+ state[3][2] = gf_mul[col[0]][3];
+ state[3][2] ^= gf_mul[col[1]][4];
+ state[3][2] ^= gf_mul[col[2]][2];
+ state[3][2] ^= gf_mul[col[3]][5];
+ // Column 4
+ col[0] = state[0][3];
+ col[1] = state[1][3];
+ col[2] = state[2][3];
+ col[3] = state[3][3];
+ state[0][3] = gf_mul[col[0]][5];
+ state[0][3] ^= gf_mul[col[1]][3];
+ state[0][3] ^= gf_mul[col[2]][4];
+ state[0][3] ^= gf_mul[col[3]][2];
+ state[1][3] = gf_mul[col[0]][2];
+ state[1][3] ^= gf_mul[col[1]][5];
+ state[1][3] ^= gf_mul[col[2]][3];
+ state[1][3] ^= gf_mul[col[3]][4];
+ state[2][3] = gf_mul[col[0]][4];
+ state[2][3] ^= gf_mul[col[1]][2];
+ state[2][3] ^= gf_mul[col[2]][5];
+ state[2][3] ^= gf_mul[col[3]][3];
+ state[3][3] = gf_mul[col[0]][3];
+ state[3][3] ^= gf_mul[col[1]][4];
+ state[3][3] ^= gf_mul[col[2]][2];
+ state[3][3] ^= gf_mul[col[3]][5];
+}
+
+/////////////////
+// (En/De)Crypt
+/////////////////
+
+void aes_encrypt(const uint8_t in[], uint8_t out[], const uint32_t key[], int keysize)
+{
+ uint8_t state[4][4];
+
+ // Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered
+ // by row, not col) called "state" for processing.
+ // *** Implementation note: The official AES documentation references the state by
+ // column, then row. Accessing an element in C requires row then column. Thus, all state
+ // references in AES must have the column and row indexes reversed for C implementation.
+ state[0][0] = in[0];
+ state[1][0] = in[1];
+ state[2][0] = in[2];
+ state[3][0] = in[3];
+ state[0][1] = in[4];
+ state[1][1] = in[5];
+ state[2][1] = in[6];
+ state[3][1] = in[7];
+ state[0][2] = in[8];
+ state[1][2] = in[9];
+ state[2][2] = in[10];
+ state[3][2] = in[11];
+ state[0][3] = in[12];
+ state[1][3] = in[13];
+ state[2][3] = in[14];
+ state[3][3] = in[15];
+
+ // Perform the necessary number of rounds. The round key is added first.
+ // The last round does not perform the MixColumns step.
+ AddRoundKey(state, &key[0]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[4]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[8]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[12]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[16]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[20]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[24]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[28]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[32]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[36]);
+ if (keysize != 128)
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[40]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[44]);
+ if (keysize != 192)
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[48]);
+ SubBytes(state);
+ ShiftRows(state);
+ MixColumns(state);
+ AddRoundKey(state, &key[52]);
+ SubBytes(state);
+ ShiftRows(state);
+ AddRoundKey(state, &key[56]);
+ }
+ else
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ AddRoundKey(state, &key[48]);
+ }
+ }
+ else
+ {
+ SubBytes(state);
+ ShiftRows(state);
+ AddRoundKey(state, &key[40]);
+ }
+
+ // Copy the state to the output array.
+ out[0] = state[0][0];
+ out[1] = state[1][0];
+ out[2] = state[2][0];
+ out[3] = state[3][0];
+ out[4] = state[0][1];
+ out[5] = state[1][1];
+ out[6] = state[2][1];
+ out[7] = state[3][1];
+ out[8] = state[0][2];
+ out[9] = state[1][2];
+ out[10] = state[2][2];
+ out[11] = state[3][2];
+ out[12] = state[0][3];
+ out[13] = state[1][3];
+ out[14] = state[2][3];
+ out[15] = state[3][3];
+}
+
+void aes_decrypt(const uint8_t in[], uint8_t out[], const uint32_t key[], int keysize)
+{
+ uint8_t state[4][4];
+
+ // Copy the input to the state.
+ state[0][0] = in[0];
+ state[1][0] = in[1];
+ state[2][0] = in[2];
+ state[3][0] = in[3];
+ state[0][1] = in[4];
+ state[1][1] = in[5];
+ state[2][1] = in[6];
+ state[3][1] = in[7];
+ state[0][2] = in[8];
+ state[1][2] = in[9];
+ state[2][2] = in[10];
+ state[3][2] = in[11];
+ state[0][3] = in[12];
+ state[1][3] = in[13];
+ state[2][3] = in[14];
+ state[3][3] = in[15];
+
+ // Perform the necessary number of rounds. The round key is added first.
+ // The last round does not perform the MixColumns step.
+ if (keysize > 128)
+ {
+ if (keysize > 192)
+ {
+ AddRoundKey(state, &key[56]);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[52]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[48]);
+ InvMixColumns(state);
+ }
+ else
+ {
+ AddRoundKey(state, &key[48]);
+ }
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[44]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[40]);
+ InvMixColumns(state);
+ }
+ else
+ {
+ AddRoundKey(state, &key[40]);
+ }
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[36]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[32]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[28]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[24]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[20]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[16]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[12]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[8]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[4]);
+ InvMixColumns(state);
+ InvShiftRows(state);
+ InvSubBytes(state);
+ AddRoundKey(state, &key[0]);
+
+ // Copy the state to the output array.
+ out[0] = state[0][0];
+ out[1] = state[1][0];
+ out[2] = state[2][0];
+ out[3] = state[3][0];
+ out[4] = state[0][1];
+ out[5] = state[1][1];
+ out[6] = state[2][1];
+ out[7] = state[3][1];
+ out[8] = state[0][2];
+ out[9] = state[1][2];
+ out[10] = state[2][2];
+ out[11] = state[3][2];
+ out[12] = state[0][3];
+ out[13] = state[1][3];
+ out[14] = state[2][3];
+ out[15] = state[3][3];
+}
+
+/*******************
+** AES DEBUGGING FUNCTIONS
+*******************/
+/*
+// This prints the "state" grid as a linear hex string.
+void print_state(BYTE state[][4])
+{
+ int idx,idx2;
+
+ for (idx=0; idx < 4; idx++)
+ for (idx2=0; idx2 < 4; idx2++)
+ printf("%02x",state[idx2][idx]);
+ printf("\n");
+}
+
+// This prints the key (4 consecutive ints) used for a given round as a linear hex string.
+void print_rnd_key(WORD key[])
+{
+ int idx;
+
+ for (idx=0; idx < 4; idx++)
+ printf("%08x",key[idx]);
+ printf("\n");
+}
+*/
diff --git a/src/common/thirdparty/aes.h b/src/common/thirdparty/aes.h
new file mode 100644
index 000000000..ab24e0aee
--- /dev/null
+++ b/src/common/thirdparty/aes.h
@@ -0,0 +1,122 @@
+/*********************************************************************
+ * Filename: aes.h
+ * Author: Brad Conte (brad AT bradconte.com)
+ * Copyright:
+ * Disclaimer: This code is presented "as is" without any guarantees.
+ * Details: Defines the API for the corresponding AES implementation.
+ *********************************************************************/
+
+#pragma once
+
+/*************************** HEADER FILES ***************************/
+#include
+#include
+
+/****************************** MACROS ******************************/
+static constexpr uint32_t AES_BLOCK_SIZE = 16; // AES operates on 16 bytes at a time
+static constexpr uint32_t AES_KEY_SCHEDULE_SIZE = 60;
+
+/*********************** FUNCTION DECLARATIONS **********************/
+///////////////////
+// AES
+///////////////////
+// Key setup must be done before any AES en/de-cryption functions can be used.
+void aes_key_setup(const uint8_t key[], // The key, must be 128, 192, or 256 bits
+ uint32_t w[], // Output key schedule to be used later
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+void aes_encrypt(const uint8_t in[], // 16 bytes of plaintext
+ uint8_t out[], // 16 bytes of ciphertext
+ const uint32_t key[], // From the key setup
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+void aes_decrypt(const uint8_t in[], // 16 bytes of ciphertext
+ uint8_t out[], // 16 bytes of plaintext
+ const uint32_t key[], // From the key setup
+ int keysize); // Bit length of the key, 128, 192, or 256
+
+///////////////////
+// AES - CBC
+///////////////////
+bool aes_encrypt_cbc(const uint8_t in[], // Plaintext
+ size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
+ uint8_t out[], // Ciphertext, same length as plaintext
+ const uint32_t key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+bool aes_decrypt_cbc(const uint8_t in[], // Ciphertext
+ size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
+ uint8_t out[], // Plaintext, same length as ciphertext
+ const uint32_t key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+#if 0
+// Disabled since it's not being used.
+// Only output the CBC-MAC of the input.
+bool aes_encrypt_cbc_mac(const uint8_t in[], // plaintext
+ size_t in_len, // Must be a multiple of AES_BLOCK_SIZE
+ uint8_t out[], // Output MAC
+ const uint32_t key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+///////////////////
+// AES - CTR
+///////////////////
+void aes_increment_iv(uint8_t iv[], // Must be a multiple of AES_BLOCK_SIZE
+ int counter_size); // Bytes of the IV used for counting (low end)
+
+void aes_encrypt_ctr(const uint8_t in[], // Plaintext
+ size_t in_len, // Any byte length
+ uint8_t out[], // Ciphertext, same length as plaintext
+ const uint32_t key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+void aes_decrypt_ctr(const uint8_t in[], // Ciphertext
+ size_t in_len, // Any byte length
+ uint8_t out[], // Plaintext, same length as ciphertext
+ const uint32_t key[], // From the key setup
+ int keysize, // Bit length of the key, 128, 192, or 256
+ const uint8_t iv[]); // IV, must be AES_BLOCK_SIZE bytes long
+
+///////////////////
+// AES - CCM
+///////////////////
+// Returns True if the input parameters do not violate any constraint.
+bool aes_encrypt_ccm(
+ const uint8_t plaintext[], // IN - Plaintext.
+ uint32_t plaintext_len, // IN - Plaintext length.
+ const uint8_t associated_data[], // IN - Associated Data included in authentication, but not encryption.
+ unsigned short associated_data_len, // IN - Associated Data length in bytes.
+ const uint8_t nonce[], // IN - The Nonce to be used for encryption.
+ unsigned short nonce_len, // IN - Nonce length in bytes.
+ uint8_t ciphertext[], // OUT - Ciphertext, a concatination of the plaintext and the MAC.
+ uint32_t* ciphertext_len, // OUT - The length of the ciphertext, always plaintext_len + mac_len.
+ uint32_t mac_len, // IN - The desired length of the MAC, must be 4, 6, 8, 10, 12, 14, or 16.
+ const uint8_t key[], // IN - The AES key for encryption.
+ int keysize); // IN - The length of the key in bits. Valid values are 128, 192, 256.
+
+// Returns True if the input parameters do not violate any constraint.
+// Use mac_auth to ensure decryption/validation was preformed correctly.
+// If authentication does not succeed, the plaintext is zeroed out. To overwride
+// this, call with mac_auth = NULL. The proper proceedure is to decrypt with
+// authentication enabled (mac_auth != NULL) and make a second call to that
+// ignores authentication explicitly if the first call failes.
+bool aes_decrypt_ccm(
+ const uint8_t ciphertext[], // IN - Ciphertext, the concatination of encrypted plaintext and MAC.
+ uint32_t ciphertext_len, // IN - Ciphertext length in bytes.
+ const uint8_t assoc[], // IN - The Associated Data, required for authentication.
+ unsigned short assoc_len, // IN - Associated Data length in bytes.
+ const uint8_t nonce[], // IN - The Nonce to use for decryption, same one as for encryption.
+ unsigned short nonce_len, // IN - Nonce length in bytes.
+ uint8_t plaintext[], // OUT - The plaintext that was decrypted. Will need to be large enough to hold ciphertext_len -
+ // mac_len.
+ uint32_t* plaintext_len, // OUT - Length in bytes of the output plaintext, always ciphertext_len - mac_len .
+ uint32_t mac_len, // IN - The length of the MAC that was calculated.
+ int* mac_auth, // OUT - TRUE if authentication succeeded, FALSE if it did not. NULL pointer will ignore the
+ // authentication.
+ const uint8_t key[], // IN - The AES key for decryption.
+ int keysize); // IN - The length of the key in BITS. Valid values are 128, 192, 256.
+#endif
\ No newline at end of file