Kurz mit der Umsetzung der AES 128 EZB

Wenn Sie den 'aes 128 ecb mode' in Yandex fahren, gibt es gute Artikel von den Jungs auf dem "Hub": ein- und zweimal - sinnvoll und gleichzeitig zu detailliert.


Die Geschichte über den Algorithmus in den Bildern ist hier (die auch auf den Links in einem der Artikel der Jungs oben zu finden ist).


Kurz zum Algorithmus: 1) Erstellen Sie ein Objekt mit einem 16-Byte-Status und einem Array von 16-Byte-Schlüsseln. 2) wir schreiben Primitive für ein Objekt (sie sind Transformationen); 3) n-mal laufen (wobei n die Anzahl der Runden ist). Wir machen alle Transformationen symmetrisch - zur Ver- und Entschlüsselung gleichzeitig. Die Entschlüsselung im Sinne des Algorithmus ist im Gegenteil die Verschlüsselung.


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; } 

Zunächst generieren wir nach dem Erstellen die Schlüssel (Infos zu sbox und RCON sind niedriger):


 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)); } } 

Wir schreiben Primitive (sie sind Transformationen). Die Transformation erhöht die Komplexität des Status, sodass er gesichert ist.


 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]; } } 

Plus eine weitere Transformation (Informationen zu den Bytes 0xe, 0x2 ... entnehmen wir dem obigen Artikel):


 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 }); } } } 

Eigentlich sind die Algorithmen:


 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; } 

Dienstprogramme:


 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>()); } 

Konstanten:


 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" }}; 

Referenzen:


  1. https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
  2. http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html

Source: https://habr.com/ru/post/de451830/


All Articles