#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define AES_RPOL 0x011b // reduction polynomial (x^8 + x^4 + x^3 + x + 1)
#define AES_GEN 0x03 // gf(2^8) generator (x + 1)
#define AES_SBOX_CC 0x63 // S-Box C constant
#define KEY_128 (128/8)
#define KEY_192 (192/8)
#define KEY_256 (256/8)
#define aes_mul(a, b) ((a)&&(b)?g_aes_ilogt[(g_aes_logt[(a)]+g_aes_logt[(b)])%0xff]:0)
#define aes_inv(a) ((a)?g_aes_ilogt[0xff-g_aes_logt[(a)]]:0)
unsigned
char
g_aes_logt[256], g_aes_ilogt[256];
unsigned
char
g_aes_sbox[256], g_aes_isbox[256];
typedef
struct
{
unsigned
char
state[4][4];
int
kcol;
size_t
rounds;
unsigned
long
keysched[0];
} aes_ctx_t;
void
aes_init();
aes_ctx_t *aes_alloc_ctx(unsigned
char
*key,
size_t
keyLen);
inline
unsigned
long
aes_subword(unsigned
long
w);
inline
unsigned
long
aes_rotword(unsigned
long
w);
void
aes_keyexpansion(aes_ctx_t *ctx);
inline
unsigned
char
aes_mul_manual(unsigned
char
a, unsigned
char
b);
void
aes_subbytes(aes_ctx_t *ctx);
void
aes_shiftrows(aes_ctx_t *ctx);
void
aes_mixcolumns(aes_ctx_t *ctx);
void
aes_addroundkey(aes_ctx_t *ctx,
int
round);
void
aes_encrypt(aes_ctx_t *ctx, unsigned
char
input[16], unsigned
char
output[16]);
void
aes_invsubbytes(aes_ctx_t *ctx);
void
aes_invshiftrows(aes_ctx_t *ctx);
void
aes_invmixcolumns(aes_ctx_t *ctx);
void
aes_decrypt(aes_ctx_t *ctx, unsigned
char
input[16], unsigned
char
output[16]);
void
aes_free_ctx(aes_ctx_t *ctx);
void
init_aes()
{
int
i;
unsigned
char
gen;
gen = 1;
for
(i = 0; i < 0xff; i++) {
g_aes_logt[gen] = i;
g_aes_ilogt[i] = gen;
gen = aes_mul_manual(gen, AES_GEN);
}
for
(i = 0; i <= 0xff; i++) {
char
bi;
unsigned
char
inv = aes_inv(i);
g_aes_sbox[i] = 0;
for
(bi = 0; bi < 8; bi++) {
g_aes_sbox[i] |= ((inv & (1<<bi)?1:0)
^ (inv & (1 << ((bi+4) & 7))?1:0)
^ (inv & (1 << ((bi+5) & 7))?1:0)
^ (inv & (1 << ((bi+6) & 7))?1:0)
^ (inv & (1 << ((bi+7) & 7))?1:0)
^ (AES_SBOX_CC & (1 << bi)?1:0)
) << bi;
}
g_aes_isbox[g_aes_sbox[i]] = i;
}
g_aes_sbox[1] = 0x7c;
g_aes_isbox[0x7c] = 1;
g_aes_isbox[0x63] = 0;
}
aes_ctx_t *aes_alloc_ctx(unsigned
char
*key,
size_t
keyLen)
{
aes_ctx_t *ctx;
size_t
rounds;
size_t
ks_size;
switch
(keyLen) {
case
16:
rounds = 10;
break
;
case
24:
rounds = 12;
break
;
case
32:
rounds = 14;
break
;
defaut:
return
NULL;
}
ks_size = 4*(rounds+1)*
sizeof
(unsigned
long
);
ctx =
malloc
(
sizeof
(aes_ctx_t)+ks_size);
if
(ctx) {
ctx->rounds = rounds;
ctx->kcol = keyLen/4;
memcpy
(ctx->keysched, key, keyLen);
ctx->keysched[43] = 0;
aes_keyexpansion(ctx);
}
return
ctx;
}
inline
unsigned
long
aes_subword(unsigned
long
w)
{
return
g_aes_sbox[w & 0x000000ff] |
(g_aes_sbox[(w & 0x0000ff00) >> 8] << 8) |
(g_aes_sbox[(w & 0x00ff0000) >> 16] << 16) |
(g_aes_sbox[(w & 0xff000000) >> 24] << 24);
}
inline
unsigned
long
aes_rotword(unsigned
long
w)
{
return
((w & 0x000000ff) << 24) |
((w & 0x0000ff00) >> 8) |
((w & 0x00ff0000) >> 8) |
((w & 0xff000000) >> 8);
}
void
aes_keyexpansion(aes_ctx_t *ctx)
{
unsigned
long
temp;
unsigned
long
rcon;
register
int
i;
rcon = 0x00000001;
for
(i = ctx->kcol; i < (4*(ctx->rounds+1)); i++) {
temp = ctx->keysched[i-1];
if
(!(i%ctx->kcol)) {
temp = aes_subword(aes_rotword(temp)) ^ rcon;
rcon = aes_mul(rcon, 2);
}
else
if
(ctx->kcol > 6 && i%ctx->kcol == 4)
temp = aes_subword(temp);
ctx->keysched[i] = ctx->keysched[i-ctx->kcol] ^ temp;
}
}
inline
unsigned
char
aes_mul_manual(unsigned
char
a, unsigned
char
b)
{
register
unsigned
short
ac;
register
unsigned
char
ret;
ac = a;
ret = 0;
while
(b) {
if
(b & 0x01)
ret ^= ac;
ac <<= 1;
b >>= 1;
if
(ac & 0x0100)
ac ^= AES_RPOL;
}
return
ret;
}
void
aes_subbytes(aes_ctx_t *ctx)
{
int
i;
for
(i = 0; i < 16; i++) {
int
x, y;
x = i & 0x03;
y = i >> 2;
ctx->state[x][y] = g_aes_sbox[ctx->state[x][y]];
}
}
void
aes_shiftrows(aes_ctx_t *ctx)
{
unsigned
char
nstate[4][4];
int
i;
for
(i = 0; i < 16; i++) {
int
x, y;
x = i & 0x03;
y = i >> 2;
nstate[x][y] = ctx->state[x][(y+x) & 0x03];
}
memcpy
(ctx->state, nstate,
sizeof
(ctx->state));
}
void
aes_mixcolumns(aes_ctx_t *ctx)
{
unsigned
char
nstate[4][4];
int
i;
for
(i = 0; i < 4; i++) {
nstate[0][i] = aes_mul(0x02, ctx->state[0][i]) ^
aes_mul(0x03, ctx->state[1][i]) ^
ctx->state[2][i] ^
ctx->state[3][i];
nstate[1][i] = ctx->state[0][i] ^
aes_mul(0x02, ctx->state[1][i]) ^
aes_mul(0x03, ctx->state[2][i]) ^
ctx->state[3][i];
nstate[2][i] = ctx->state[0][i] ^
ctx->state[1][i] ^
aes_mul(0x02, ctx->state[2][i]) ^
aes_mul(0x03, ctx->state[3][i]);
nstate[3][i] = aes_mul(0x03, ctx->state[0][i]) ^
ctx->state[1][i] ^
ctx->state[2][i] ^
aes_mul(0x02, ctx->state[3][i]);
}
memcpy
(ctx->state, nstate,
sizeof
(ctx->state));
}
void
aes_addroundkey(aes_ctx_t *ctx,
int
round)
{
int
i;
for
(i = 0; i < 16; i++) {
int
x, y;
x = i & 0x03;
y = i >> 2;
ctx->state[x][y] = ctx->state[x][y] ^
((ctx->keysched[round*4+y] & (0xff << (x*8))) >> (x*8));
}
}
void
aes_encrypt(aes_ctx_t *ctx, unsigned
char
input[16], unsigned
char
output[16])
{
int
i;
for
(i = 0; i < 16; i++)
ctx->state[i & 0x03][i >> 2] = input[i];
aes_addroundkey(ctx, 0);
for
(i = 1; i < ctx->rounds; i++) {
aes_subbytes(ctx);
aes_shiftrows(ctx);
aes_mixcolumns(ctx);
aes_addroundkey(ctx, i);
}
aes_subbytes(ctx);
aes_shiftrows(ctx);
aes_addroundkey(ctx, ctx->rounds);
for
(i = 0; i < 16; i++)
output[i] = ctx->state[i & 0x03][i >> 2];
}
void
aes_invshiftrows(aes_ctx_t *ctx)
{
unsigned
char
nstate[4][4];
int
i;
for
(i = 0; i < 16; i++) {
int
x, y;
x = i & 0x03;
y = i >> 2;
nstate[x][(y+x) & 0x03] = ctx->state[x][y];
}
memcpy
(ctx->state, nstate,
sizeof
(ctx->state));
}
void
aes_invsubbytes(aes_ctx_t *ctx)
{
int
i;
for
(i = 0; i < 16; i++) {
int
x, y;
x = i & 0x03;
y = i >> 2;
ctx->state[x][y] = g_aes_isbox[ctx->state[x][y]];
}
}
void
aes_invmixcolumns(aes_ctx_t *ctx)
{
unsigned
char
nstate[4][4];
int
i;
for
(i = 0; i < 4; i++) {
nstate[0][i] = aes_mul(0x0e, ctx->state[0][i]) ^
aes_mul(0x0b, ctx->state[1][i]) ^
aes_mul(0x0d, ctx->state[2][i]) ^
aes_mul(0x09, ctx->state[3][i]);
nstate[1][i] = aes_mul(0x09, ctx->state[0][i]) ^
aes_mul(0x0e, ctx->state[1][i]) ^
aes_mul(0x0b, ctx->state[2][i]) ^
aes_mul(0x0d, ctx->state[3][i]);
nstate[2][i] = aes_mul(0x0d, ctx->state[0][i]) ^
aes_mul(0x09, ctx->state[1][i]) ^
aes_mul(0x0e, ctx->state[2][i]) ^
aes_mul(0x0b, ctx->state[3][i]);
nstate[3][i] = aes_mul(0x0b, ctx->state[0][i]) ^
aes_mul(0x0d, ctx->state[1][i]) ^
aes_mul(0x09, ctx->state[2][i]) ^
aes_mul(0x0e, ctx->state[3][i]);
}
memcpy
(ctx->state, nstate,
sizeof
(ctx->state));
}
void
aes_decrypt(aes_ctx_t *ctx, unsigned
char
input[16], unsigned
char
output[16])
{
int
i, j;
for
(i = 0; i < 16; i++)
ctx->state[i & 0x03][i >> 2] = input[i];
aes_addroundkey(ctx, ctx->rounds);
for
(i = ctx->rounds-1; i >= 1; i--) {
aes_invshiftrows(ctx);
aes_invsubbytes(ctx);
aes_addroundkey(ctx, i);
aes_invmixcolumns(ctx);
}
aes_invshiftrows(ctx);
aes_invsubbytes(ctx);
aes_addroundkey(ctx, 0);
for
(i = 0; i < 16; i++)
output[i] = ctx->state[i & 0x03][i >> 2];
}
void
aes_free_ctx(aes_ctx_t *ctx)
{
free
(ctx);
}
int
main(
int
argc,
char
*argv[])
{
unsigned
char
key[KEY_128] =
"uber strong key!"
;
unsigned
char
ptext[16] =
"Attack at dawn!"
;
unsigned
char
ctext[16];
unsigned
char
decptext[16];
aes_ctx_t *ctx;
init_aes();
ctx = aes_alloc_ctx(key,
sizeof
(key));
if
(!ctx) {
perror
(
"aes_alloc_ctx"
);
return
EXIT_FAILURE;
}
aes_encrypt(ctx, ptext, ctext);
aes_decrypt(ctx, ctext, decptext);
puts
(decptext);
aes_free_ctx(ctx);
return
EXIT_SUCCESS;
}
In the attached zip you will also find the compiled ELF binary. - Click here
No comments:
Post a Comment