| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| #include "aes.h" |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| int aes_encrypt_block(const unsigned char *plain_text, const unsigned char *key, |
| const int key_len, unsigned char *cipher_text) { |
| int num_rounds = aes_get_num_rounds(key_len); |
| if (num_rounds < 0) { |
| printf("ERROR: aes_get_num_rounds() failed\n"); |
| return -EINVAL; |
| } |
| |
| unsigned char rcon; |
| unsigned char state[16]; |
| unsigned char round_key[16]; |
| unsigned char *full_key = |
| (unsigned char *)malloc(key_len * sizeof(unsigned char)); |
| if (full_key == NULL) { |
| printf("ERROR: malloc() failed\n"); |
| return -ENOMEM; |
| } |
| |
| // init |
| for (int i = 0; i < 16; i++) { |
| state[i] = plain_text[i]; |
| } |
| for (int i = 0; i < key_len; i++) { |
| full_key[i] = key[i]; |
| } |
| for (int i = 0; i < 16; i++) { |
| round_key[i] = full_key[i]; |
| } |
| rcon = 0; |
| |
| // ecnrypt |
| aes_add_round_key(state, round_key); |
| for (int j = 0; j < num_rounds; j++) { |
| aes_sub_bytes(state); |
| aes_shift_rows(state); |
| if (j < (num_rounds - 1)) { |
| aes_mix_columns(state); |
| } |
| aes_key_expand(round_key, full_key, key_len, &rcon, j); |
| aes_add_round_key(state, round_key); |
| } |
| |
| // finish |
| for (int i = 0; i < 16; i++) { |
| cipher_text[i] = state[i]; |
| } |
| |
| free(full_key); |
| |
| return 0; |
| } |
| |
| int aes_decrypt_block(const unsigned char *cipher_text, |
| const unsigned char *key, const int key_len, |
| unsigned char *plain_text) { |
| int num_rounds = aes_get_num_rounds(key_len); |
| if (num_rounds < 0) { |
| printf("ERROR: aes_get_num_rounds() failed\n"); |
| return -EINVAL; |
| } |
| |
| unsigned char rcon; |
| unsigned char state[16]; |
| unsigned char round_key[16]; |
| unsigned char *full_key = |
| (unsigned char *)malloc(key_len * sizeof(unsigned char)); |
| if (full_key == NULL) { |
| printf("ERROR: malloc() failed\n"); |
| return -ENOMEM; |
| } |
| |
| // init |
| for (int i = 0; i < 16; i++) { |
| state[i] = cipher_text[i]; |
| } |
| for (int i = 0; i < key_len; i++) { |
| full_key[i] = key[i]; |
| } |
| for (int i = 0; i < 16; i++) { |
| round_key[i] = full_key[i]; |
| } |
| rcon = 0; |
| |
| // get decryption start key |
| for (int j = 0; j < num_rounds; j++) { |
| aes_key_expand(round_key, full_key, key_len, &rcon, j); |
| } |
| rcon = 0; |
| |
| // decrypt - using Equivalent Inverse Cipher |
| aes_add_round_key(state, round_key); |
| for (int j = 0; j < num_rounds; j++) { |
| aes_inv_sub_bytes(state); |
| aes_inv_shift_rows(state); |
| if (j < (num_rounds - 1)) { |
| aes_inv_mix_columns(state); |
| } |
| aes_inv_key_expand(round_key, full_key, key_len, &rcon, j); |
| if (j < (num_rounds - 1)) { |
| aes_inv_mix_columns(round_key); |
| } |
| aes_add_round_key(state, round_key); |
| } |
| |
| // finish |
| for (int i = 0; i < 16; i++) { |
| plain_text[i] = state[i]; |
| } |
| |
| free(full_key); |
| return 0; |
| } |
| |
| void aes_print_block(const unsigned char *data, const int num_bytes) { |
| for (int i = 0; i < num_bytes; i++) { |
| if ((i > 0) && (i % 8 == 0)) { |
| printf("- "); |
| } |
| printf("%x%x ", data[i] >> 4, data[i] & 0xF); |
| } |
| printf("\n"); |
| |
| return; |
| } |
| |
| int aes_get_num_rounds(int key_len) { |
| int num_rounds = 0; |
| int num_k = key_len / 4; |
| |
| if (num_k == 4) { |
| num_rounds = 10; |
| } else if (num_k == 6) { |
| num_rounds = 12; |
| } else if (num_k == 8) { |
| num_rounds = 14; |
| } else { |
| printf("ERROR: key_len = %i not supported\n", key_len); |
| return -EINVAL; |
| } |
| |
| return num_rounds; |
| } |
| |
| static unsigned char aes_mul2(unsigned char in) { |
| // set individual bits of out |
| unsigned char out = 0x0; |
| |
| // extract bits possible xor shift to right position |
| out |= (((in >> 7) & 0x1)) << 0; |
| out |= (((in >> 0) & 0x1) ^ ((in >> 7) & 0x1)) << 1; |
| out |= (((in >> 1) & 0x1)) << 2; |
| out |= (((in >> 2) & 0x1) ^ ((in >> 7) & 0x1)) << 3; |
| out |= (((in >> 3) & 0x1) ^ ((in >> 7) & 0x1)) << 4; |
| out |= (((in >> 4) & 0x1)) << 5; |
| out |= (((in >> 5) & 0x1)) << 6; |
| out |= (((in >> 6) & 0x1)) << 7; |
| |
| return out; |
| } |
| |
| static unsigned char aes_mul4(unsigned char in) { |
| // return aes_mul2(aes_mul2(in)); |
| |
| // set individual bits of out |
| unsigned char out = 0x0; |
| |
| // extract bits possible xor shift to right position |
| out |= (((in >> 6) & 0x1)) << 0; |
| out |= (((in >> 7) & 0x1) ^ ((in >> 6) & 0x1)) << 1; |
| out |= (((in >> 0) & 0x1) ^ ((in >> 7) & 0x1)) << 2; |
| out |= (((in >> 1) & 0x1) ^ ((in >> 6) & 0x1)) << 3; |
| out |= (((in >> 2) & 0x1) ^ ((in >> 7) & 0x1) ^ ((in >> 6) & 0x1)) << 4; |
| out |= (((in >> 3) & 0x1) ^ ((in >> 7) & 0x1)) << 5; |
| out |= (((in >> 4) & 0x1)) << 6; |
| out |= (((in >> 5) & 0x1)) << 7; |
| |
| return out; |
| } |
| |
| void aes_add_round_key(unsigned char *state, const unsigned char *round_key) { |
| for (int i = 0; i < 16; i++) { |
| state[i] ^= round_key[i]; |
| } |
| |
| return; |
| } |
| |
| void aes_sub_bytes(unsigned char *state) { |
| // substitute |
| for (int i = 0; i < 16; i++) { |
| state[i] = sbox[state[i]]; |
| } |
| |
| return; |
| } |
| |
| void aes_inv_sub_bytes(unsigned char *state) { |
| // substitute |
| for (int i = 0; i < 16; i++) { |
| state[i] = inv_sbox[state[i]]; |
| } |
| |
| return; |
| } |
| |
| void aes_shift_rows(unsigned char *state) { |
| unsigned char temp[16]; |
| |
| // copy state to temp |
| for (int i = 0; i < 16; i++) { |
| temp[i] = state[i]; |
| } |
| |
| // extract state from temp |
| // Row 1 |
| state[1] = temp[5]; |
| state[5] = temp[9]; |
| state[9] = temp[13]; |
| state[13] = temp[1]; |
| |
| // Row 2 |
| state[2] = temp[10]; |
| state[6] = temp[14]; |
| state[10] = temp[2]; |
| state[14] = temp[6]; |
| |
| // Row 3 |
| state[3] = temp[15]; |
| state[7] = temp[3]; |
| state[11] = temp[7]; |
| state[15] = temp[11]; |
| |
| return; |
| } |
| |
| void aes_inv_shift_rows(unsigned char *state) { |
| unsigned char temp[16]; |
| |
| // copy state to temp |
| for (int i = 0; i < 16; i++) { |
| temp[i] = state[i]; |
| } |
| |
| // extract state from temp |
| // Row 1 |
| state[1] = temp[13]; |
| state[5] = temp[1]; |
| state[9] = temp[5]; |
| state[13] = temp[9]; |
| |
| // Row 2 -> same as for encryption |
| state[2] = temp[10]; |
| state[6] = temp[14]; |
| state[10] = temp[2]; |
| state[14] = temp[6]; |
| |
| // Row 3 |
| state[3] = temp[7]; |
| state[7] = temp[11]; |
| state[11] = temp[15]; |
| state[15] = temp[3]; |
| |
| return; |
| } |
| |
| void aes_mix_columns(unsigned char *state) { |
| unsigned char temp[16]; |
| |
| // copy state to temp |
| for (int i = 0; i < 16; i++) { |
| temp[i] = state[i]; |
| } |
| |
| // do the matrix mul column by column |
| unsigned char x3, x2, x1, x0; |
| for (int j = 0; j < 4; j++) { |
| // see satoh_compact_2001.pdf |
| |
| x3 = temp[0 + j * 4] ^ temp[1 + j * 4]; |
| x2 = temp[1 + j * 4] ^ temp[2 + j * 4]; |
| x1 = temp[2 + j * 4] ^ temp[3 + j * 4]; |
| x0 = temp[3 + j * 4] ^ temp[0 + j * 4]; |
| |
| state[0 + j * 4] = aes_mul2(x3) ^ x1 ^ temp[1 + j * 4]; |
| state[1 + j * 4] = aes_mul2(x2) ^ x1 ^ temp[0 + j * 4]; |
| state[2 + j * 4] = aes_mul2(x1) ^ x3 ^ temp[3 + j * 4]; |
| state[3 + j * 4] = aes_mul2(x0) ^ x3 ^ temp[2 + j * 4]; |
| } |
| |
| return; |
| } |
| |
| void aes_inv_mix_columns(unsigned char *state) { |
| unsigned char temp[16]; |
| |
| // copy state to temp |
| for (int i = 0; i < 16; i++) { |
| temp[i] = state[i]; |
| } |
| |
| // do the matrix mul column by column |
| unsigned char x3, x2, x1, x0; |
| unsigned char y2, y1, y0, z1, z0; |
| for (int j = 0; j < 4; j++) { |
| // see satoh_compact_2001.pdf |
| |
| // first step equal to encryption |
| x3 = temp[0 + j * 4] ^ temp[1 + j * 4]; |
| x2 = temp[1 + j * 4] ^ temp[2 + j * 4]; |
| x1 = temp[2 + j * 4] ^ temp[3 + j * 4]; |
| x0 = temp[3 + j * 4] ^ temp[0 + j * 4]; |
| |
| state[0 + j * 4] = aes_mul2(x3) ^ x1 ^ temp[1 + j * 4]; |
| state[1 + j * 4] = aes_mul2(x2) ^ x1 ^ temp[0 + j * 4]; |
| state[2 + j * 4] = aes_mul2(x1) ^ x3 ^ temp[3 + j * 4]; |
| state[3 + j * 4] = aes_mul2(x0) ^ x3 ^ temp[2 + j * 4]; |
| |
| // second & third step |
| y0 = aes_mul4(temp[1 + j * 4] ^ temp[3 + j * 4]); |
| y1 = aes_mul4(temp[0 + j * 4] ^ temp[2 + j * 4]); |
| y2 = aes_mul2(y1 ^ y0); |
| |
| z0 = y2 ^ y0; |
| z1 = y2 ^ y1; |
| |
| state[0 + j * 4] ^= z1; |
| state[1 + j * 4] ^= z0; |
| state[2 + j * 4] ^= z1; |
| state[3 + j * 4] ^= z0; |
| } |
| |
| return; |
| } |
| |
| void aes_key_expand(unsigned char *round_key, unsigned char *key, int key_len, |
| unsigned char *rcon, int rnd) { |
| // NOTE: The "words" of the key corresponds to columns of the key matrix, |
| // i.e., word w[0] = [k[0], k[1], k[2], k[3]] |
| |
| // NOTE: round_key is the Nb words key used in the next round, |
| // key is the KEY_LEN last key bytes used to compute the new round key |
| // for key_len == 16, key == round_key |
| |
| unsigned char temp[4]; |
| unsigned char *old_key; |
| old_key = (unsigned char *)malloc(key_len * sizeof(unsigned char)); |
| if (!old_key) { |
| printf("ERROR: malloc() failed."); |
| } |
| |
| // copy key to temp |
| for (int i = 0; i < key_len; i++) { |
| old_key[i] = key[i]; |
| } |
| |
| if (key_len == 16) { |
| // shift last word |
| temp[0] = old_key[13]; |
| temp[1] = old_key[14]; |
| temp[2] = old_key[15]; |
| temp[3] = old_key[12]; |
| |
| // sub bytes in last word |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_next(rcon); |
| |
| // get new words |
| // Word 0 |
| key[0] = temp[0] ^ old_key[0] ^ *rcon; |
| key[1] = temp[1] ^ old_key[1]; |
| key[2] = temp[2] ^ old_key[2]; |
| key[3] = temp[3] ^ old_key[3]; |
| |
| // Word 1 - 3 |
| for (int i = 1; i < 4; i++) { |
| key[0 + 4 * i] = key[0 + 4 * (i - 1)] ^ old_key[0 + 4 * i]; |
| key[1 + 4 * i] = key[1 + 4 * (i - 1)] ^ old_key[1 + 4 * i]; |
| key[2 + 4 * i] = key[2 + 4 * (i - 1)] ^ old_key[2 + 4 * i]; |
| key[3 + 4 * i] = key[3 + 4 * (i - 1)] ^ old_key[3 + 4 * i]; |
| } |
| } else if (key_len == 24) { |
| // determine shift (in bytes) and amount of key bytes to take over |
| int shift, take; |
| if (rnd == 0) { |
| shift = 8; |
| take = 16; |
| } else { |
| shift = 16; |
| take = 8; |
| } |
| |
| // copy to key what won't be changed in this round |
| for (int i = 0; i < take; i++) { |
| key[i] = old_key[shift + i]; |
| } |
| |
| // compute new bytes/words - there are four different cases: |
| // 1. Word 6*, 7: w/ RotWord, SubWord, Rcon - rnd 0 |
| // 2. Word 8, 9, 10, 11: - rnd 1, 4, 7, 10 |
| // 3. Word 12*, 13, 14, 15: w/ Rotword, SubWord, Rcon - rnd 2, 5, 8, 11 |
| // 4. Word 16, 17, 18*, 19: w/ RotWord, SubWord, Rcon - rnd 3, 6, 9 |
| if (rnd == 0) { |
| // RotWord |
| temp[0] = old_key[21]; |
| temp[1] = old_key[22]; |
| temp[2] = old_key[23]; |
| temp[3] = old_key[20]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_next(rcon); |
| |
| // Word 6 |
| key[16] = old_key[0] ^ temp[0] ^ *rcon; |
| key[17] = old_key[1] ^ temp[1]; |
| key[18] = old_key[2] ^ temp[2]; |
| key[19] = old_key[3] ^ temp[3]; |
| |
| // Word 7 |
| key[20] = old_key[4] ^ key[16]; |
| key[21] = old_key[5] ^ key[17]; |
| key[22] = old_key[6] ^ key[18]; |
| key[23] = old_key[7] ^ key[19]; |
| } else if (rnd == 1 || rnd == 4 || rnd == 7 || rnd == 10) { |
| // Word 8 |
| key[8] = old_key[0] ^ key[4]; // key[4] == old_key[20] |
| key[9] = old_key[1] ^ key[5]; // key[5] == old_key[21] |
| key[10] = old_key[2] ^ key[6]; // key[6] == old_key[22] |
| key[11] = old_key[3] ^ key[7]; // key[7] == old_key[23] |
| |
| // Word 9 |
| key[12] = old_key[4] ^ key[8]; |
| key[13] = old_key[5] ^ key[9]; |
| key[14] = old_key[6] ^ key[10]; |
| key[15] = old_key[7] ^ key[11]; |
| |
| // Word 10 |
| key[16] = old_key[8] ^ key[12]; |
| key[17] = old_key[9] ^ key[13]; |
| key[18] = old_key[10] ^ key[14]; |
| key[19] = old_key[11] ^ key[15]; |
| |
| // Word 11 |
| key[20] = old_key[12] ^ key[16]; |
| key[21] = old_key[13] ^ key[17]; |
| key[22] = old_key[14] ^ key[18]; |
| key[23] = old_key[15] ^ key[19]; |
| } else if (rnd == 2 || rnd == 5 || rnd == 8 || rnd == 11) { |
| // RotWord |
| temp[0] = old_key[21]; |
| temp[1] = old_key[22]; |
| temp[2] = old_key[23]; |
| temp[3] = old_key[20]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_next(rcon); |
| |
| // Word 12 |
| key[8] = old_key[0] ^ temp[0] ^ *rcon; |
| key[9] = old_key[1] ^ temp[1]; |
| key[10] = old_key[2] ^ temp[2]; |
| key[11] = old_key[3] ^ temp[3]; |
| |
| // Word 13 |
| key[12] = old_key[4] ^ key[8]; |
| key[13] = old_key[5] ^ key[9]; |
| key[14] = old_key[6] ^ key[10]; |
| key[15] = old_key[7] ^ key[11]; |
| |
| // Word 14 |
| key[16] = old_key[8] ^ key[12]; |
| key[17] = old_key[9] ^ key[13]; |
| key[18] = old_key[10] ^ key[14]; |
| key[19] = old_key[11] ^ key[15]; |
| |
| // Word 15 |
| key[20] = old_key[12] ^ key[16]; |
| key[21] = old_key[13] ^ key[17]; |
| key[22] = old_key[14] ^ key[18]; |
| key[23] = old_key[15] ^ key[19]; |
| } else { // (rnd == 3 || rnd == 6 || rnd == 9 || rnd == 12) |
| |
| // Word 16 |
| key[8] = old_key[0] ^ key[4]; // key[4] == old_key[20] |
| key[9] = old_key[1] ^ key[5]; // key[5] == old_key[21] |
| key[10] = old_key[2] ^ key[6]; // key[6] == old_key[22] |
| key[11] = old_key[3] ^ key[7]; // key[7] == old_key[23] |
| |
| // Word 17 |
| key[12] = old_key[4] ^ key[8]; |
| key[13] = old_key[5] ^ key[9]; |
| key[14] = old_key[6] ^ key[10]; |
| key[15] = old_key[7] ^ key[11]; |
| |
| // RotWord |
| temp[0] = key[13]; |
| temp[1] = key[14]; |
| temp[2] = key[15]; |
| temp[3] = key[12]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_next(rcon); |
| |
| // Word 18 |
| key[16] = old_key[8] ^ temp[0] ^ *rcon; |
| key[17] = old_key[9] ^ temp[1]; |
| key[18] = old_key[10] ^ temp[2]; |
| key[19] = old_key[11] ^ temp[3]; |
| |
| // Word 19 |
| key[20] = old_key[12] ^ key[16]; |
| key[21] = old_key[13] ^ key[17]; |
| key[22] = old_key[14] ^ key[18]; |
| key[23] = old_key[15] ^ key[19]; |
| } |
| } else { // key_len == 32 |
| |
| // determine shift (in bytes) and amount of key bytes to take over |
| int shift, take; |
| if (rnd == 0) { |
| shift = 0; |
| take = 32; |
| } else { |
| shift = 16; |
| take = 16; |
| } |
| |
| // copy to key what won't be changed in this round |
| for (int i = 0; i < take; i++) { |
| key[i] = old_key[shift + i]; |
| } |
| |
| // compute new bytes/words - there three two cases |
| // 1. Rnd 0: DO NOTHING YET |
| // 2. Odd rounds: -> RotWord, SubWord, Rcon |
| // 3. Even rounds: -> SubWord only |
| |
| if (rnd == 0) { |
| // NOTHING TO COMPUTE |
| } else if (rnd % 2) { // odd rounds -> SubWord, RotWord, Rcon |
| |
| // RotWord |
| temp[0] = old_key[29]; |
| temp[1] = old_key[30]; |
| temp[2] = old_key[31]; |
| temp[3] = old_key[28]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_next(rcon); |
| |
| // Word 8 |
| key[16] = old_key[0] ^ temp[0] ^ *rcon; |
| key[17] = old_key[1] ^ temp[1]; |
| key[18] = old_key[2] ^ temp[2]; |
| key[19] = old_key[3] ^ temp[3]; |
| |
| // Word 9 |
| key[20] = old_key[4] ^ key[16]; |
| key[21] = old_key[5] ^ key[17]; |
| key[22] = old_key[6] ^ key[18]; |
| key[23] = old_key[7] ^ key[19]; |
| |
| // Word 10 |
| key[24] = old_key[8] ^ key[20]; |
| key[25] = old_key[9] ^ key[21]; |
| key[26] = old_key[10] ^ key[22]; |
| key[27] = old_key[11] ^ key[23]; |
| |
| // Word 11 |
| key[28] = old_key[12] ^ key[24]; |
| key[29] = old_key[13] ^ key[25]; |
| key[30] = old_key[14] ^ key[26]; |
| key[31] = old_key[15] ^ key[27]; |
| } else { // even rounds -> SubWord only |
| |
| // Extract |
| temp[0] = old_key[28]; |
| temp[1] = old_key[29]; |
| temp[2] = old_key[30]; |
| temp[3] = old_key[31]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // Word 8 |
| key[16] = old_key[0] ^ temp[0]; |
| key[17] = old_key[1] ^ temp[1]; |
| key[18] = old_key[2] ^ temp[2]; |
| key[19] = old_key[3] ^ temp[3]; |
| |
| // Word 9 |
| key[20] = old_key[4] ^ key[16]; |
| key[21] = old_key[5] ^ key[17]; |
| key[22] = old_key[6] ^ key[18]; |
| key[23] = old_key[7] ^ key[19]; |
| |
| // Word 10 |
| key[24] = old_key[8] ^ key[20]; |
| key[25] = old_key[9] ^ key[21]; |
| key[26] = old_key[10] ^ key[22]; |
| key[27] = old_key[11] ^ key[23]; |
| |
| // Word 11 |
| key[28] = old_key[12] ^ key[24]; |
| key[29] = old_key[13] ^ key[25]; |
| key[30] = old_key[14] ^ key[26]; |
| key[31] = old_key[15] ^ key[27]; |
| } |
| } |
| |
| // copy 16 last bytes from key to round key |
| for (int i = 0; i < 16; i++) { |
| round_key[i] = key[key_len - 16 + i]; |
| } |
| |
| free(old_key); |
| |
| return; |
| } |
| |
| void aes_inv_key_expand(unsigned char *round_key, unsigned char *key, |
| int key_len, unsigned char *rcon, int rnd) { |
| // NOTE: The "words" of the key corresponds to columns of the key matrix, |
| // i.e., word w[0] = [k[0], k[1], k[2], k[3]] |
| |
| // NOTE: round_key is the Nb words key used in the next round, |
| // key is the KEY_LEN last key bytes used to compute the new round key |
| // for key_len == 16, key == round_key |
| |
| unsigned char temp[4]; |
| unsigned char *old_key; |
| old_key = (unsigned char *)malloc(key_len * sizeof(unsigned char)); |
| if (!old_key) { |
| printf("ERROR: malloc() failed."); |
| } |
| |
| // copy key to temp |
| for (int i = 0; i < key_len; i++) { |
| old_key[i] = key[i]; |
| } |
| |
| if (key_len == 16) { |
| // get Word 3'-1': |
| // Word 3' = Word 2 xor Word 3 |
| // Word 2' = Word 1 xor Word 2 |
| // Word 1' = Word 0 xor Word 1 |
| for (int i = 3; i > 0; i--) { |
| key[0 + 4 * i] = old_key[0 + 4 * (i - 1)] ^ old_key[0 + 4 * i]; |
| key[1 + 4 * i] = old_key[1 + 4 * (i - 1)] ^ old_key[1 + 4 * i]; |
| key[2 + 4 * i] = old_key[2 + 4 * (i - 1)] ^ old_key[2 + 4 * i]; |
| key[3 + 4 * i] = old_key[3 + 4 * (i - 1)] ^ old_key[3 + 4 * i]; |
| } |
| |
| // update rcon |
| aes_rcon_prev(rcon, key_len); |
| |
| // get Word 0': |
| // 1. temp = Word 3' -> shift, aes_inv_sub_bytes |
| // 2. Word 0' = (temp xor Word 0) xor rcon |
| |
| // shift Word 3' |
| temp[0] = key[13]; |
| temp[1] = key[14]; |
| temp[2] = key[15]; |
| temp[3] = key[12]; |
| |
| // sub bytes shifted Word 3' |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // get Word 0': (temp xor Word 0) xor rcon |
| key[0] = temp[0] ^ old_key[0] ^ *rcon; |
| key[1] = temp[1] ^ old_key[1]; |
| key[2] = temp[2] ^ old_key[2]; |
| key[3] = temp[3] ^ old_key[3]; |
| } else if (key_len == 24) { |
| // determine shift (in bytes) and amount of key bytes to take over |
| int shift, take; |
| if (rnd == 0) { |
| shift = 8; |
| take = 16; |
| } else { |
| shift = 16; |
| take = 8; |
| } |
| |
| // copy to key what won't be changed in this round - going backwards |
| for (int i = take + shift - 1; i >= shift; i--) { |
| key[i] = old_key[i - shift]; |
| } |
| |
| // compute new bytes/words - there are four different cases: |
| // 1. Word 44, 45: - rnd 0 |
| // 2. Word 40, 41, 42*, 43: w/ Rotword, SubWord, Rcon - rnd 1, 4, 7, 10 |
| // 3. Word 36*, 37, 38, 39: w/ Rotword, SubWord, Rcon - rnd 2, 5, 8, 11 |
| // 4. Word 32, 33, 34, 35: - rnd 3, 6, 9 |
| if (rnd == 0) { |
| // Word 45 = Word 50 xor Word 51 |
| key[4] = old_key[20] ^ old_key[16]; |
| key[5] = old_key[21] ^ old_key[17]; |
| key[6] = old_key[22] ^ old_key[18]; |
| key[7] = old_key[23] ^ old_key[19]; |
| |
| // Word 44 = Word 49 xor Word 50 |
| key[0] = old_key[16] ^ old_key[12]; |
| key[1] = old_key[17] ^ old_key[13]; |
| key[2] = old_key[18] ^ old_key[14]; |
| key[3] = old_key[19] ^ old_key[15]; |
| } else if (rnd == 1 || rnd == 4 || rnd == 7 || rnd == 10) { |
| // Word 43 |
| key[12] = old_key[20] ^ old_key[16]; |
| key[13] = old_key[21] ^ old_key[17]; |
| key[14] = old_key[22] ^ old_key[18]; |
| key[15] = old_key[23] ^ old_key[19]; |
| |
| // RotWord |
| temp[0] = old_key[13]; |
| temp[1] = old_key[14]; |
| temp[2] = old_key[15]; |
| temp[3] = old_key[12]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_prev(rcon, key_len); |
| |
| // Word 42 |
| key[8] = old_key[16] ^ temp[0] ^ *rcon; |
| key[9] = old_key[17] ^ temp[1]; |
| key[10] = old_key[18] ^ temp[2]; |
| key[11] = old_key[19] ^ temp[3]; |
| |
| // Word 41 |
| key[4] = old_key[12] ^ old_key[8]; |
| key[5] = old_key[13] ^ old_key[9]; |
| key[6] = old_key[14] ^ old_key[10]; |
| key[7] = old_key[15] ^ old_key[11]; |
| |
| // Word 40 |
| key[0] = old_key[8] ^ old_key[4]; |
| key[1] = old_key[9] ^ old_key[5]; |
| key[2] = old_key[10] ^ old_key[6]; |
| key[3] = old_key[11] ^ old_key[7]; |
| } else if (rnd == 2 || rnd == 5 || rnd == 8 || rnd == 11) { |
| // Word 39 |
| key[12] = old_key[20] ^ old_key[16]; |
| key[13] = old_key[21] ^ old_key[17]; |
| key[14] = old_key[22] ^ old_key[18]; |
| key[15] = old_key[23] ^ old_key[19]; |
| |
| // Word 38 |
| key[8] = old_key[16] ^ old_key[12]; |
| key[9] = old_key[17] ^ old_key[13]; |
| key[10] = old_key[18] ^ old_key[14]; |
| key[11] = old_key[19] ^ old_key[15]; |
| |
| // Word 37 |
| key[4] = old_key[12] ^ old_key[8]; |
| key[5] = old_key[13] ^ old_key[9]; |
| key[6] = old_key[14] ^ old_key[10]; |
| key[7] = old_key[15] ^ old_key[11]; |
| |
| // RotWord |
| temp[0] = old_key[5]; |
| temp[1] = old_key[6]; |
| temp[2] = old_key[7]; |
| temp[3] = old_key[4]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_prev(rcon, key_len); |
| |
| // Word 36 |
| key[0] = old_key[8] ^ temp[0] ^ *rcon; |
| key[1] = old_key[9] ^ temp[1]; |
| key[2] = old_key[10] ^ temp[2]; |
| key[3] = old_key[11] ^ temp[3]; |
| } else { // (rnd == 3 || rnd == 6 || rnd == 9 || rnd == 12) |
| |
| // Word 35 |
| key[12] = old_key[20] ^ old_key[16]; |
| key[13] = old_key[21] ^ old_key[17]; |
| key[14] = old_key[22] ^ old_key[18]; |
| key[15] = old_key[23] ^ old_key[19]; |
| |
| // Word 34 |
| key[8] = old_key[16] ^ old_key[12]; |
| key[9] = old_key[17] ^ old_key[13]; |
| key[10] = old_key[18] ^ old_key[14]; |
| key[11] = old_key[19] ^ old_key[15]; |
| |
| // Word 33 |
| key[4] = old_key[12] ^ old_key[8]; |
| key[5] = old_key[13] ^ old_key[9]; |
| key[6] = old_key[14] ^ old_key[10]; |
| key[7] = old_key[15] ^ old_key[11]; |
| |
| // Word 32 |
| key[0] = old_key[8] ^ old_key[4]; |
| key[1] = old_key[9] ^ old_key[5]; |
| key[2] = old_key[10] ^ old_key[6]; |
| key[3] = old_key[11] ^ old_key[7]; |
| } |
| } else { // key_len == 32 |
| |
| // determine shift (in bytes) and amount of key bytes to take over |
| int shift, take; |
| if (rnd == 0) { |
| shift = 0; |
| take = 32; |
| } else { |
| shift = 16; |
| take = 16; |
| } |
| |
| // copy to key what won't be changed in this round - going backwards |
| for (int i = take + shift - 1; i >= shift; i--) { |
| key[i] = old_key[i - shift]; |
| } |
| |
| // compute new bytes/words - there are three cases |
| // 1. Rnd 0: DO NOTHING YET |
| // 2. Odd rounds: -> RotWord, SubWord, Rcon |
| // 3. Even rounds: -> SubWord only |
| |
| if (rnd == 0) { |
| // NOTHING TO COMPUTE |
| } else if (rnd % 2) { // odd rounds -> SubWord, RotWord, Rcon |
| |
| // Word 51 |
| key[12] = old_key[28] ^ old_key[24]; |
| key[13] = old_key[29] ^ old_key[25]; |
| key[14] = old_key[30] ^ old_key[26]; |
| key[15] = old_key[31] ^ old_key[27]; |
| |
| // Word 50 |
| key[8] = old_key[24] ^ old_key[20]; |
| key[9] = old_key[25] ^ old_key[21]; |
| key[10] = old_key[26] ^ old_key[22]; |
| key[11] = old_key[27] ^ old_key[23]; |
| |
| // Word 49 |
| key[4] = old_key[20] ^ old_key[16]; |
| key[5] = old_key[21] ^ old_key[17]; |
| key[6] = old_key[22] ^ old_key[18]; |
| key[7] = old_key[23] ^ old_key[19]; |
| |
| // RotWord |
| temp[0] = old_key[13]; |
| temp[1] = old_key[14]; |
| temp[2] = old_key[15]; |
| temp[3] = old_key[12]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // update rcon |
| aes_rcon_prev(rcon, key_len); |
| |
| // Word 48 |
| key[0] = old_key[16] ^ temp[0] ^ *rcon; |
| key[1] = old_key[17] ^ temp[1]; |
| key[2] = old_key[18] ^ temp[2]; |
| key[3] = old_key[19] ^ temp[3]; |
| } else { // even rounds -> SubWord only |
| |
| // Word 47 |
| key[12] = old_key[28] ^ old_key[24]; |
| key[13] = old_key[29] ^ old_key[25]; |
| key[14] = old_key[30] ^ old_key[26]; |
| key[15] = old_key[31] ^ old_key[27]; |
| |
| // Word 46 |
| key[8] = old_key[24] ^ old_key[20]; |
| key[9] = old_key[25] ^ old_key[21]; |
| key[10] = old_key[26] ^ old_key[22]; |
| key[11] = old_key[27] ^ old_key[23]; |
| |
| // Word 45 |
| key[4] = old_key[20] ^ old_key[16]; |
| key[5] = old_key[21] ^ old_key[17]; |
| key[6] = old_key[22] ^ old_key[18]; |
| key[7] = old_key[23] ^ old_key[19]; |
| |
| // Extract |
| temp[0] = old_key[12]; |
| temp[1] = old_key[13]; |
| temp[2] = old_key[14]; |
| temp[3] = old_key[15]; |
| |
| // SubWord |
| for (int i = 0; i < 4; i++) { |
| temp[i] = sbox[temp[i]]; |
| } |
| |
| // Word 44 |
| key[0] = old_key[16] ^ temp[0]; |
| key[1] = old_key[17] ^ temp[1]; |
| key[2] = old_key[18] ^ temp[2]; |
| key[3] = old_key[19] ^ temp[3]; |
| } |
| } |
| |
| // copy 16 first bytes from key to round key |
| for (int i = 0; i < 16; i++) { |
| round_key[i] = key[i]; |
| } |
| |
| free(old_key); |
| |
| return; |
| } |
| |
| void aes_rcon_next(unsigned char *rcon) { |
| // rcon cannot be 0 |
| if (*rcon) { |
| // update rcon |
| *rcon = aes_mul2(*rcon); |
| } else { |
| // init rcon to first round value |
| *rcon = 0x1; |
| } |
| |
| return; |
| } |
| |
| void aes_rcon_prev(unsigned char *rcon, int key_len) { |
| unsigned char rcon_tmp; |
| |
| // rcon cannot be 0 |
| if (*rcon) { |
| // update rcon - actually this is the inverse of aes_mul2 |
| rcon_tmp = *rcon; |
| |
| // set individual bits of rcon |
| *rcon = 0x0; |
| // extract bits possible xor shift to right |
| // position |
| *rcon |= (((rcon_tmp >> 1) & 0x1) ^ ((rcon_tmp >> 0) & 0x1)) << 0; |
| *rcon |= (((rcon_tmp >> 2) & 0x1)) << 1; |
| *rcon |= (((rcon_tmp >> 3) & 0x1) ^ ((rcon_tmp >> 0) & 0x1)) << 2; |
| *rcon |= (((rcon_tmp >> 4) & 0x1) ^ ((rcon_tmp >> 0) & 0x1)) << 3; |
| *rcon |= (((rcon_tmp >> 5) & 0x1)) << 4; |
| *rcon |= (((rcon_tmp >> 6) & 0x1)) << 5; |
| *rcon |= (((rcon_tmp >> 7) & 0x1)) << 6; |
| *rcon |= (((rcon_tmp >> 0) & 0x1)) << 7; |
| } else { |
| // init rcon to first round value |
| if (key_len == 16) { |
| *rcon = 0x36; |
| } else if (key_len == 24) { |
| *rcon = 0x80; |
| } else { // key_len == 32 |
| *rcon = 0x40; |
| } |
| } |
| |
| return; |
| } |