Jika Anda mengarahkan 'aes 128 ecb mode' ke Yandex, akan ada artikel bagus oleh orang-orang di "hub": sekali dan dua kali - masuk akal dan pada saat yang sama terlalu rinci.
Kisah tentang algoritma dalam gambar ada di sini (yang juga dapat ditemukan di tautan di salah satu artikel cowok di atas).
Secara singkat tentang algoritma: 1) membuat objek dengan keadaan 16-byte dan array kunci 16-byte; 2) kami menulis primitif untuk objek (mereka adalah transformasi); 3) jalankan n kali (di mana n adalah jumlah putaran). Kami membuat semua transformasi simetris - untuk enkripsi dan dekripsi pada saat yang bersamaan. Dekripsi dalam hal algoritma adalah enkripsi sebaliknya.
Struktur:
using byte_t = unsigned char; struct aes128 { aes128(const std::string& text, const std::string& cipher, bool decrypt = false) : state({begin(text), end(text)}), keys({{begin(cipher), end(cipher)}}), decrypt(decrypt) {} aes128() = default; aes128(const aes128&) = default; std::vector<byte_t> state; std::vector<std::vector<byte_t>> keys; bool decrypt; }
Pertama-tama, setelah membuat, kami membuat kunci (INFA tentang sbox dan RCON akan lebih rendah):
void key_expansion() { for (int j = 1; j != 11; j++) { // for 11 rounds std::vector<byte_t> key = keys[j-1]; std::vector<byte_t> column = {key[13], key[14], key[15], key[12]}; // rotation for (auto& x: column) x = sbox(x); column[0] ^= RCON[j]; std::transform(begin(column), end(column), begin(key), begin(key), std::bit_xor<byte_t>()); std::transform(begin(key)+4, end(key), begin(key), begin(key)+4, std::bit_xor<byte_t>()); keys.emplace_back(std::move(key)); } }
Kami menulis primitif (mereka adalah transformasi). Transformasi menambah kompleksitas untuk dinyatakan sehingga diamankan.
void add_round_key(int r) { std::transform(begin(keys[r]), end(keys[r]), begin(state), begin(state), std::bit_xor<byte_t>()); } void substitute_bytes() { std::transform(begin(state), end(state), begin(state), [&](byte_t x) { return sbox(x, decrypt); }); } void shift_rows() { int k = decrypt ? 3 : 1; // coef for rotation point for (int i = 1; i != 4; ++i) shift_row({state[i], state[4+i], state[8+i], state[12+i]}, (k*i) % 4, i); } void shift_row(std::array<byte_t, 4>&& row, int k, int j) { std::rotate(begin(row), begin(row)+k, end(row)); for (int i = 0; i != 4; ++i) { state[i*4+j] = row[i]; } }
Ditambah satu transformasi lagi (info tentang byte 0xe, 0x2 ... kami ambil dari artikel orang di atas):
void mix_columns() { for (int i = 0; i != 4; i++) { const std::array<byte_t, 4> column = {state[i*4], state[i*4+1], state[i*4+2], state[i*4+3]}; if (!decrypt) { state[i*4] = vector_mult(column, { 0x2, 0x3, 0x1, 0x1 }); state[i*4+1] = vector_mult(column, { 0x1, 0x2, 0x3, 0x1 }); state[i*4+2] = vector_mult(column, { 0x1, 0x1, 0x2, 0x3 }); state[i*4+3] = vector_mult(column, { 0x3, 0x1, 0x1, 0x2 }); } else { state[i*4] = vector_mult(column, { 0xe, 0xb, 0xd, 0x9 }); state[i*4+1] = vector_mult(column, { 0x9, 0xe, 0xb, 0xd }); state[i*4+2] = vector_mult(column, { 0xd, 0x9, 0xe, 0xb }); state[i*4+3] = vector_mult(column, { 0xb, 0xd, 0x9, 0xe }); } } }
Sebenarnya, algoritma:
aes128 encrypt(const std::string& text, const std::string& cipher) { aes128 aes(text, cipher); aes.key_expansion(); aes.add_round_key(0); for (int i = 1; i != 10; i++) { aes.substitute_bytes(); aes.shift_rows(); aes.mix_columns(); aes.add_round_key(i); } aes.substitute_bytes(); aes.shift_rows(); aes.add_round_key(10); return aes; } template <typename I> aes128 decrypt(I first, I last, const std::string& cipher) { aes128 aes({first, last}, cipher, true); aes.key_expansion(); aes.add_round_key(10); aes.shift_rows(); aes.substitute_bytes(); for (int i = 9; i != 0; --i) { aes.add_round_key(i); aes.mix_columns(); aes.shift_rows(); aes.substitute_bytes(); } aes.add_round_key(0); return aes; }
Utilitas:
byte_t hex(char ch) { return (ch - '0') % 39; } byte_t sbox(byte_t x, bool decrypt = false) { std::string s = (decrypt ? INV_SBOX : SBOX)[x >> 4][x & 15]; return hex(s[0]) << 4 | hex(s[1]); } byte_t mult_by_2(byte_t x) { return (x < 128) ? x << 1 : (x << 1 & 0xff) ^ 0x1b; } byte_t mult_by_8(byte_t x) { return mult_by_2(mult_by_2(mult_by_2(x))); } const std::unordered_map<byte_t, std::function<byte_t(byte_t)>> mapper = { {0x1, [](byte_t x) { return x; }}, {0x2, mult_by_2}, {0x3, [](byte_t x) { return mult_by_2(x) ^ x; }}, {0x9, [](byte_t x) { return mult_by_8(x) ^ x; }}, {0xb, [](byte_t x) { return mult_by_8(x) ^ mult_by_2(x) ^ x; }}, {0xd, [](byte_t x) { return mult_by_8(x) ^ mult_by_2(mult_by_2(x)) ^ x; }}, {0xe, [](byte_t x) { return mult_by_8(x) ^ mult_by_2(mult_by_2(x)) ^ mult_by_2(x); }}, }; byte_t vector_mult(const std::array<byte_t, 4>& v1, std::array<byte_t, 4>&& v2) { std::transform(begin(v1), end(v1), begin(v2), begin(v2), [](byte_t x, byte_t y) { return mapper.at(y)(x); }); return std::accumulate(begin(v2), end(v2), byte_t(0), std::bit_xor<byte_t>()); }
Konstanta:
const std::vector<std::vector<std::string>> SBOX = { { "63", "7c", "77", "7b", "f2", "6b", "6f", "c5", "30", "01", "67", "2b", "fe", "d7", "ab", "76" }, { "ca", "82", "c9", "7d", "fa", "59", "47", "f0", "ad", "d4", "a2", "af", "9c", "a4", "72", "c0" }, { "b7", "fd", "93", "26", "36", "3f", "f7", "cc", "34", "a5", "e5", "f1", "71", "d8", "31", "15" }, { "04", "c7", "23", "c3", "18", "96", "05", "9a", "07", "12", "80", "e2", "eb", "27", "b2", "75" }, { "09", "83", "2c", "1a", "1b", "6e", "5a", "a0", "52", "3b", "d6", "b3", "29", "e3", "2f", "84" }, { "53", "d1", "00", "ed", "20", "fc", "b1", "5b", "6a", "cb", "be", "39", "4a", "4c", "58", "cf" }, { "d0", "ef", "aa", "fb", "43", "4d", "33", "85", "45", "f9", "02", "7f", "50", "3c", "9f", "a8" }, { "51", "a3", "40", "8f", "92", "9d", "38", "f5", "bc", "b6", "da", "21", "10", "ff", "f3", "d2" }, { "cd", "0c", "13", "ec", "5f", "97", "44", "17", "c4", "a7", "7e", "3d", "64", "5d", "19", "73" }, { "60", "81", "4f", "dc", "22", "2a", "90", "88", "46", "ee", "b8", "14", "de", "5e", "0b", "db" }, { "e0", "32", "3a", "0a", "49", "06", "24", "5c", "c2", "d3", "ac", "62", "91", "95", "e4", "79" }, { "e7", "c8", "37", "6d", "8d", "d5", "4e", "a9", "6c", "56", "f4", "ea", "65", "7a", "ae", "08" }, { "ba", "78", "25", "2e", "1c", "a6", "b4", "c6", "e8", "dd", "74", "1f", "4b", "bd", "8b", "8a" }, { "70", "3e", "b5", "66", "48", "03", "f6", "0e", "61", "35", "57", "b9", "86", "c1", "1d", "9e" }, { "e1", "f8", "98", "11", "69", "d9", "8e", "94", "9b", "1e", "87", "e9", "ce", "55", "28", "df" }, { "8c", "a1", "89", "0d", "bf", "e6", "42", "68", "41", "99", "2d", "0f", "b0", "54", "bb", "16" }}; const std::vector<int> RCON = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 }; // ten rounds const std::vector<std::vector<std::string>> INV_SBOX = { { "52", "09", "6a", "d5", "30", "36", "a5", "38", "bf", "40", "a3", "9e", "81", "f3", "d7", "fb" }, { "7c", "e3", "39", "82", "9b", "2f", "ff", "87", "34", "8e", "43", "44", "c4", "de", "e9", "cb" }, { "54", "7b", "94", "32", "a6", "c2", "23", "3d", "ee", "4c", "95", "0b", "42", "fa", "c3", "4e" }, { "08", "2e", "a1", "66", "28", "d9", "24", "b2", "76", "5b", "a2", "49", "6d", "8b", "d1", "25" }, { "72", "f8", "f6", "64", "86", "68", "98", "16", "d4", "a4", "5c", "cc", "5d", "65", "b6", "92" }, { "6c", "70", "48", "50", "fd", "ed", "b9", "da", "5e", "15", "46", "57", "a7", "8d", "9d", "84" }, { "90", "d8", "ab", "00", "8c", "bc", "d3", "0a", "f7", "e4", "58", "05", "b8", "b3", "45", "06" }, { "d0", "2c", "1e", "8f", "ca", "3f", "0f", "02", "c1", "af", "bd", "03", "01", "13", "8a", "6b" }, { "3a", "91", "11", "41", "4f", "67", "dc", "ea", "97", "f2", "cf", "ce", "f0", "b4", "e6", "73" }, { "96", "ac", "74", "22", "e7", "ad", "35", "85", "e2", "f9", "37", "e8", "1c", "75", "df", "6e" }, { "47", "f1", "1a", "71", "1d", "29", "c5", "89", "6f", "b7", "62", "0e", "aa", "18", "be", "1b" }, { "fc", "56", "3e", "4b", "c6", "d2", "79", "20", "9a", "db", "c0", "fe", "78", "cd", "5a", "f4" }, { "1f", "dd", "a8", "33", "88", "07", "c7", "31", "b1", "12", "10", "59", "27", "80", "ec", "5f" }, { "60", "51", "7f", "a9", "19", "b5", "4a", "0d", "2d", "e5", "7a", "9f", "93", "c9", "9c", "ef" }, { "a0", "e0", "3b", "4d", "ae", "2a", "f5", "b0", "c8", "eb", "bb", "3c", "83", "53", "99", "61" }, { "17", "2b", "04", "7e", "ba", "77", "d6", "26", "e1", "69", "14", "63", "55", "21", "0c", "7d" }};
Referensi:
- https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
- http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html