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