From 3ff595e5e812624bf786672592646bf68b6677f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20V=C3=B6gele?= Date: Sun, 14 Jul 2019 02:13:37 +0200 Subject: [PATCH] Initial --- aes.cpp | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++ aes.hpp | 29 ++++++++ main.cpp | 131 ++++++++++++++++++++++++++++++++++ meson.build | 3 + types.cpp | 29 ++++++++ types.hpp | 28 ++++++++ 6 files changed, 418 insertions(+) create mode 100644 aes.cpp create mode 100644 aes.hpp create mode 100644 main.cpp create mode 100644 meson.build create mode 100644 types.cpp create mode 100644 types.hpp diff --git a/aes.cpp b/aes.cpp new file mode 100644 index 0000000..a0e4380 --- /dev/null +++ b/aes.cpp @@ -0,0 +1,198 @@ +#include "aes.hpp" + +#include +#include + +const uint8_t AES::irreducible_polynomial = 0x1b; + +const uint8_t AES::sbox[256] = { + 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 }; + +const uint8_t AES::inv_sbox[256] = { + 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 }; + +const uint8_t AES::shiftrows_targets[16] = {0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11}; + +const uint8_t AES::rc[10] = { + 0b00000001, + 0b00000010, + 0b00000100, + 0b00001000, + 0b00010000, + 0b00100000, + 0b01000000, + 0b10000000, + 0x1b, + 0x1b << 1 +}; + +void AES::print_data(uint8_t data[16]) +{ + for (int i = 0;i < 16;i++) + { + std::cout << std::hex << (int) data[i] << " "; + } + std::cout << std::endl; +} + +void AES::encrypt_ecb(uint8_t data[16], const uint8_t key[16]) +{ + uint8_t round_keys[11][16]; + construct_round_keys(key, round_keys); + add_round_key(data, round_keys[0]); + for (int r = 1;r < 10;r++) + { + sub_bytes(data); + shift_rows(data); + mix_columns(data); + add_round_key(data, round_keys[r]); + } + sub_bytes(data); + shift_rows(data); + add_round_key(data, round_keys[10]); +} + +void AES::add_round_key(uint8_t data_[16], const uint8_t key_[16]) +{ + const uint32_t (&key)[4] = *reinterpret_cast(key_); + uint32_t (&data)[4] = *reinterpret_cast(data_); + for (int i = 0;i < 4;i++) + { + data[i] ^= key[i]; + } +} + +void AES::sub_bytes(uint8_t data[16]) +{ + for (int i = 0;i < 16;i++) + { + data[i] = sbox[data[i]]; + } +} + +#define SWAP(x, y, tmp) tmp = x; x = y; y = tmp + +void AES::shift_rows(uint8_t data[16]) +{ + uint8_t tmp = data[1]; + data[1] = data[5]; + data[5] = data[9]; + data[9] = data[13]; + data[13] = tmp; + + SWAP(data[2], data[10], tmp); + SWAP(data[6], data[14], tmp); + + tmp = data[15]; + data[15] = data[11]; + data[11] = data[7]; + data[7] = data[3]; + data[3] = tmp; +} + +#undef SWAP + +void AES::mix_columns(uint8_t data[16]) +{ + uint8_t data_new[16]; + for (int i = 0;i < 4;i++) + { + data_new[i * 4 + 0] = gf_mult2(data[i * 4 + 0]) ^ gf_mult3(data[i * 4 + 1]) ^ data[i * 4 + 2] ^ data[i * 4 + 3]; + data_new[i * 4 + 1] = data[i * 4 + 0] ^ gf_mult2(data[i * 4 + 1]) ^ gf_mult3(data[i * 4 + 2]) ^ data[i * 4 + 3]; + data_new[i * 4 + 2] = data[i * 4 + 0] ^ data[i * 4 + 1] ^ gf_mult2(data[i * 4 + 2]) ^ gf_mult3(data[i * 4 + 3]); + data_new[i * 4 + 3] = gf_mult3(data[i * 4 + 0]) ^ data[i * 4 + 1] ^ data[i * 4 + 2] ^ gf_mult2(data[i * 4 + 3]); + } + memcpy(data, data_new, 16); +} + +void AES::mix_column(uint8_t data[4]) +{ + uint8_t data_new[4]; + data_new[0] = gf_mult2(data[0]) ^ gf_mult3(data[1]) ^ data[2] ^ data[3]; + data_new[1] = data[0] ^ gf_mult2(data[1]) ^ gf_mult3(data[2]) ^ data[3]; + data_new[2] = data[0] ^ data[1] ^ gf_mult2(data[2]) ^ gf_mult3(data[3]); + data_new[3] = gf_mult3(data[0]) ^ data[1] ^ data[2] ^ gf_mult2(data[3]); + memcpy(data, data_new, 4); +} + +void AES::construct_round_keys(const uint8_t initial_key_[16], uint8_t round_keys_[11][16]) +{ + const uint32_t (&initial_key)[4] = *reinterpret_cast(initial_key_); + uint32_t (&round_keys)[11][4] = *reinterpret_cast(round_keys_); + for (int k = 0;k < 4;k++) + { + round_keys[0][k] = initial_key[k]; + } + for (int r = 1;r < 11;r++) + { + round_keys[r][0] = round_keys[r - 1][0] ^ roundkey_g(round_keys[r - 1][3], r - 1); + round_keys[r][1] = round_keys[r][0] ^ round_keys[r - 1][1]; + round_keys[r][2] = round_keys[r][1] ^ round_keys[r - 1][2]; + round_keys[r][3] = round_keys[r][2] ^ round_keys[r - 1][3]; + } +} + +uint32_t AES::roundkey_g(uint32_t last_roundkey, uint8_t round) +{ + uint32_t result; + uint8_t *last = (uint8_t*) &last_roundkey; + uint8_t *next = (uint8_t*) &result; + next[3] = sbox[last[0]]; + next[0] = sbox[last[1]] ^ rc[round]; // TODO Check round + next[1] = sbox[last[2]]; + next[2] = sbox[last[3]]; + return result; +} + +uint8_t AES::gf_reduce(uint8_t value) +{ + return value ^ irreducible_polynomial; +} + +uint8_t AES::gf_mult2(uint8_t value) +{ + uint16_t result = ((uint16_t) value) << 1; + if ((result & 0x100) == 0) + { + return (uint8_t) result; + } + else + { + return gf_reduce(result); + } +} + +uint8_t AES::gf_mult3(uint8_t value) +{ + return gf_mult2(value) ^ value; +} diff --git a/aes.hpp b/aes.hpp new file mode 100644 index 0000000..0e38af2 --- /dev/null +++ b/aes.hpp @@ -0,0 +1,29 @@ +#ifndef AES_HPP_ +#define AES_HPP_ + +#include + +class AES +{ +public: + static const uint8_t shiftrows_targets[16]; + static const uint8_t sbox[256]; + static const uint8_t inv_sbox[256]; + static const uint8_t rc[10]; + static const uint8_t irreducible_polynomial; + AES(); + static void encrypt_ecb(uint8_t data[16], const uint8_t key[16]); + static void construct_round_keys(const uint8_t initial_key_[16], uint8_t round_keys_[11][16]); + static uint32_t roundkey_g(uint32_t last_roundkey, uint8_t round); + static void add_round_key(uint8_t data[16], const uint8_t key[16]); + static void shift_rows(uint8_t data[16]); + static void sub_bytes(uint8_t data[16]); + static void mix_columns(uint8_t data[16]); + static void mix_column(uint8_t data[4]); + static void print_data(uint8_t data[16]); + static uint8_t gf_mult2(uint8_t value); + static uint8_t gf_mult3(uint8_t value); + static uint8_t gf_reduce(uint8_t value); +}; + +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..784f15a --- /dev/null +++ b/main.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +#include "types.hpp" +#include "aes.hpp" + +const int no_traces = 10'000; + +using namespace std; + +char read_char(istream &stream) +{ + char buf; + stream.get(buf); + return buf; +} + +traces_vector_t load_traces() +{ + traces_vector_t traces(no_traces, trace()); + //ifstream plaintexts("plaintexts.dat", ios::binary); + ifstream ciphertexts("ciphertexts.dat", ios::binary); + ifstream faultytexts("faultytexts.dat", ios::binary); + for (int trace_no = 0;trace_no < no_traces;trace_no++) + { + trace ¤t_trace = traces[trace_no]; + for (int i = 0;i < 16;i++) + { + //current_trace.plaintext[i] = read_char(plaintexts); + current_trace.ciphertext[i] = read_char(ciphertexts); + current_trace.faultytext[i] = read_char(faultytexts); + } + } + if (!ciphertexts.good() || !ciphertexts.good()) + { + cout << "IO ERROR"; + exit(1); + } + return traces; +} + +int main(int argc, char **argv) +{ + const int faultpos = 1; + traces_vector_t traces = load_traces(); + aes_col_vector_t deltas = aes_col_vector_t(256, aes_col()); + for (int i = 0;i < 256;i++) + { + deltas[i].column[faultpos] = i; + AES::mix_column(deltas[i].column); + } + + aes_col key; + set candidates; + for (int i = 0;i < no_traces;i++) + { + cout << i; + cout.flush(); + set round_candidates; + for (int k0 = 0;k0 < 256;k0++) + { + for (int k1 = 0;k1 < 256;k1++) + { + for (int k2 = 0;k2 < 256;k2++) + { + for (int k3 = 0;k3 < 256;k3++) + { + key.column[0] = k0; + key.column[1] = k1; + key.column[2] = k2; + key.column[3] = k3; + aes_col diff; + trace current = traces[i]; + AES::shift_rows(current.ciphertext); + AES::shift_rows(current.faultytext); + for (int j = 0;j < 4;j++) + { + current.ciphertext[j] = AES::inv_sbox[current.ciphertext[j] ^ key.column[j]]; + current.faultytext[j] = AES::inv_sbox[current.faultytext[j] ^ key.column[j]]; + diff.column[j] = current.ciphertext[j] ^ current.faultytext[j]; + } + for (int delta = 0;delta < 256;delta++) + { + if (diff == deltas[delta]) + { + round_candidates.insert(key); + break; + } + } + } + } + } + } + if (i == 0) + { + candidates = round_candidates; + } + else + { + set intersection; + set_intersection(candidates.begin(), candidates.end(), round_candidates.begin(), round_candidates.end(), std::inserter(intersection, intersection.begin())); + candidates = intersection; + } + + if (candidates.size() == 1) + { + cout << endl; + break; + } + else if (candidates.size() == 0) + { + cout << endl << "Error!" << endl; + break; + } + else + { + cout << " -> " << candidates.size() << endl; + } + } + + cout << "Key: "; + key = *candidates.begin(); + for (int i = 0; i < 4;i++) + { + cout << key.column[i] << " "; + } + cout << endl; + return 0; +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..7b65598 --- /dev/null +++ b/meson.build @@ -0,0 +1,3 @@ +project('PhyAtt10', 'cpp') +executable('PhyAtt10', 'main.cpp', 'aes.cpp', 'types.cpp') + diff --git a/types.cpp b/types.cpp new file mode 100644 index 0000000..4be93ff --- /dev/null +++ b/types.cpp @@ -0,0 +1,29 @@ +#include "types.hpp" + +aes_col::aes_col() +{ + this->column[0] = 0; + this->column[1] = 0; + this->column[2] = 0; + this->column[3] = 0; +} + +bool aes_col::operator==(const aes_col &other) const +{ + for (int i = 0;i < 4;i++) + { + if (this->column[i] != other.column[i]) + return false; + } + return true; +} + +bool aes_col::operator<(const aes_col &other) const +{ + for (int i = 0;i < 4;i++) + { + if (this->column[i] < other.column[i]) + return true; + } + return false; +} diff --git a/types.hpp b/types.hpp new file mode 100644 index 0000000..9ea4547 --- /dev/null +++ b/types.hpp @@ -0,0 +1,28 @@ +#ifndef TYPES_HPP_ +#define TYPES_HPP_ + +#include +#include + +class trace +{ +public: + //uint8_t plaintext[16]; + uint8_t ciphertext[16]; + uint8_t faultytext[16]; +}; + +class aes_col +{ +public: + uint8_t column[4]; + aes_col(); + bool operator==(const aes_col &) const; + bool operator<(const aes_col &) const; +}; + +typedef std::vector traces_vector_t; +typedef std::vector aes_col_vector_t; +typedef std::vector aes_col_matrix_t; + +#endif