#ifndef ALCRYPTOLIB_STREAM_CIPHER_CIPHER_AES_BASE_2020_01_29_H #define ALCRYPTOLIB_STREAM_CIPHER_CIPHER_AES_BASE_2020_01_29_H #include #include #include #include #if(__cplusplus >= 201703L) namespace al::crypto::stream::cipher { #else namespace al { namespace crypto { namespace stream { namespace cipher { #endif template class cipher_aes_base : public al::crypto::stream::cipher::cipher_base { private: using base_class_type = al::crypto::stream::cipher::cipher_base; static constexpr auto sbox() -> std::array, 16U> { return {{ {{ 0x63U, 0x7CU, 0x77U, 0x7BU, 0xF2U, 0x6BU, 0x6FU, 0xC5U, 0x30U, 0x01U, 0x67U, 0x2BU, 0xFEU, 0xD7U, 0xABU, 0x76U }}, {{ 0xCAU, 0x82U, 0xC9U, 0x7DU, 0xFAU, 0x59U, 0x47U, 0xF0U, 0xADU, 0xD4U, 0xA2U, 0xAFU, 0x9CU, 0xA4U, 0x72U, 0xC0U }}, {{ 0xB7U, 0xFDU, 0x93U, 0x26U, 0x36U, 0x3FU, 0xF7U, 0xCCU, 0x34U, 0xA5U, 0xE5U, 0xF1U, 0x71U, 0xD8U, 0x31U, 0x15U }}, {{ 0x04U, 0xC7U, 0x23U, 0xC3U, 0x18U, 0x96U, 0x05U, 0x9AU, 0x07U, 0x12U, 0x80U, 0xE2U, 0xEBU, 0x27U, 0xB2U, 0x75U }}, {{ 0x09U, 0x83U, 0x2CU, 0x1AU, 0x1BU, 0x6EU, 0x5AU, 0xA0U, 0x52U, 0x3BU, 0xD6U, 0xB3U, 0x29U, 0xE3U, 0x2FU, 0x84U }}, {{ 0x53U, 0xD1U, 0x00U, 0xEDU, 0x20U, 0xFCU, 0xB1U, 0x5BU, 0x6AU, 0xCBU, 0xBEU, 0x39U, 0x4AU, 0x4CU, 0x58U, 0xCFU }}, {{ 0xD0U, 0xEFU, 0xAAU, 0xFBU, 0x43U, 0x4DU, 0x33U, 0x85U, 0x45U, 0xF9U, 0x02U, 0x7FU, 0x50U, 0x3CU, 0x9FU, 0xA8U }}, {{ 0x51U, 0xA3U, 0x40U, 0x8FU, 0x92U, 0x9DU, 0x38U, 0xF5U, 0xBCU, 0xB6U, 0xDAU, 0x21U, 0x10U, 0xFFU, 0xF3U, 0xD2U }}, {{ 0xCDU, 0x0CU, 0x13U, 0xECU, 0x5FU, 0x97U, 0x44U, 0x17U, 0xC4U, 0xA7U, 0x7EU, 0x3DU, 0x64U, 0x5DU, 0x19U, 0x73U }}, {{ 0x60U, 0x81U, 0x4FU, 0xDCU, 0x22U, 0x2AU, 0x90U, 0x88U, 0x46U, 0xEEU, 0xB8U, 0x14U, 0xDEU, 0x5EU, 0x0BU, 0xDBU }}, {{ 0xE0U, 0x32U, 0x3AU, 0x0AU, 0x49U, 0x06U, 0x24U, 0x5CU, 0xC2U, 0xD3U, 0xACU, 0x62U, 0x91U, 0x95U, 0xE4U, 0x79U }}, {{ 0xE7U, 0xC8U, 0x37U, 0x6DU, 0x8DU, 0xD5U, 0x4EU, 0xA9U, 0x6CU, 0x56U, 0xF4U, 0xEAU, 0x65U, 0x7AU, 0xAEU, 0x08U }}, {{ 0xBAU, 0x78U, 0x25U, 0x2EU, 0x1CU, 0xA6U, 0xB4U, 0xC6U, 0xE8U, 0xDDU, 0x74U, 0x1FU, 0x4BU, 0xBDU, 0x8BU, 0x8AU }}, {{ 0x70U, 0x3EU, 0xB5U, 0x66U, 0x48U, 0x03U, 0xF6U, 0x0EU, 0x61U, 0x35U, 0x57U, 0xB9U, 0x86U, 0xC1U, 0x1DU, 0x9EU }}, {{ 0xE1U, 0xF8U, 0x98U, 0x11U, 0x69U, 0xD9U, 0x8EU, 0x94U, 0x9BU, 0x1EU, 0x87U, 0xE9U, 0xCEU, 0x55U, 0x28U, 0xDFU }}, {{ 0x8CU, 0xA1U, 0x89U, 0x0DU, 0xBFU, 0xE6U, 0x42U, 0x68U, 0x41U, 0x99U, 0x2DU, 0x0FU, 0xB0U, 0x54U, 0xBBU, 0x16U }} }}; } static constexpr auto inv_sbox() -> std::array, 16U> { return {{ {{ UINT8_C(0x52), UINT8_C(0x09), UINT8_C(0x6A), UINT8_C(0xD5), UINT8_C(0x30), UINT8_C(0x36), UINT8_C(0xA5), UINT8_C(0x38), UINT8_C(0xBF), UINT8_C(0x40), UINT8_C(0xA3), UINT8_C(0x9E), UINT8_C(0x81), UINT8_C(0xF3), UINT8_C(0xD7), UINT8_C(0xFB) }}, {{ UINT8_C(0x7C), UINT8_C(0xE3), UINT8_C(0x39), UINT8_C(0x82), UINT8_C(0x9B), UINT8_C(0x2F), UINT8_C(0xFF), UINT8_C(0x87), UINT8_C(0x34), UINT8_C(0x8E), UINT8_C(0x43), UINT8_C(0x44), UINT8_C(0xC4), UINT8_C(0xDE), UINT8_C(0xE9), UINT8_C(0xCB) }}, {{ UINT8_C(0x54), UINT8_C(0x7B), UINT8_C(0x94), UINT8_C(0x32), UINT8_C(0xA6), UINT8_C(0xC2), UINT8_C(0x23), UINT8_C(0x3D), UINT8_C(0xEE), UINT8_C(0x4C), UINT8_C(0x95), UINT8_C(0x0B), UINT8_C(0x42), UINT8_C(0xFA), UINT8_C(0xC3), UINT8_C(0x4E) }}, {{ UINT8_C(0x08), UINT8_C(0x2E), UINT8_C(0xA1), UINT8_C(0x66), UINT8_C(0x28), UINT8_C(0xD9), UINT8_C(0x24), UINT8_C(0xB2), UINT8_C(0x76), UINT8_C(0x5B), UINT8_C(0xA2), UINT8_C(0x49), UINT8_C(0x6D), UINT8_C(0x8B), UINT8_C(0xD1), UINT8_C(0x25) }}, {{ UINT8_C(0x72), UINT8_C(0xF8), UINT8_C(0xF6), UINT8_C(0x64), UINT8_C(0x86), UINT8_C(0x68), UINT8_C(0x98), UINT8_C(0x16), UINT8_C(0xD4), UINT8_C(0xA4), UINT8_C(0x5C), UINT8_C(0xCC), UINT8_C(0x5D), UINT8_C(0x65), UINT8_C(0xB6), UINT8_C(0x92) }}, {{ UINT8_C(0x6C), UINT8_C(0x70), UINT8_C(0x48), UINT8_C(0x50), UINT8_C(0xFD), UINT8_C(0xED), UINT8_C(0xB9), UINT8_C(0xDA), UINT8_C(0x5E), UINT8_C(0x15), UINT8_C(0x46), UINT8_C(0x57), UINT8_C(0xA7), UINT8_C(0x8D), UINT8_C(0x9D), UINT8_C(0x84) }}, {{ UINT8_C(0x90), UINT8_C(0xD8), UINT8_C(0xAB), UINT8_C(0x00), UINT8_C(0x8C), UINT8_C(0xBC), UINT8_C(0xD3), UINT8_C(0x0A), UINT8_C(0xF7), UINT8_C(0xE4), UINT8_C(0x58), UINT8_C(0x05), UINT8_C(0xB8), UINT8_C(0xB3), UINT8_C(0x45), UINT8_C(0x06) }}, {{ UINT8_C(0xD0), UINT8_C(0x2C), UINT8_C(0x1E), UINT8_C(0x8F), UINT8_C(0xCA), UINT8_C(0x3F), UINT8_C(0x0F), UINT8_C(0x02), UINT8_C(0xC1), UINT8_C(0xAF), UINT8_C(0xBD), UINT8_C(0x03), UINT8_C(0x01), UINT8_C(0x13), UINT8_C(0x8A), UINT8_C(0x6B) }}, {{ UINT8_C(0x3A), UINT8_C(0x91), UINT8_C(0x11), UINT8_C(0x41), UINT8_C(0x4F), UINT8_C(0x67), UINT8_C(0xDC), UINT8_C(0xEA), UINT8_C(0x97), UINT8_C(0xF2), UINT8_C(0xCF), UINT8_C(0xCE), UINT8_C(0xF0), UINT8_C(0xB4), UINT8_C(0xE6), UINT8_C(0x73) }}, {{ UINT8_C(0x96), UINT8_C(0xAC), UINT8_C(0x74), UINT8_C(0x22), UINT8_C(0xE7), UINT8_C(0xAD), UINT8_C(0x35), UINT8_C(0x85), UINT8_C(0xE2), UINT8_C(0xF9), UINT8_C(0x37), UINT8_C(0xE8), UINT8_C(0x1C), UINT8_C(0x75), UINT8_C(0xDF), UINT8_C(0x6E) }}, {{ UINT8_C(0x47), UINT8_C(0xF1), UINT8_C(0x1A), UINT8_C(0x71), UINT8_C(0x1D), UINT8_C(0x29), UINT8_C(0xC5), UINT8_C(0x89), UINT8_C(0x6F), UINT8_C(0xB7), UINT8_C(0x62), UINT8_C(0x0E), UINT8_C(0xAA), UINT8_C(0x18), UINT8_C(0xBE), UINT8_C(0x1B) }}, {{ UINT8_C(0xFC), UINT8_C(0x56), UINT8_C(0x3E), UINT8_C(0x4B), UINT8_C(0xC6), UINT8_C(0xD2), UINT8_C(0x79), UINT8_C(0x20), UINT8_C(0x9A), UINT8_C(0xDB), UINT8_C(0xC0), UINT8_C(0xFE), UINT8_C(0x78), UINT8_C(0xCD), UINT8_C(0x5A), UINT8_C(0xF4) }}, {{ UINT8_C(0x1F), UINT8_C(0xDD), UINT8_C(0xA8), UINT8_C(0x33), UINT8_C(0x88), UINT8_C(0x07), UINT8_C(0xC7), UINT8_C(0x31), UINT8_C(0xB1), UINT8_C(0x12), UINT8_C(0x10), UINT8_C(0x59), UINT8_C(0x27), UINT8_C(0x80), UINT8_C(0xEC), UINT8_C(0x5F) }}, {{ UINT8_C(0x60), UINT8_C(0x51), UINT8_C(0x7F), UINT8_C(0xA9), UINT8_C(0x19), UINT8_C(0xB5), UINT8_C(0x4A), UINT8_C(0x0D), UINT8_C(0x2D), UINT8_C(0xE5), UINT8_C(0x7A), UINT8_C(0x9F), UINT8_C(0x93), UINT8_C(0xC9), UINT8_C(0x9C), UINT8_C(0xEF) }}, {{ UINT8_C(0xA0), UINT8_C(0xE0), UINT8_C(0x3B), UINT8_C(0x4D), UINT8_C(0xAE), UINT8_C(0x2A), UINT8_C(0xF5), UINT8_C(0xB0), UINT8_C(0xC8), UINT8_C(0xEB), UINT8_C(0xBB), UINT8_C(0x3C), UINT8_C(0x83), UINT8_C(0x53), UINT8_C(0x99), UINT8_C(0x61) }}, {{ UINT8_C(0x17), UINT8_C(0x2B), UINT8_C(0x04), UINT8_C(0x7E), UINT8_C(0xBA), UINT8_C(0x77), UINT8_C(0xD6), UINT8_C(0x26), UINT8_C(0xE1), UINT8_C(0x69), UINT8_C(0x14), UINT8_C(0x63), UINT8_C(0x55), UINT8_C(0x21), UINT8_C(0x0C), UINT8_C(0x7D) }} }}; } public: cipher_aes_base(const cipher_aes_base&) = default; cipher_aes_base(cipher_aes_base&&) noexcept = default; ~cipher_aes_base() override = default; auto operator=(const cipher_aes_base& other) -> cipher_aes_base& = default; auto operator=(cipher_aes_base&&) noexcept -> cipher_aes_base& = default; protected: static constexpr auto Nb = static_cast(4U); static constexpr auto blockBytesLen = static_cast(static_cast(4U) * (Nb * sizeof(std::uint8_t))); cipher_aes_base() = default; void SubBytes(std::uint8_t** state) { for(std::size_t i = 0U; i < 4U; ++i) { for(std::size_t j = 0U; j < Nb; ++j) { const std::uint8_t t = state[i][j]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) state[i][j] = sbox()[t / 16U][t % 16U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } } } auto ShiftRow(std::uint8_t** state, std::size_t i, std::size_t n) -> void // NOLINT(bugprone-easily-swappable-parameters) { // Shift row i on n positions. for(std::size_t k = 0U; k < n; ++k) { const std::uint8_t t = state[i][0U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(std::size_t j = 0U; j < Nb - 1U; ++j) { state[i][j] = state[i][j + 1U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } state[i][Nb - 1U] = t; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } } auto ShiftRows(std::uint8_t** state) -> void { ShiftRow(state, 1, 1); ShiftRow(state, 2, 2); ShiftRow(state, 3, 3); } auto AddRoundKey(std::uint8_t** state, const std::uint8_t* key) -> void { for(std::size_t i = 0U; i < 4U; ++i) { for(std::size_t j = 0U; j < Nb; ++j) { state[i][j] = state[i][j] ^ key[i + (4U * j)]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } } } auto MixColumns(std::uint8_t** state) -> void { std::array s { }; std::array s1 { }; for(auto j = static_cast(0U); j < Nb; ++j) { for(auto i = static_cast(0U); i < static_cast(4U); ++i) { s[i] = state[i][j]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } s1[0U] = static_cast(static_cast(mul_bytes(UINT8_C(0x02), s[0]) ^ mul_bytes(UINT8_C(0x03), s[1U])) ^ static_cast(s[2U] ^ s[3U])); s1[1U] = static_cast(static_cast(s[0U] ^ mul_bytes(UINT8_C(0x02), s[1U])) ^ static_cast(mul_bytes(UINT8_C(0x03), s[2U]) ^ s[3U])); s1[2U] = static_cast(static_cast(s[0U] ^ s[1U] ) ^ static_cast(mul_bytes(UINT8_C(0x02), s[2U]) ^ mul_bytes(UINT8_C(0x03), s[3U]))); s1[3U] = static_cast(static_cast(mul_bytes(UINT8_C(0x03), s[0]) ^ s[1U] ) ^ static_cast(s[2U] ^ mul_bytes(UINT8_C(0x02), s[3U]))); for(std::size_t i = 0U; i < 4U; ++i) { state[i][j] = s1[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } } } auto SubWord(std::uint8_t *a) -> void { for(std::size_t i = 0U; i < 4U; ++i) { a[i] = sbox()[a[i] / 16U][a[i] % 16U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } } auto InvSubBytes(std::uint8_t** state) -> void { for(std::size_t i = 0U; i < 4U; ++i) { for(std::size_t j = 0; j < Nb; ++j) { const std::uint8_t t = state[i][j]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) state[i][j] = inv_sbox()[t / 16U][t % 16U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } } } auto InvMixColumns(std::uint8_t** state) -> void { std::array s { }; std::array s1 { }; for(std::size_t j = 0U; j < Nb; ++j) { for(std::size_t i = 0U; i < 4U; ++i) { s[i] = state[i][j]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } s1[0U] = static_cast(static_cast(mul_bytes(UINT8_C(0x0E), s[0U]) ^ mul_bytes(UINT8_C(0x0B), s[1U])) ^ static_cast(mul_bytes(UINT8_C(0x0D), s[2U]) ^ mul_bytes(UINT8_C(0x09), s[3U]))); s1[1U] = static_cast(static_cast(mul_bytes(UINT8_C(0x09), s[0U]) ^ mul_bytes(UINT8_C(0x0E), s[1U])) ^ static_cast(mul_bytes(UINT8_C(0x0B), s[2U]) ^ mul_bytes(UINT8_C(0x0D), s[3U]))); s1[2U] = static_cast(static_cast(mul_bytes(UINT8_C(0x0D), s[0U]) ^ mul_bytes(UINT8_C(0x09), s[1U])) ^ static_cast(mul_bytes(UINT8_C(0x0E), s[2U]) ^ mul_bytes(UINT8_C(0x0B), s[3U]))); s1[3U] = static_cast(static_cast(mul_bytes(UINT8_C(0x0B), s[0U]) ^ mul_bytes(UINT8_C(0x0D), s[1U])) ^ static_cast(mul_bytes(UINT8_C(0x09), s[2U]) ^ mul_bytes(UINT8_C(0x0E), s[3U]))); for(std::size_t i = 0; i < 4; ++i) { state[i][j] = s1[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-bounds-constant-array-index) } } } auto InvShiftRows(std::uint8_t** state) -> void { ShiftRow(state, 1, Nb - 1); ShiftRow(state, 2, Nb - 2); ShiftRow(state, 3, Nb - 3); } static auto Rcon(std::uint8_t* a, std::size_t n) -> void { std::uint8_t c = 1; for(std::size_t i = 0U; i < n - 1U; ++i) { c = xtime(c); } a[0U] = c; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) a[1U] = a[2U] = a[3U] = 0U; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } static auto RotWord(std::uint8_t *a) -> void { std::uint8_t c = a[0U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) a[0U] = a[1U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) a[1U] = a[2U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) a[2U] = a[3U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) a[3U] = c; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } static auto XorWords(const std::uint8_t* a, const std::uint8_t* b, std::uint8_t* c) -> void // NOLINT(bugprone-easily-swappable-parameters) { for(std::size_t i = 0U; i < 4U; ++i) { c[i] = a[i] ^ b[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } } private: static auto xtime(std::uint8_t b) -> std::uint8_t { // multiply on x const bool high_bit_is_set = ((b & 0x80U) != 0U); b = std::uint8_t(b << 1U); if(high_bit_is_set) { // mod m(x) constexpr std::uint8_t m = 0x1BU; b = b ^ m; } return b; } static auto mul_bytes(const std::uint8_t a, std::uint8_t b) -> std::uint8_t { std::uint8_t c = 0U; for(std::size_t i = 0U; i < 8U; ++i) { const bool low_bit_is_set = ((b & 1U) != 0U); if(low_bit_is_set) { std::uint8_t d = a; for(std::size_t j = 0U; j < i; ++j) { // multiply on x^i d = xtime(d); } // xor to result c = c ^ d; } b = std::uint8_t(b >> 1U); } return c; } }; #if(__cplusplus >= 201703L) } // namespace al::crypto::stream::cipher #else } // namespace cipher } // namespace stream } // namespace crypto } // namespace al #endif #endif // ALCRYPTOLIB_STREAM_CIPHER_CIPHER_AES_BASE_2020_01_29_H