diff --git a/include/boost/crypt2/aes/cipher_mode.hpp b/include/boost/crypt2/aes/cipher_mode.hpp new file mode 100644 index 00000000..858a4fd0 --- /dev/null +++ b/include/boost/crypt2/aes/cipher_mode.hpp @@ -0,0 +1,17 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CIPHER_MODE_HPP +#define BOOST_CIPHER_MODE_HPP + +namespace boost::crypt::aes { + +enum class cipher_mode +{ + ecb, // Electronic Codebook +}; + +} // namespace boost::crypt::aes + +#endif //BOOST_CIPHER_MODE_HPP diff --git a/include/boost/crypt2/aes/detail/cipher.hpp b/include/boost/crypt2/aes/detail/cipher.hpp new file mode 100644 index 00000000..50674d26 --- /dev/null +++ b/include/boost/crypt2/aes/detail/cipher.hpp @@ -0,0 +1,497 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT2_AES_DETAIL_CIPHER_HPP +#define BOOST_CRYPT2_AES_DETAIL_CIPHER_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost::crypt::aes_detail { + +inline constexpr compat::array sbox = { + compat::byte{0x63}, compat::byte{0x7c}, compat::byte{0x77}, compat::byte{0x7b}, compat::byte{0xf2}, compat::byte{0x6b}, compat::byte{0x6f}, compat::byte{0xc5}, compat::byte{0x30}, compat::byte{0x01}, compat::byte{0x67}, compat::byte{0x2b}, compat::byte{0xfe}, compat::byte{0xd7}, compat::byte{0xab}, compat::byte{0x76}, + compat::byte{0xca}, compat::byte{0x82}, compat::byte{0xc9}, compat::byte{0x7d}, compat::byte{0xfa}, compat::byte{0x59}, compat::byte{0x47}, compat::byte{0xf0}, compat::byte{0xad}, compat::byte{0xd4}, compat::byte{0xa2}, compat::byte{0xaf}, compat::byte{0x9c}, compat::byte{0xa4}, compat::byte{0x72}, compat::byte{0xc0}, + compat::byte{0xb7}, compat::byte{0xfd}, compat::byte{0x93}, compat::byte{0x26}, compat::byte{0x36}, compat::byte{0x3f}, compat::byte{0xf7}, compat::byte{0xcc}, compat::byte{0x34}, compat::byte{0xa5}, compat::byte{0xe5}, compat::byte{0xf1}, compat::byte{0x71}, compat::byte{0xd8}, compat::byte{0x31}, compat::byte{0x15}, + compat::byte{0x04}, compat::byte{0xc7}, compat::byte{0x23}, compat::byte{0xc3}, compat::byte{0x18}, compat::byte{0x96}, compat::byte{0x05}, compat::byte{0x9a}, compat::byte{0x07}, compat::byte{0x12}, compat::byte{0x80}, compat::byte{0xe2}, compat::byte{0xeb}, compat::byte{0x27}, compat::byte{0xb2}, compat::byte{0x75}, + compat::byte{0x09}, compat::byte{0x83}, compat::byte{0x2c}, compat::byte{0x1a}, compat::byte{0x1b}, compat::byte{0x6e}, compat::byte{0x5a}, compat::byte{0xa0}, compat::byte{0x52}, compat::byte{0x3b}, compat::byte{0xd6}, compat::byte{0xb3}, compat::byte{0x29}, compat::byte{0xe3}, compat::byte{0x2f}, compat::byte{0x84}, + compat::byte{0x53}, compat::byte{0xd1}, compat::byte{0x00}, compat::byte{0xed}, compat::byte{0x20}, compat::byte{0xfc}, compat::byte{0xb1}, compat::byte{0x5b}, compat::byte{0x6a}, compat::byte{0xcb}, compat::byte{0xbe}, compat::byte{0x39}, compat::byte{0x4a}, compat::byte{0x4c}, compat::byte{0x58}, compat::byte{0xcf}, + compat::byte{0xd0}, compat::byte{0xef}, compat::byte{0xaa}, compat::byte{0xfb}, compat::byte{0x43}, compat::byte{0x4d}, compat::byte{0x33}, compat::byte{0x85}, compat::byte{0x45}, compat::byte{0xf9}, compat::byte{0x02}, compat::byte{0x7f}, compat::byte{0x50}, compat::byte{0x3c}, compat::byte{0x9f}, compat::byte{0xa8}, + compat::byte{0x51}, compat::byte{0xa3}, compat::byte{0x40}, compat::byte{0x8f}, compat::byte{0x92}, compat::byte{0x9d}, compat::byte{0x38}, compat::byte{0xf5}, compat::byte{0xbc}, compat::byte{0xb6}, compat::byte{0xda}, compat::byte{0x21}, compat::byte{0x10}, compat::byte{0xff}, compat::byte{0xf3}, compat::byte{0xd2}, + compat::byte{0xcd}, compat::byte{0x0c}, compat::byte{0x13}, compat::byte{0xec}, compat::byte{0x5f}, compat::byte{0x97}, compat::byte{0x44}, compat::byte{0x17}, compat::byte{0xc4}, compat::byte{0xa7}, compat::byte{0x7e}, compat::byte{0x3d}, compat::byte{0x64}, compat::byte{0x5d}, compat::byte{0x19}, compat::byte{0x73}, + compat::byte{0x60}, compat::byte{0x81}, compat::byte{0x4f}, compat::byte{0xdc}, compat::byte{0x22}, compat::byte{0x2a}, compat::byte{0x90}, compat::byte{0x88}, compat::byte{0x46}, compat::byte{0xee}, compat::byte{0xb8}, compat::byte{0x14}, compat::byte{0xde}, compat::byte{0x5e}, compat::byte{0x0b}, compat::byte{0xdb}, + compat::byte{0xe0}, compat::byte{0x32}, compat::byte{0x3a}, compat::byte{0x0a}, compat::byte{0x49}, compat::byte{0x06}, compat::byte{0x24}, compat::byte{0x5c}, compat::byte{0xc2}, compat::byte{0xd3}, compat::byte{0xac}, compat::byte{0x62}, compat::byte{0x91}, compat::byte{0x95}, compat::byte{0xe4}, compat::byte{0x79}, + compat::byte{0xe7}, compat::byte{0xc8}, compat::byte{0x37}, compat::byte{0x6d}, compat::byte{0x8d}, compat::byte{0xd5}, compat::byte{0x4e}, compat::byte{0xa9}, compat::byte{0x6c}, compat::byte{0x56}, compat::byte{0xf4}, compat::byte{0xea}, compat::byte{0x65}, compat::byte{0x7a}, compat::byte{0xae}, compat::byte{0x08}, + compat::byte{0xba}, compat::byte{0x78}, compat::byte{0x25}, compat::byte{0x2e}, compat::byte{0x1c}, compat::byte{0xa6}, compat::byte{0xb4}, compat::byte{0xc6}, compat::byte{0xe8}, compat::byte{0xdd}, compat::byte{0x74}, compat::byte{0x1f}, compat::byte{0x4b}, compat::byte{0xbd}, compat::byte{0x8b}, compat::byte{0x8a}, + compat::byte{0x70}, compat::byte{0x3e}, compat::byte{0xb5}, compat::byte{0x66}, compat::byte{0x48}, compat::byte{0x03}, compat::byte{0xf6}, compat::byte{0x0e}, compat::byte{0x61}, compat::byte{0x35}, compat::byte{0x57}, compat::byte{0xb9}, compat::byte{0x86}, compat::byte{0xc1}, compat::byte{0x1d}, compat::byte{0x9e}, + compat::byte{0xe1}, compat::byte{0xf8}, compat::byte{0x98}, compat::byte{0x11}, compat::byte{0x69}, compat::byte{0xd9}, compat::byte{0x8e}, compat::byte{0x94}, compat::byte{0x9b}, compat::byte{0x1e}, compat::byte{0x87}, compat::byte{0xe9}, compat::byte{0xce}, compat::byte{0x55}, compat::byte{0x28}, compat::byte{0xdf}, + compat::byte{0x8c}, compat::byte{0xa1}, compat::byte{0x89}, compat::byte{0x0d}, compat::byte{0xbf}, compat::byte{0xe6}, compat::byte{0x42}, compat::byte{0x68}, compat::byte{0x41}, compat::byte{0x99}, compat::byte{0x2d}, compat::byte{0x0f}, compat::byte{0xb0}, compat::byte{0x54}, compat::byte{0xbb}, compat::byte{0x16} +}; + +inline constexpr compat::array rsbox = { + compat::byte{0x52}, compat::byte{0x09}, compat::byte{0x6a}, compat::byte{0xd5}, compat::byte{0x30}, compat::byte{0x36}, compat::byte{0xa5}, compat::byte{0x38}, compat::byte{0xbf}, compat::byte{0x40}, compat::byte{0xa3}, compat::byte{0x9e}, compat::byte{0x81}, compat::byte{0xf3}, compat::byte{0xd7}, compat::byte{0xfb}, + compat::byte{0x7c}, compat::byte{0xe3}, compat::byte{0x39}, compat::byte{0x82}, compat::byte{0x9b}, compat::byte{0x2f}, compat::byte{0xff}, compat::byte{0x87}, compat::byte{0x34}, compat::byte{0x8e}, compat::byte{0x43}, compat::byte{0x44}, compat::byte{0xc4}, compat::byte{0xde}, compat::byte{0xe9}, compat::byte{0xcb}, + compat::byte{0x54}, compat::byte{0x7b}, compat::byte{0x94}, compat::byte{0x32}, compat::byte{0xa6}, compat::byte{0xc2}, compat::byte{0x23}, compat::byte{0x3d}, compat::byte{0xee}, compat::byte{0x4c}, compat::byte{0x95}, compat::byte{0x0b}, compat::byte{0x42}, compat::byte{0xfa}, compat::byte{0xc3}, compat::byte{0x4e}, + compat::byte{0x08}, compat::byte{0x2e}, compat::byte{0xa1}, compat::byte{0x66}, compat::byte{0x28}, compat::byte{0xd9}, compat::byte{0x24}, compat::byte{0xb2}, compat::byte{0x76}, compat::byte{0x5b}, compat::byte{0xa2}, compat::byte{0x49}, compat::byte{0x6d}, compat::byte{0x8b}, compat::byte{0xd1}, compat::byte{0x25}, + compat::byte{0x72}, compat::byte{0xf8}, compat::byte{0xf6}, compat::byte{0x64}, compat::byte{0x86}, compat::byte{0x68}, compat::byte{0x98}, compat::byte{0x16}, compat::byte{0xd4}, compat::byte{0xa4}, compat::byte{0x5c}, compat::byte{0xcc}, compat::byte{0x5d}, compat::byte{0x65}, compat::byte{0xb6}, compat::byte{0x92}, + compat::byte{0x6c}, compat::byte{0x70}, compat::byte{0x48}, compat::byte{0x50}, compat::byte{0xfd}, compat::byte{0xed}, compat::byte{0xb9}, compat::byte{0xda}, compat::byte{0x5e}, compat::byte{0x15}, compat::byte{0x46}, compat::byte{0x57}, compat::byte{0xa7}, compat::byte{0x8d}, compat::byte{0x9d}, compat::byte{0x84}, + compat::byte{0x90}, compat::byte{0xd8}, compat::byte{0xab}, compat::byte{0x00}, compat::byte{0x8c}, compat::byte{0xbc}, compat::byte{0xd3}, compat::byte{0x0a}, compat::byte{0xf7}, compat::byte{0xe4}, compat::byte{0x58}, compat::byte{0x05}, compat::byte{0xb8}, compat::byte{0xb3}, compat::byte{0x45}, compat::byte{0x06}, + compat::byte{0xd0}, compat::byte{0x2c}, compat::byte{0x1e}, compat::byte{0x8f}, compat::byte{0xca}, compat::byte{0x3f}, compat::byte{0x0f}, compat::byte{0x02}, compat::byte{0xc1}, compat::byte{0xaf}, compat::byte{0xbd}, compat::byte{0x03}, compat::byte{0x01}, compat::byte{0x13}, compat::byte{0x8a}, compat::byte{0x6b}, + compat::byte{0x3a}, compat::byte{0x91}, compat::byte{0x11}, compat::byte{0x41}, compat::byte{0x4f}, compat::byte{0x67}, compat::byte{0xdc}, compat::byte{0xea}, compat::byte{0x97}, compat::byte{0xf2}, compat::byte{0xcf}, compat::byte{0xce}, compat::byte{0xf0}, compat::byte{0xb4}, compat::byte{0xe6}, compat::byte{0x73}, + compat::byte{0x96}, compat::byte{0xac}, compat::byte{0x74}, compat::byte{0x22}, compat::byte{0xe7}, compat::byte{0xad}, compat::byte{0x35}, compat::byte{0x85}, compat::byte{0xe2}, compat::byte{0xf9}, compat::byte{0x37}, compat::byte{0xe8}, compat::byte{0x1c}, compat::byte{0x75}, compat::byte{0xdf}, compat::byte{0x6e}, + compat::byte{0x47}, compat::byte{0xf1}, compat::byte{0x1a}, compat::byte{0x71}, compat::byte{0x1d}, compat::byte{0x29}, compat::byte{0xc5}, compat::byte{0x89}, compat::byte{0x6f}, compat::byte{0xb7}, compat::byte{0x62}, compat::byte{0x0e}, compat::byte{0xaa}, compat::byte{0x18}, compat::byte{0xbe}, compat::byte{0x1b}, + compat::byte{0xfc}, compat::byte{0x56}, compat::byte{0x3e}, compat::byte{0x4b}, compat::byte{0xc6}, compat::byte{0xd2}, compat::byte{0x79}, compat::byte{0x20}, compat::byte{0x9a}, compat::byte{0xdb}, compat::byte{0xc0}, compat::byte{0xfe}, compat::byte{0x78}, compat::byte{0xcd}, compat::byte{0x5a}, compat::byte{0xf4}, + compat::byte{0x1f}, compat::byte{0xdd}, compat::byte{0xa8}, compat::byte{0x33}, compat::byte{0x88}, compat::byte{0x07}, compat::byte{0xc7}, compat::byte{0x31}, compat::byte{0xb1}, compat::byte{0x12}, compat::byte{0x10}, compat::byte{0x59}, compat::byte{0x27}, compat::byte{0x80}, compat::byte{0xec}, compat::byte{0x5f}, + compat::byte{0x60}, compat::byte{0x51}, compat::byte{0x7f}, compat::byte{0xa9}, compat::byte{0x19}, compat::byte{0xb5}, compat::byte{0x4a}, compat::byte{0x0d}, compat::byte{0x2d}, compat::byte{0xe5}, compat::byte{0x7a}, compat::byte{0x9f}, compat::byte{0x93}, compat::byte{0xc9}, compat::byte{0x9c}, compat::byte{0xef}, + compat::byte{0xa0}, compat::byte{0xe0}, compat::byte{0x3b}, compat::byte{0x4d}, compat::byte{0xae}, compat::byte{0x2a}, compat::byte{0xf5}, compat::byte{0xb0}, compat::byte{0xc8}, compat::byte{0xeb}, compat::byte{0xbb}, compat::byte{0x3c}, compat::byte{0x83}, compat::byte{0x53}, compat::byte{0x99}, compat::byte{0x61}, + compat::byte{0x17}, compat::byte{0x2b}, compat::byte{0x04}, compat::byte{0x7e}, compat::byte{0xba}, compat::byte{0x77}, compat::byte{0xd6}, compat::byte{0x26}, compat::byte{0xe1}, compat::byte{0x69}, compat::byte{0x14}, compat::byte{0x63}, compat::byte{0x55}, compat::byte{0x21}, compat::byte{0x0c}, compat::byte{0x7d} +}; + +inline constexpr compat::array Rcon = { + compat::byte{0x8d}, compat::byte{0x01}, compat::byte{0x02}, compat::byte{0x04}, compat::byte{0x08}, compat::byte{0x10}, compat::byte{0x20}, compat::byte{0x40}, compat::byte{0x80}, compat::byte{0x1b}, compat::byte{0x36} +}; + +template +class cipher +{ +private: + + static constexpr compat::size_t Nb {4}; // Block size + static constexpr compat::size_t Nk {Nr == 10 ? 4 : + Nr == 12 ? 6 : + Nr == 14 ? 8 : 0}; // Key length in 32-bit words + + static_assert(Nk != 0, "Invalid key length"); + + static constexpr compat::size_t key_expansion_size {Nr == 10 ? 176 : + Nr == 12 ? 208 : + Nr == 14 ? 240 : 0}; + + static constexpr compat::size_t state_total_size {Nb * Nb}; + + compat::array, Nb> state {}; + compat::array round_key {}; + bool initialized {false}; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto rot_word(compat::array& temp) noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sub_word(compat::array& temp) noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto key_expansion(compat::span key) noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto sub_bytes() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto inv_sub_bytes() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto shift_rows() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto inv_shift_rows() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto xtimes(compat::byte b) noexcept -> compat::byte; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto mix_columns() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto inv_mix_columns() noexcept -> void; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto gf28_multiply(compat::byte x, compat::byte y) noexcept -> compat::byte; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto add_round_key(compat::size_t round) noexcept -> void; + +public: + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR cipher() noexcept = default; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~cipher() noexcept; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span key) noexcept -> crypt::state; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto block_cipher(compat::span buffer) noexcept -> crypt::state; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto inverse_block_cipher(compat::span buffer) noexcept -> crypt::state; +}; + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR cipher::~cipher() noexcept +{ + detail::clear_mem(state[0]); + detail::clear_mem(state[1]); + detail::clear_mem(state[2]); + detail::clear_mem(state[3]); + + detail::clear_mem(round_key); + + initialized = false; +} + +// The transformation of words in which the four bytes of the word +// are permuted cyclically. +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::rot_word(compat::array& temp) noexcept -> void +{ + const auto temp0 {temp[0]}; + temp[0] = temp[1]; + temp[1] = temp[2]; + temp[2] = temp[3]; + temp[3] = temp0; +} + +// The transformation of words in which the S-box is applied to each +// of the four bytes of the word. +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::sub_word(compat::array& temp) noexcept -> void +{ + temp[0] = sbox[static_cast(temp[0])]; + temp[1] = sbox[static_cast(temp[1])]; + temp[2] = sbox[static_cast(temp[2])]; + temp[3] = sbox[static_cast(temp[3])]; +} + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::key_expansion(compat::span key) noexcept -> void +{ + compat::array temp; + + for (compat::size_t i {}; i < Nk; ++i) + { + const auto k {i * 4U}; + round_key[k + 0U] = key[k + 0U]; + round_key[k + 1U] = key[k + 1U]; + round_key[k + 2U] = key[k + 2U]; + round_key[k + 3U] = key[k + 3U]; + } + + for (compat::size_t i {Nk}; i < Nb * (Nr + 1); ++i) + { + const auto k {(i - 1) * 4U}; + temp[0] = round_key[k + 0U]; + temp[1] = round_key[k + 1U]; + temp[2] = round_key[k + 2U]; + temp[3] = round_key[k + 3U]; + + if (i % Nk == 0) + { + rot_word(temp); + sub_word(temp); + temp[0] ^= Rcon[i / Nk]; + } + + if constexpr (Nk > 6U) + { + if (i % Nk == 4U) + { + sub_word(temp); + } + } + const auto j {i * 4U}; + const auto l {(i - Nk) * 4U}; + round_key[j + 0U] = round_key[l + 0U] ^ temp[0]; + round_key[j + 1U] = round_key[l + 1U] ^ temp[1]; + round_key[j + 2U] = round_key[l + 2U] ^ temp[2]; + round_key[j + 3U] = round_key[l + 3U] ^ temp[3]; + } +} + +// The transformation of the state that applies the S-box independently +// to each byte of the state. +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::sub_bytes() noexcept -> void +{ + for (auto& line : state) + { + for (auto& val : line) + { + val = sbox[static_cast(val)]; + } + } +} + +// The inverse of sub_bytes (above), in which rsbox is applied to each byte +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::inv_sub_bytes() noexcept -> void +{ + for (auto& line : state) + { + for (auto& val : line) + { + val = rsbox[static_cast(val)]; + } + } +} + +// The transformation of the state in which the last three rows are +// cyclically shifted by different offsets. +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::shift_rows() noexcept -> void +{ + compat::byte temp {}; + + temp = state[0][1]; + state[0][1] = state[1][1]; + state[1][1] = state[2][1]; + state[2][1] = state[3][1]; + state[3][1] = temp; + + temp = state[0][2]; + state[0][2] = state[2][2]; + state[2][2] = temp; + + temp = state[1][2]; + state[1][2] = state[3][2]; + state[3][2] = temp; + + temp = state[0][3]; + state[0][3] = state[3][3]; + state[3][3] = state[2][3]; + state[2][3] = state[1][3]; + state[1][3] = temp; +} + +// inv_shift_rows in the inverse of shift rows (above). +// In particular, the bytes in the last three rows of the state are shifted cyclically +// +// s'_r,c = s_r,(c-r) mod 4 for 0 <= r < 4 and 0 <= c < 4 +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::inv_shift_rows() noexcept -> void +{ + compat::byte temp {}; + + temp = state[3][1]; + state[3][1] = state[2][1]; + state[2][1] = state[1][1]; + state[1][1] = state[0][1]; + state[0][1] = temp; + + temp = state[0][2]; + state[0][2] = state[2][2]; + state[2][2] = temp; + + temp = state[1][2]; + state[1][2] = state[3][2]; + state[3][2] = temp; + + temp = state[0][3]; + state[0][3] = state[1][3]; + state[1][3] = state[2][3]; + state[2][3] = state[3][3]; + state[3][3] = temp; +} + +// The transformation of bytes in which the polynomial representation +// of the input byte is multiplied by x, modulo m(x), to produce the +// polynomial representation of the output byte. +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::xtimes(compat::byte b) noexcept -> compat::byte +{ + return static_cast((b << 1U) ^ static_cast(static_cast((b >> 7U) & static_cast(1U)) * 0x1BU)); +} + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::mix_columns() noexcept -> void +{ + for (auto& column : state) + { + const auto s0 {column[0]}; + const auto all_c {column[0] ^ column[1] ^ column[2] ^ column[3]}; + + // s'_0,c = ({02} * s_0,c) ^ ({03} * s_1,c) ^ s_2,c ^ s_3,c + auto temp {column[0] ^ column[1]}; + temp = xtimes(temp); + column[0] ^= temp ^ all_c; + + // s'_1,c = s_0,c ^ ({02} * s_1,c) ^ ({03} * s_2,c) ^ s_3,c + temp = column[1] ^ column[2]; + temp = xtimes(temp); + column[1] ^= temp ^ all_c; + + // s`_2,c = s_0,c ^ s_1,c ^ ({02} * s_2,c) ^ ({03} * s_3,c) + temp = column[2] ^ column[3]; + temp = xtimes(temp); + column[2] ^= temp ^ all_c; + + // s`_3,c = ({03} * s_0,c) ^ s_1,c ^ s_2,c ^ ({02} * s_3,c) + temp = column[3] ^ s0; + temp = xtimes(temp); + column[3] ^= temp ^ all_c ; + } +} + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::inv_mix_columns() noexcept -> void +{ + for (auto& column : state) + { + const auto s0 {column[0]}; + const auto s1 {column[1]}; + const auto s2 {column[2]}; + const auto s3 {column[3]}; + + constexpr compat::byte b {0x0b}; + constexpr compat::byte d {0x0d}; + constexpr compat::byte e {0x0e}; + constexpr compat::byte nine {0x09}; + + + // s'_0,c = ({0e} * s_0,c) ^ ({0b} * s_1,c) ^ ({0d} * s_2,c) ^ ({09} * s_3,c) + column[0] = gf28_multiply(s0, e) ^ gf28_multiply(s1, b) ^ gf28_multiply(s2, d) ^ gf28_multiply(s3, nine); + + // s'_1,c = ({09} * s_0,c) ^ ({0e} * s_1,c) ^ ({0b} * s_2,c) ^ ({0d} * s_3,c) + column[1] = gf28_multiply(s0, nine) ^ gf28_multiply(s1, e) ^ gf28_multiply(s2, b) ^ gf28_multiply(s3, d); + + // s`_2,c = ({0d} * s_0,c) ^ ({09} * s_1,c) ^ ({0e} * s_2,c) ^ ({0b} * s_3,c) + column[2] = gf28_multiply(s0, d) ^ gf28_multiply(s1, nine) ^ gf28_multiply(s2, e) ^ gf28_multiply(s3, b); + + // s`_3,c = ({0b} * s_0,c) ^ ({0d} * s_1,c) ^ ({09} * s_2,c) ^ ({0e} * s_3,c) + column[3] = gf28_multiply(s0, b) ^ gf28_multiply(s1, d) ^ gf28_multiply(s2, nine) ^ gf28_multiply(s3, e); + } +} + +// Multiplication of two elements in GF(2^8) +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::gf28_multiply(compat::byte x, compat::byte y) noexcept -> compat::byte +{ + constexpr compat::byte one {1U}; + + return static_cast( + static_cast(static_cast(y & one) * static_cast(x)) ^ + static_cast(static_cast(y >> 1U & one) * static_cast(xtimes(x))) ^ + static_cast(static_cast(y >> 2U & one) * static_cast(xtimes(xtimes(x)))) ^ + static_cast(static_cast(y >> 3U & one) * static_cast(xtimes(xtimes(xtimes(x))))) ^ + static_cast(static_cast(y >> 4U & one) * static_cast(xtimes(xtimes(xtimes(xtimes(x)))))) + ); +} + +// The transformation of the state in which a round key is combined +// with the state. +// +// Add round_key is its own inverse so there is no separate inverse function +template +constexpr auto cipher::add_round_key(compat::size_t round) noexcept -> void +{ + for (compat::size_t i {}; i < Nb; ++i) + { + for (compat::size_t j {}; j < Nb; ++j) + { + const auto round_key_value {round_key[(round * Nb * 4U) + (i * Nb) + j]}; + state[i][j] ^= round_key_value; + } + } +} + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::init(compat::span key) noexcept -> crypt::state +{ + key_expansion(key); + initialized = true; + return state::success; +} + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto cipher::block_cipher(compat::span buffer) noexcept -> crypt::state +{ + if (!initialized) + { + return state::uninitialized; + } + + // Write the buffer to state and then perform operations + auto buffer_iter {buffer.begin()}; + for (auto& row : state) + { + for (auto& element : row) + { + element = *buffer_iter++; + } + } + BOOST_CRYPT_ASSERT(buffer_iter == buffer.end()); + + compat::size_t round {}; + + add_round_key(round); + + for (++round; round < Nr; ++round) + { + sub_bytes(); + shift_rows(); + mix_columns(); + add_round_key(round); + } + + BOOST_CRYPT_ASSERT(round == Nr); + + sub_bytes(); + shift_rows(); + add_round_key(round); + + // Write the cipher text back + buffer_iter = buffer.begin(); + for (const auto& row : state) + { + for (const auto& element : row) + { + *buffer_iter++ = element; + } + } + BOOST_CRYPT_ASSERT(buffer_iter == buffer.end()); + + return state::success; +} + +template +constexpr auto cipher::inverse_block_cipher(compat::span buffer) noexcept -> crypt::state +{ + if (!initialized) + { + return state::uninitialized; + } + + // Write the buffer to state and then perform operations + auto buffer_iter {buffer.begin()}; + for (auto& row : state) + { + for (auto& element : row) + { + element = *buffer_iter++; + } + } + BOOST_CRYPT_ASSERT(buffer_iter == buffer.end()); + + compat::size_t round {Nr}; + + add_round_key(round); + + for (--round; round > 0; --round) + { + inv_shift_rows(); + inv_sub_bytes(); + add_round_key(round); + inv_mix_columns(); + } + + BOOST_CRYPT_ASSERT(round == 0); + inv_shift_rows(); + inv_sub_bytes(); + add_round_key(round); + + // Write the cipher text back + buffer_iter = buffer.begin(); + for (const auto& row : state) + { + for (const auto& element : row) + { + *buffer_iter++ = element; + } + } + BOOST_CRYPT_ASSERT(buffer_iter == buffer.end()); + + return state::success; +} + +} // namespace boost::crypt::aes_detail + +#endif // BOOST_CRYPT2_AES_DETAIL_CIPHER_HPP diff --git a/include/boost/crypt2/detail/compat.hpp b/include/boost/crypt2/detail/compat.hpp index e4b5fe0e..9fc91cd2 100644 --- a/include/boost/crypt2/detail/compat.hpp +++ b/include/boost/crypt2/detail/compat.hpp @@ -46,11 +46,13 @@ namespace boost::crypt::compat { // Fixed width types #if BOOST_CRYPT_HAS_CUDA using size_t = cuda::std::size_t; +using uint8_t = cuda::std::uint8_t; using uint16_t = cuda::std::uint16_t; using uint32_t = cuda::std::uint32_t; using uint64_t = cuda::std::uint64_t; #else using size_t = std::size_t; +using uint8_t = std::uint8_t; using uint16_t = std::uint16_t; using uint32_t = std::uint32_t; using uint64_t = std::uint64_t; diff --git a/test/Jamfile b/test/Jamfile index b364f475..b336f163 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -81,7 +81,7 @@ run test_hmac_drbg.cpp ; run test_hash_drbg.cpp ; -#run test_aes.cpp ; +run test_aes.cpp ; # NIST standard testing run test_nist_cavs_sha1_monte.cpp ; diff --git a/test/test_aes.cpp b/test/test_aes.cpp index 715c15a7..102b4e42 100644 --- a/test/test_aes.cpp +++ b/test/test_aes.cpp @@ -2,43 +2,58 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include #include +#include -void basic_aes128_test() +void basic_block_cipher_test() { // AES-128 key from appendix A.1 - boost::crypt::array key = { - 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c + + constexpr std::array key = { + std::byte{0x2b}, std::byte{0x7e}, std::byte{0x15}, std::byte{0x16}, + std::byte{0x28}, std::byte{0xae}, std::byte{0xd2}, std::byte{0xa6}, + std::byte{0xab}, std::byte{0xf7}, std::byte{0x15}, std::byte{0x88}, + std::byte{0x09}, std::byte{0xcf}, std::byte{0x4f}, std::byte{0x3c} }; + const std::span key_span {key}; - boost::crypt::array plaintext = { - 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, - 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 + std::array plaintext = { + std::byte{0x32}, std::byte{0x43}, std::byte{0xf6}, std::byte{0xa8}, + std::byte{0x88}, std::byte{0x5a}, std::byte{0x30}, std::byte{0x8d}, + std::byte{0x31}, std::byte{0x31}, std::byte{0x98}, std::byte{0xa2}, + std::byte{0xe0}, std::byte{0x37}, std::byte{0x07}, std::byte{0x34} }; + std::span plaintext_span {plaintext}; const auto original_message {plaintext}; - boost::crypt::aes128 gen; - BOOST_TEST(gen.init(key, key.size()) == boost::crypt::state::success); - BOOST_TEST(gen.encrypt(plaintext.begin(), plaintext.size()) == boost::crypt::state::success); + boost::crypt::aes_detail::cipher<10> gen; + BOOST_TEST(gen.init(key_span) == boost::crypt::state::success); + BOOST_TEST(gen.block_cipher(plaintext_span) == boost::crypt::state::success); + - const boost::crypt::array validation_1 = { - 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, - 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, + constexpr std::array validation_1 = { + std::byte{0x39}, std::byte{0x25}, std::byte{0x84}, std::byte{0x1d}, + std::byte{0x02}, std::byte{0xdc}, std::byte{0x09}, std::byte{0xfb}, + std::byte{0xdc}, std::byte{0x11}, std::byte{0x85}, std::byte{0x97}, + std::byte{0x19}, std::byte{0x6a}, std::byte{0x0b}, std::byte{0x32} }; BOOST_TEST(plaintext == validation_1); - BOOST_TEST(gen.decrypt(plaintext.begin(), plaintext.size()) == boost::crypt::state::success); + BOOST_TEST(gen.inverse_block_cipher(plaintext_span) == boost::crypt::state::success); BOOST_TEST(plaintext == original_message); - gen.destroy(); + // Bad inputs + boost::crypt::aes_detail::cipher<10> gen2; + BOOST_TEST(gen2.block_cipher(plaintext_span) == boost::crypt::state::uninitialized); + BOOST_TEST(gen2.inverse_block_cipher(plaintext_span) == boost::crypt::state::uninitialized); } +/* void cbc_test() { // GFSbox test @@ -303,10 +318,12 @@ void cfb128_test() BOOST_TEST(gen.decrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()) == boost::crypt::state::success); BOOST_TEST(plaintext == plaintext_original); } +*/ int main() { - basic_aes128_test(); + basic_block_cipher_test(); + /* cbc_test(); cbc_mmt_test(); ofb_test(); @@ -315,6 +332,7 @@ int main() ctr_mmt_test(); cfb8_test(); cfb128_test(); + */ return boost::report_errors(); }