49 uint8_t
mult(uint8_t a, uint8_t b) {
89 if (a & 0x80) a = (a << 1) ^ 0b100011011;
107 for (
size_t x = 0; x < 256; ++x) {
108 if (
mult(a, x) == 1)
return x;
131 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
132 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
142 uint32_t
RotWord(
const uint32_t& word) {
return std::rotl(word, 8);}
153 uint8_t dest[4] = {0};
156 auto* bytes =
reinterpret_cast<const uint8_t*
>(&word);
158 for (
size_t x = 0; x < 4; ++x) {
160 const uint8_t
byte = bytes[x];
161 std::bitset<8> i =
gf::inverse(
byte), c = 0b01100011, result = 0;
162 for (
int x = 0; x < 8; ++x) {
163 result[x] = i[x] ^ i[(x + 4) % 8] ^ i[(x + 5) % 8] ^ i[(x + 6) % 8] ^ i[(x + 7) % 8] ^ c[x];
165 dest[x] = uint8_t(result.to_ulong());
169 return *
reinterpret_cast<uint32_t*
>(&dest[0]);
193 std::vector<uint32_t>
Expansion(
const std::array<uint64_t, 4>& key,
const uint64_t& Nk) {
197 std::vector<uint32_t> words;
198 for (
size_t x = 0; x < 4; ++x) {
199 words.emplace_back(key[x] & 0xffffffff);
200 words.emplace_back(key[x] >> 32);
205 uint64_t Nr = Nk == 4 ? 10 : Nk == 6 ? 12 : 14;
206 auto w = std::vector<uint32_t>(4*Nr + 4, 0);
220 for(; i < 4*Nr + 3; ++i) {
223 uint32_t temp = w[i - 1];
230 else if (Nk > 6 && i % Nk == 4) {
233 w[i] = w[i - Nk] ^ temp;
254 std::array<std::array<uint8_t, 4>, 4> array;
264 auto length = in.length();
281 for (; x < length && i < 16; ++i, ++x) array[i / 4][i % 4] = in[x];
284 for (; i < 16; ++i) array[i / 4][i % 4] = 0;
290 auto length = in.length();
291 for (uint8_t i = 0; i < 16; ++i)
292 array[i / 4][i % 4] = i < length ? in[i] : 0;
297 state_array(
const state_array& arr) {
298 for (uint8_t row = 0; row < 4; ++row) {
299 for (uint8_t col = 0; col < 4; ++col) {
300 array[row][col] = arr.array[row][col];
308 for (uint8_t row = 0; row < 4; ++row) {
309 for (uint8_t col = 0; col < 4; ++col) {
317 auto& get() {
return array;}
318 const auto& get()
const {
return array;}
322 void xor_arr(
const state_array& arr) {
323 for (uint8_t row = 0; row < 4; ++row) {
324 for (uint8_t col = 0; col < 4; ++col) {
325 array[col][row] ^= arr.array[col][row];
332 void shift_r(
const size_t& bits) {
333 if (bits == 0)
return;
346 for (uint8_t row = 0; row < 4; ++row) {
347 for (uint8_t col = 0; col < 4; ++col) {
350 uint8_t value = (array[col][row] >> 1) | carry;
353 if (array[col][row] & 1)
358 array[col][row] = value;
380 std::stringstream out;
381 for (uint8_t row = 0; row < 4; ++row) {
382 for (uint8_t col = 0; col < 4; ++col) {
383 out << array[row][col];
396 void AddRoundKey(
const uint64_t& round,
const std::vector<uint32_t>& keys) {
397 for (
size_t col = 0; col < 4; ++col) {
398 const auto key = keys[(4 * round) + col];
401 auto* bytes =
reinterpret_cast<const uint8_t*
>(&key);
403 for (
size_t row = 0; row < 4; ++row) {
404 array[row][col] ^= bytes[row];
420 for (uint8_t row = 0; row < 4; ++row) {
421 for (uint8_t col = 0; col < 4; ++col) {
423 const uint8_t
byte = array[col][row];
432 std::bitset<8> i =
gf::inverse(
byte), c = 0b01100011, result = 0;
438 for (
int x = 0; x < 8; ++x) {
443 result[x] = i[x] ^ i[(x + 4) % 8] ^ i[(x + 5) % 8] ^ i[(x + 6) % 8] ^ i[(x + 7) % 8] ^ c[x];
447 array[col][row] = result.to_ulong();
460 for (uint8_t row = 0; row < 4; ++row) {
461 for (uint8_t col = 0; col < 4; ++col) {
462 const uint8_t
byte = array[col][row];
469 uint8_t i = byte, c = 0b00000101, result = 0;
470 result = std::rotl(i, 1) ^ std::rotl(i, 3) ^ std::rotl(i, 6) ^ c;
491 std::array<std::array<uint8_t, 4>, 4> buffer;
508 for (
size_t row = 0; row < 4; ++row) {
509 for (
size_t col = 0; col < 4; ++col) {
510 buffer[col][row] = array[(col + row) % 4][row];
518 for (
size_t row = 0; row < 4; ++row) {
519 for (
size_t col = 0; col < 4; ++col) {
520 array[col][row] = buffer[col][row];
536 std::array<std::array<uint8_t, 4>, 4> buffer;
539 for (
size_t row = 0; row < 4; ++row) {
540 for (
size_t col = 0; col < 4; ++col) {
541 buffer[col][row] = array[(col - row) % 4][row];
546 for (
size_t row = 0; row < 4; ++row) {
547 for (
size_t col = 0; col < 4; ++col) {
548 array[col][row] = buffer[col][row];
571 const uint8_t set[4] = {0x02, 0x01, 0x01, 0x03};
572 for (
size_t col = 0; col < 4; ++col) {
573 buffer[0] =
gf::mult(0x2, array[col][0]) ^
gf::mult(0x3, array[col][1]) ^ array[col][2] ^ array[col][3];
574 buffer[1] = array[col][0] ^
gf::mult(0x2, array[col][1]) ^
gf::mult(0x3, array[col][2]) ^ array[col][3];
575 buffer[2] = array[col][0] ^ array[col][1] ^
gf::mult(0x2, array[col][2]) ^
gf::mult(0x3, array[col][3]);
576 buffer[3] =
gf::mult(0x3, array[col][0]) ^ array[col][1] ^ array[col][2] ^
gf::mult(0x2, array[col][3]);
578 for (
size_t row = 0; row < 4; ++row) array[col][row] = buffer[row];
599 const uint8_t set[4] = {0x0e, 0x09, 0x0d, 0x0b};
600 for (
size_t col = 0; col < 4; ++col) {
606 for (
size_t row = 0; row < 4; ++row) array[col][row] = buffer[row];
617 std::vector<state_array> arrays;
618 std::vector<uint32_t> expanded;
619 std::array<uint64_t, 4> key = {0};
629 void Schedule(
const std::array<uint64_t, 4>& k,
const uint64_t& Nr) {
634 default:
throw std::runtime_error(
"Invalid key size:" + std::to_string(Nr));
642 state(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t& Nr) {
651 while (x < in.length()) {arrays.emplace_back(
state_array(in, x));}
659 state(
const std::vector<state_array>& arrs,
const std::array<uint64_t, 4>& k,
const uint64_t& Nr) {
668 auto& get_arrays() {
return arrays;}
669 const auto& get_arrays()
const {
return arrays;}
670 const auto& get_key() {
return key;}
671 const auto& get_rounds() {
return rounds;}
679 std::stringstream out;
680 for (
const auto& array : arrays)
681 out << array.unravel();
691 void AddRoundKey(
const uint64_t& round) {
for (
auto& array: arrays) array.AddRoundKey(round, expanded);}
694 void SubBytes() {
for (
auto& array: arrays) array.SubBytes();}
695 void InvSubBytes() {
for (
auto& array: arrays) array.InvSubBytes();}
698 void ShiftRows() {
for (
auto& array: arrays) array.ShiftRows();}
699 void InvShiftRows() {
for (
auto& array: arrays) array.InvShiftRows();}
702 void MixColumns() {
for (
auto& array: arrays) array.MixColumns();}
703 void InvMixColumns() {
for (
auto& array: arrays) array.InvMixColumns();}
716 std::string
Cipher(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t& Nr) {
717 auto s =
state(in, k, Nr);
720 for (
size_t x = 0; x < Nr - 1; ++x) {
724 s.AddRoundKey(x + 1);
729 s.AddRoundKey(Nr - 1);
744 std::string
InvCipher(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t& Nr) {
745 auto s =
state(in, k, Nr);
750 s.AddRoundKey(Nr - 1);
752 for (
size_t x = Nr - 1; x >= 1; --x) {
776 std::string
Ctr(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t Nr, uint64_t nonce) {
778 auto s =
state(in, k, Nr);
781 for (
auto& array: s.get_arrays()) {
784 auto pad =
state_array(
Cipher(std::string(
reinterpret_cast<char*
>(&nonce),
sizeof(uint64_t)), k, Nr));
830 auto& array = X.get();
863 uint32_t lsb = (array[3][0] << 24) | (array[3][1] << 16) | (array[3][2] << 8) | array[3][3];
872 for (
int x = 3; x >= 0; --x) {
875 array[3][x] = lsb & 0xFF;
892 R.get()[0][0] = 0b11100001;
911 for (
size_t row = 0; row < 4; ++row) {
912 for (
size_t col = 0; col < 4; ++col) {
913 uint8_t
byte = X.get()[col][row];
914 for (
size_t bit = 0; bit < 8; ++bit) {
917 bool x =
byte & 0b10000000;
926 if (V.get()[3][3] & 1 == 1)
960 for (
const auto& array: X.get_arrays()) {
981 for (
auto& array: s.get_arrays()) {
1007 std::string Enc(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t Nr, uint64_t nonce) {
1013 auto J =
GHASH(
state(std::string(
reinterpret_cast<char*
>(&nonce),
sizeof(nonce)), k, Nr), H);
1022 auto cipher_state =
state(in, k, Nr);
1023 cipher_state =
GCTR(cipher_state, Jc);
1032 auto hash =
GCTR(
state({
GHASH(cipher_state, H)}, k, Nr), J).get_arrays()[0];
1035 cipher_state.get_arrays().emplace_back(hash);
1036 return cipher_state.unravel();
1049 std::string
Dec(
const std::string& in,
const std::array<uint64_t, 4>& k,
const uint64_t Nr, uint64_t nonce) {
1055 auto J =
GHASH(
state(std::string(
reinterpret_cast<char*
>(&nonce),
sizeof(nonce)), k, Nr), H);
1058 auto cipher_state =
state(in, k, Nr);
1059 auto hash = cipher_state.get_arrays().back();
1060 cipher_state.get_arrays().pop_back();
1063 hash =
GCTR(
state({hash}, k, Nr), J).get_arrays()[0];
1067 if (hash.unravel() !=
GHASH(cipher_state, H).unravel()) {
1068 throw std::runtime_error(
"Message does not match! Refusing to decrypt!");
The state array is a 4x4 byte matrix to which AES operations are performed; also called a block.
Definition aes.h:248
void ShiftRows()
Cyclically shift the bytes in each row.
Definition aes.h:488
void InvShiftRows()
Invert the cyclical shift in ShiftRows()
Definition aes.h:533
void AddRoundKey(const uint64_t &round, const std::vector< uint32_t > &keys)
Add the round key.
Definition aes.h:396
state_array(const std::string &in, size_t &x)
Initialize a state_array from a string.
Definition aes.h:263
void MixColumns()
Transform each column by a single, fixed matrix.
Definition aes.h:560
void InvMixColumns()
Inverts the column transformation.
Definition aes.h:587
std::string unravel() const
Unravel the state_array back into a string.
Definition aes.h:379
void InvSubBytes()
: Invert the SubBytes step of AES.
Definition aes.h:459
void SubBytes()
A invertible, non-linear transformation of the state.
Definition aes.h:419
An arbitrary collection of state arrays.
Definition aes.h:615
std::string unravel() const
Unravel a state into a character string.
Definition aes.h:678
void AddRoundKey(const uint64_t &round)
Definition aes.h:691
state GCTR(state s, state_array ICB)
Apply AES-CTR to a message.
Definition aes.h:979
std::string Dec(const std::string &in, const std::array< uint64_t, 4 > &k, const uint64_t Nr, uint64_t nonce)
Decrypt a message with AES-GCM.
Definition aes.h:1049
state_array mult(const state_array &X, const state_array &Y)
Perform a multiplication on two blocks of data.
Definition aes.h:888
void increment(state_array &X)
The Nonce Increment Function.
Definition aes.h:828
state_array GHASH(const state &X, const state_array &H)
Calculate the GHASH for a state.
Definition aes.h:956
uint8_t mult(uint8_t a, uint8_t b)
Multiply two bytes in GA(256)
Definition aes.h:49
uint8_t inverse(uint8_t a)
Find the Multiplicative Inverse of a byte in GF(2**8)
Definition aes.h:106
uint32_t Rcon[10]
The round constants.
Definition aes.h:130
uint32_t RotWord(const uint32_t &word)
Rotate a word by one byte left.
Definition aes.h:142
uint32_t SubWord(const uint32_t &word)
Substitue the bytes in a key-schedule word.
Definition aes.h:152
std::vector< uint32_t > Expansion(const std::array< uint64_t, 4 > &key, const uint64_t &Nk)
Expand a set of keys.
Definition aes.h:193
The namespace containing AES encryption/decryption functions.
Definition aes.h:34
std::string InvCipher(const std::string &in, const std::array< uint64_t, 4 > &k, const uint64_t &Nr)
Decrypt a message with AES.
Definition aes.h:744
std::string Ctr(const std::string &in, const std::array< uint64_t, 4 > &k, const uint64_t Nr, uint64_t nonce)
An implementation of AES in CTR mode.
Definition aes.h:776
std::string Cipher(const std::string &in, const std::array< uint64_t, 4 > &k, const uint64_t &Nr)
Encrypt a message with AES.
Definition aes.h:716