radare2/libr/crypto/p/crypto_aes_algo.c
2016-03-25 11:10:16 +01:00

245 lines
8.1 KiB
C

// original code from:
//====================
// advanced encryption standard
// author: karl malbrain, malbrain@yahoo.com
//
// adapted from Christophe Devine's tables
// and George Anescu's c++ code.
#include "crypto_aes_algo.h"
#define Nb 4 // number of columns in the state & expanded key
// #define Nk 4 // number of columns in a key
// #define Nr 10 // number of rounds in encryption
// #define AES_KEY (4 * Nk)
// #define ROUND_KEY_COUNT ((Nr + 1) * 4)
static const ut8 Rcon[30] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1b, 0x36, 0x6c, 0xc0, 0xab, 0x4d, 0x9a, 0x2f,
0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91};
// Expand a user-supplied key material into a session key.
// key - The 128/192/256-bit user-key to use.
//expkey[2][Nr + 1][Nb]
void aes_expkey (const struct aes_state *st, ut32 expkey[2][st->rounds + 1][Nb]) {
int ROUND_KEY_COUNT = 4 * (1 + st->rounds);
ut32 tk[st->columns], tt;
st32 idx = 0, t = 0;
const ut8 *key = st->key;
st32 i, j, r;
for (i = 0; i <= st->rounds; i++)
for (j = 0; j < Nb; j++)
expkey[0][i][j] = 0;
for (i = 0; i <= st->rounds; i++)
for (j = 0; j < Nb; j++)
expkey[1][i][j] = 0;
// Copy user material bytes into temporary ints
for (i = 0; i < st->columns; i++) {
tk[i] = *key++ << 24;
tk[i] |= *key++ << 16;
tk[i] |= *key++ << 8;
tk[i] |= *key++;
}
// Copy values into round key arrays
for (j = 0; j < st->columns && t < ROUND_KEY_COUNT; j++, t++) {
expkey[0][t / Nb][t % Nb] = tk[j];
expkey[1][st->rounds - (t / Nb)][t % Nb] = tk[j];
}
while (t < ROUND_KEY_COUNT) {
// Extrapolate using phi (the round key evolution function)
tt = tk[st->columns - 1];
tk[0] ^= Sbox[(ut8)(tt >> 16)] << 24 ^ Sbox[(ut8)(tt >> 8)] << 16 ^
Sbox[(ut8)tt] << 8 ^ Sbox[(ut8)(tt >> 24)] ^ Rcon[idx++] << 24;
if (st->columns != 8)
for (i = 1, j = 0; i < st->columns;)
tk[i++] ^= tk[j++];
else {
for (i = 1, j = 0; i < st->columns / 2;)
tk[i++] ^= tk[j++];
tt = tk[st->columns / 2 - 1];
tk[st->columns / 2] ^= Sbox[(ut8)tt] ^ Sbox[(ut8)(tt >> 8)] << 8 ^
Sbox[(ut8)(tt >> 16)] << 16 ^
Sbox[(ut8)(tt >> 24)] << 24;
for (j = st->columns / 2, i = j + 1; i < st->columns;)
tk[i++] ^= tk[j++];
}
// Copy values into round key arrays
for (j = 0; j < st->columns && t < ROUND_KEY_COUNT; j++, t++) {
expkey[0][t / Nb][t % Nb] = tk[j];
expkey[1][st->rounds - (t / Nb)][t % Nb] = tk[j];
}
}
// Inverse MixColumn where needed
for (r = 1; r < st->rounds; r++)
for (j = 0; j < Nb; j++) {
tt = expkey[1][r][j];
expkey[1][r][j] = U0[(ut8)(tt >> 24)] ^ U1[(ut8)(tt >> 16)] ^
U2[(ut8)(tt >> 8)] ^ U3[(ut8)tt];
}
}
// Convenience method to encrypt exactly one block of plaintext, assuming
// Rijndael's default block size (128-bit).
// in - The plaintext
// result - The ciphertext generated from a plaintext using the key
void aes_encrypt (struct aes_state *st, ut8 *in, ut8 *result) {
ut32 expkey[2][st->rounds + 1][Nb];
aes_expkey(st, expkey);
ut32 t0, t1, t2, t3, tt;
ut32 a0, a1, a2, a3, r;
t0 = *in++ << 24;
t0 |= *in++ << 16;
t0 |= *in++ << 8;
t0 |= *in++;
t0 ^= expkey[0][0][0];
t1 = *in++ << 24;
t1 |= *in++ << 16;
t1 |= *in++ << 8;
t1 |= *in++;
t1 ^= expkey[0][0][1];
t2 = *in++ << 24;
t2 |= *in++ << 16;
t2 |= *in++ << 8;
t2 |= *in++;
t2 ^= expkey[0][0][2];
t3 = *in++ << 24;
t3 |= *in++ << 16;
t3 |= *in++ << 8;
t3 |= *in++;
t3 ^= expkey[0][0][3];
// Apply Round Transforms
for (r = 1; r < st->rounds; r++) {
a0 = (FT0[(ut8)(t0 >> 24)] ^ FT1[(ut8)(t1 >> 16)] ^ FT2[(ut8)(t2 >> 8)] ^
FT3[(ut8)t3]);
a1 = (FT0[(ut8)(t1 >> 24)] ^ FT1[(ut8)(t2 >> 16)] ^ FT2[(ut8)(t3 >> 8)] ^
FT3[(ut8)t0]);
a2 = (FT0[(ut8)(t2 >> 24)] ^ FT1[(ut8)(t3 >> 16)] ^ FT2[(ut8)(t0 >> 8)] ^
FT3[(ut8)t1]);
a3 = (FT0[(ut8)(t3 >> 24)] ^ FT1[(ut8)(t0 >> 16)] ^ FT2[(ut8)(t1 >> 8)] ^
FT3[(ut8)t2]);
t0 = a0 ^ expkey[0][r][0];
t1 = a1 ^ expkey[0][r][1];
t2 = a2 ^ expkey[0][r][2];
t3 = a3 ^ expkey[0][r][3];
}
// Last Round is special
tt = expkey[0][st->rounds][0];
result[0] = Sbox[(ut8)(t0 >> 24)] ^ (ut8)(tt >> 24);
result[1] = Sbox[(ut8)(t1 >> 16)] ^ (ut8)(tt >> 16);
result[2] = Sbox[(ut8)(t2 >> 8)] ^ (ut8)(tt >> 8);
result[3] = Sbox[(ut8)t3] ^ (ut8)tt;
tt = expkey[0][st->rounds][1];
result[4] = Sbox[(ut8)(t1 >> 24)] ^ (ut8)(tt >> 24);
result[5] = Sbox[(ut8)(t2 >> 16)] ^ (ut8)(tt >> 16);
result[6] = Sbox[(ut8)(t3 >> 8)] ^ (ut8)(tt >> 8);
result[7] = Sbox[(ut8)t0] ^ (ut8)tt;
tt = expkey[0][st->rounds][2];
result[8] = Sbox[(ut8)(t2 >> 24)] ^ (ut8)(tt >> 24);
result[9] = Sbox[(ut8)(t3 >> 16)] ^ (ut8)(tt >> 16);
result[10] = Sbox[(ut8)(t0 >> 8)] ^ (ut8)(tt >> 8);
result[11] = Sbox[(ut8)t1] ^ (ut8)tt;
tt = expkey[0][st->rounds][3];
result[12] = Sbox[(ut8)(t3 >> 24)] ^ (ut8)(tt >> 24);
result[13] = Sbox[(ut8)(t0 >> 16)] ^ (ut8)(tt >> 16);
result[14] = Sbox[(ut8)(t1 >> 8)] ^ (ut8)(tt >> 8);
result[15] = Sbox[(ut8)t2] ^ (ut8)tt;
}
// Convenience method to decrypt exactly one block of plaintext, assuming
// Rijndael's default block size (128-bit).
// in - The ciphertext.
// result - The plaintext generated from a ciphertext using the session key.
void aes_decrypt (struct aes_state *st, ut8 *in, ut8 *result) {
ut32 expkey[2][st->rounds + 1][Nb];
aes_expkey(st, expkey);
ut32 t0, t1, t2, t3, tt;
ut32 a0, a1, a2, a3, r;
t0 = *in++ << 24;
t0 |= *in++ << 16;
t0 |= *in++ << 8;
t0 |= *in++;
t0 ^= expkey[1][0][0];
t1 = *in++ << 24;
t1 |= *in++ << 16;
t1 |= *in++ << 8;
t1 |= *in++;
t1 ^= expkey[1][0][1];
t2 = *in++ << 24;
t2 |= *in++ << 16;
t2 |= *in++ << 8;
t2 |= *in++;
t2 ^= expkey[1][0][2];
t3 = *in++ << 24;
t3 |= *in++ << 16;
t3 |= *in++ << 8;
t3 |= *in++;
t3 ^= expkey[1][0][3];
// Apply round transforms
for (r = 1; r < st->rounds; r++) {
a0 = (RT0[(ut8)(t0 >> 24)] ^ RT1[(ut8)(t3 >> 16)] ^ RT2[(ut8)(t2 >> 8)] ^
RT3[(ut8)t1]);
a1 = (RT0[(ut8)(t1 >> 24)] ^ RT1[(ut8)(t0 >> 16)] ^ RT2[(ut8)(t3 >> 8)] ^
RT3[(ut8)t2]);
a2 = (RT0[(ut8)(t2 >> 24)] ^ RT1[(ut8)(t1 >> 16)] ^ RT2[(ut8)(t0 >> 8)] ^
RT3[(ut8)t3]);
a3 = (RT0[(ut8)(t3 >> 24)] ^ RT1[(ut8)(t2 >> 16)] ^ RT2[(ut8)(t1 >> 8)] ^
RT3[(ut8)t0]);
t0 = a0 ^ expkey[1][r][0];
t1 = a1 ^ expkey[1][r][1];
t2 = a2 ^ expkey[1][r][2];
t3 = a3 ^ expkey[1][r][3];
}
// Last Round is special
tt = expkey[1][st->rounds][0];
result[0] = InvSbox[(ut8)(t0 >> 24)] ^ (ut8)(tt >> 24);
result[1] = InvSbox[(ut8)(t3 >> 16)] ^ (ut8)(tt >> 16);
result[2] = InvSbox[(ut8)(t2 >> 8)] ^ (ut8)(tt >> 8);
result[3] = InvSbox[(ut8)t1] ^ (ut8)tt;
tt = expkey[1][st->rounds][1];
result[4] = InvSbox[(ut8)(t1 >> 24)] ^ (ut8)(tt >> 24);
result[5] = InvSbox[(ut8)(t0 >> 16)] ^ (ut8)(tt >> 16);
result[6] = InvSbox[(ut8)(t3 >> 8)] ^ (ut8)(tt >> 8);
result[7] = InvSbox[(ut8)t2] ^ (ut8)tt;
tt = expkey[1][st->rounds][2];
result[8] = InvSbox[(ut8)(t2 >> 24)] ^ (ut8)(tt >> 24);
result[9] = InvSbox[(ut8)(t1 >> 16)] ^ (ut8)(tt >> 16);
result[10] = InvSbox[(ut8)(t0 >> 8)] ^ (ut8)(tt >> 8);
result[11] = InvSbox[(ut8)t3] ^ (ut8)tt;
tt = expkey[1][st->rounds][3];
result[12] = InvSbox[(ut8)(t3 >> 24)] ^ (ut8)(tt >> 24);
result[13] = InvSbox[(ut8)(t2 >> 16)] ^ (ut8)(tt >> 16);
result[14] = InvSbox[(ut8)(t1 >> 8)] ^ (ut8)(tt >> 8);
result[15] = InvSbox[(ut8)t0] ^ (ut8)tt;
}