libtomcrypt/aes.c
2010-06-16 12:37:51 +02:00

401 lines
13 KiB
C

/* This is an independent implementation of the encryption algorithm: */
/* */
/* RIJNDAEL by Joan Daemen and Vincent Rijmen */
/* */
/* which is a candidate algorithm in the Advanced Encryption Standard */
/* programme of the US National Institute of Standards and Technology. */
/* */
/* Copyright in this implementation is held by Dr B R Gladman but I */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions */
/* that the originators of the algorithm place on its exploitation. */
/* */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999 */
/* This code has been modified by Tom St Denis for libtomcrypt.a */
#include "mycrypt.h"
#ifdef RIJNDAEL
const struct _cipher_descriptor rijndael_desc =
{
"rijndael",
6,
16, 32, 16, 10,
&rijndael_setup,
&rijndael_ecb_encrypt,
&rijndael_ecb_decrypt,
&rijndael_test,
&rijndael_keysize
};
const struct _cipher_descriptor aes_desc =
{
"aes",
6,
16, 32, 16, 10,
&rijndael_setup,
&rijndael_ecb_encrypt,
&rijndael_ecb_decrypt,
&rijndael_test,
&rijndael_keysize
};
#include "aes_tab.c"
#define byte(x, y) (((x)>>(8*(y)))&255)
#define f_rn(bo, bi, n, k) \
bo[n] = ft_tab[0][byte(bi[n],0)] ^ \
ft_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
ft_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
ft_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rn(bo, bi, n, k) \
bo[n] = it_tab[0][byte(bi[n],0)] ^ \
it_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
it_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
it_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#define ls_box(x) \
( fl_tab[0][byte(x, 0)] ^ \
fl_tab[1][byte(x, 1)] ^ \
fl_tab[2][byte(x, 2)] ^ \
fl_tab[3][byte(x, 3)] )
#define f_rl(bo, bi, n, k) \
bo[n] = fl_tab[0][byte(bi[n],0)] ^ \
fl_tab[1][byte(bi[(n + 1) & 3],1)] ^ \
fl_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
fl_tab[3][byte(bi[(n + 3) & 3],3)] ^ *(k + n)
#define i_rl(bo, bi, n, k) \
bo[n] = il_tab[0][byte(bi[n],0)] ^ \
il_tab[1][byte(bi[(n + 3) & 3],1)] ^ \
il_tab[2][byte(bi[(n + 2) & 3],2)] ^ \
il_tab[3][byte(bi[(n + 1) & 3],3)] ^ *(k + n)
#define star_x(x) (((x) & 0x7f7f7f7fUL) << 1) ^ ((((x) & 0x80808080UL) >> 7) * 0x1bUL)
#define imix_col(y,x) \
u = star_x(x); \
v = star_x(u); \
w = star_x(v); \
t = w ^ (x); \
(y) = u ^ v ^ w; \
(y) ^= ROR(u ^ t, 8) ^ \
ROR(v ^ t, 16) ^ \
ROR(t,24)
#ifdef CLEAN_STACK
static int _rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
#else
int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
#endif
{
unsigned long t, u, v, w, in_key[8];
int i, k_len;
/* check arguments */
_ARGCHK(key != NULL);
_ARGCHK(skey != NULL);
if (numrounds == 0)
numrounds = 10 + (2 * ((keylen/8)-2));
if (keylen != 16 && keylen != 24 && keylen != 32) {
return CRYPT_INVALID_KEYSIZE;
}
if (numrounds != (10 + (2 * ((keylen/8)-2)))) {
return CRYPT_INVALID_ROUNDS;
}
k_len = keylen / 4;
for (i = 0; i < k_len; i++) {
LOAD32L(in_key[i], key+(4*i));
}
skey->rijndael.k_len = k_len;
skey->rijndael.eK[0] = in_key[0]; skey->rijndael.eK[1] = in_key[1];
skey->rijndael.eK[2] = in_key[2]; skey->rijndael.eK[3] = in_key[3];
switch(k_len) {
case 4: t = skey->rijndael.eK[3];
for(i = 0; i < 10; ++i) {
t = ls_box(ROR(t, 8)) ^ rco_tab[i];
t ^= skey->rijndael.eK[4 * i]; skey->rijndael.eK[4 * i + 4] = t;
t ^= skey->rijndael.eK[4 * i + 1]; skey->rijndael.eK[4 * i + 5] = t;
t ^= skey->rijndael.eK[4 * i + 2]; skey->rijndael.eK[4 * i + 6] = t;
t ^= skey->rijndael.eK[4 * i + 3]; skey->rijndael.eK[4 * i + 7] = t;
}
break;
case 6: skey->rijndael.eK[4] = in_key[4];
t = skey->rijndael.eK[5] = in_key[5];
for(i = 0; i < 8; ++i) {
t = ls_box(ROR(t, 8)) ^ rco_tab[i];
t ^= skey->rijndael.eK[6 * i]; skey->rijndael.eK[6 * i + 6] = t;
t ^= skey->rijndael.eK[6 * i + 1]; skey->rijndael.eK[6 * i + 7] = t;
t ^= skey->rijndael.eK[6 * i + 2]; skey->rijndael.eK[6 * i + 8] = t;
t ^= skey->rijndael.eK[6 * i + 3]; skey->rijndael.eK[6 * i + 9] = t;
t ^= skey->rijndael.eK[6 * i + 4]; skey->rijndael.eK[6 * i + 10] = t;
t ^= skey->rijndael.eK[6 * i + 5]; skey->rijndael.eK[6 * i + 11] = t;
}
break;
case 8: skey->rijndael.eK[4] = in_key[4];
skey->rijndael.eK[5] = in_key[5];
skey->rijndael.eK[6] = in_key[6];
t = skey->rijndael.eK[7] = in_key[7];
for(i = 0; i < 7; ++i) {
t = ls_box(ROR(t, 8)) ^ rco_tab[i];
t ^= skey->rijndael.eK[8 * i]; skey->rijndael.eK[8 * i + 8] = t;
t ^= skey->rijndael.eK[8 * i + 1]; skey->rijndael.eK[8 * i + 9] = t;
t ^= skey->rijndael.eK[8 * i + 2]; skey->rijndael.eK[8 * i + 10] = t;
t ^= skey->rijndael.eK[8 * i + 3]; skey->rijndael.eK[8 * i + 11] = t;
t = skey->rijndael.eK[8 * i + 4] ^ ls_box(t); skey->rijndael.eK[8 * i + 12] = t;
t ^= skey->rijndael.eK[8 * i + 5]; skey->rijndael.eK[8 * i + 13] = t;
t ^= skey->rijndael.eK[8 * i + 6]; skey->rijndael.eK[8 * i + 14] = t;
t ^= skey->rijndael.eK[8 * i + 7]; skey->rijndael.eK[8 * i + 15] = t;
}
break;
}
skey->rijndael.dK[0] = skey->rijndael.eK[0];
skey->rijndael.dK[1] = skey->rijndael.eK[1];
skey->rijndael.dK[2] = skey->rijndael.eK[2];
skey->rijndael.dK[3] = skey->rijndael.eK[3];
for(i = 4; i < 4 * k_len + 24; ++i) {
imix_col(skey->rijndael.dK[i], skey->rijndael.eK[i]);
}
return CRYPT_OK;
};
#ifdef CLEAN_STACK
int rijndael_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
{
int x;
x = _rijndael_setup(key, keylen, numrounds, skey);
burn_stack(sizeof(unsigned long) * 12 + sizeof(int) * 2);
return x;
}
#endif
/* encrypt a block of text */
#define f_nround(bo, bi, k) \
f_rn(bo, bi, 0, k); \
f_rn(bo, bi, 1, k); \
f_rn(bo, bi, 2, k); \
f_rn(bo, bi, 3, k); \
k += 4
#define f_lround(bo, bi, k) \
f_rl(bo, bi, 0, k); \
f_rl(bo, bi, 1, k); \
f_rl(bo, bi, 2, k); \
f_rl(bo, bi, 3, k)
#ifdef SMALL_CODE
static void _fnround(unsigned long *bo, unsigned long *bi, unsigned long *k)
{
f_nround(bo, bi, k);
}
static void _flround(unsigned long *bo, unsigned long *bi, unsigned long *k)
{
f_lround(bo, bi, k);
}
#undef f_nround
#define f_nround(bo, bi, k) { _fnround(bo, bi, k); k += 4; }
#undef f_lround
#define f_lround(bo, bi, k) _flround(bo, bi, k)
#endif
void rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
{
unsigned long b0[4], b1[4], *kp;
_ARGCHK(pt != NULL);
_ARGCHK(ct != NULL);
_ARGCHK(skey != NULL);
LOAD32L(b0[0], &pt[0]); LOAD32L(b0[1], &pt[4]);
LOAD32L(b0[2], &pt[8]); LOAD32L(b0[3], &pt[12]);
b0[0] ^= skey->rijndael.eK[0]; b0[1] ^= skey->rijndael.eK[1];
b0[2] ^= skey->rijndael.eK[2]; b0[3] ^= skey->rijndael.eK[3];
kp = skey->rijndael.eK + 4;
if (skey->rijndael.k_len > 6) {
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
} else if (skey->rijndael.k_len > 4) {
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
}
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_nround(b0, b1, kp);
f_nround(b1, b0, kp); f_lround(b0, b1, kp);
STORE32L(b0[0], &ct[0]); STORE32L(b0[1], &ct[4]);
STORE32L(b0[2], &ct[8]); STORE32L(b0[3], &ct[12]);
#ifdef CLEAN_STACK
zeromem(b0, sizeof(b0));
zeromem(b1, sizeof(b1));
#endif
};
/* decrypt a block of text */
#define i_nround(bo, bi, k) \
i_rn(bo, bi, 0, k); \
i_rn(bo, bi, 1, k); \
i_rn(bo, bi, 2, k); \
i_rn(bo, bi, 3, k); \
k -= 4
#define i_lround(bo, bi, k) \
i_rl(bo, bi, 0, k); \
i_rl(bo, bi, 1, k); \
i_rl(bo, bi, 2, k); \
i_rl(bo, bi, 3, k)
#ifdef SMALL_CODE
static void _inround(unsigned long *bo, unsigned long *bi, unsigned long *k)
{
i_nround(bo, bi, k);
}
static void _ilround(unsigned long *bo, unsigned long *bi, unsigned long *k)
{
i_lround(bo, bi, k);
}
#undef i_nround
#define i_nround(bo, bi, k) { _inround(bo, bi, k); k -= 4; }
#undef i_lround
#define i_lround(bo, bi, k) _ilround(bo, bi, k)
#endif
void rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
{
unsigned long b0[4], b1[4], *kp;
_ARGCHK(pt != NULL);
_ARGCHK(ct != NULL);
_ARGCHK(skey != NULL);
LOAD32L(b0[0], &ct[0]); LOAD32L(b0[1], &ct[4]);
LOAD32L(b0[2], &ct[8]); LOAD32L(b0[3], &ct[12]);
b0[0] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 24];
b0[1] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 25];
b0[2] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 26];
b0[3] ^= skey->rijndael.eK[4 * skey->rijndael.k_len + 27];
kp = skey->rijndael.dK + 4 * (skey->rijndael.k_len + 5);
if(skey->rijndael.k_len > 6) {
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
} else if(skey->rijndael.k_len > 4) {
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
}
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_nround(b0, b1, kp);
i_nround(b1, b0, kp); i_lround(b0, b1, kp);
STORE32L(b0[0], &pt[0]); STORE32L(b0[1], &pt[4]);
STORE32L(b0[2], &pt[8]); STORE32L(b0[3], &pt[12]);
#ifdef CLEAN_STACK
zeromem(b0, sizeof(b0));
zeromem(b1, sizeof(b1));
#endif
};
int rijndael_test(void)
{
int errno;
static const struct {
int keylen;
unsigned char key[32], pt[16], ct[16];
} tests[] = {
{ 16,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }
}, {
24,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }
}, {
32,
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
{ 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }
}
};
symmetric_key key;
unsigned char tmp[2][16];
int i;
for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
if ((errno = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
return errno;
}
rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key);
rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
if (memcmp(tmp[0], tests[i].ct, 16) || memcmp(tmp[1], tests[i].pt, 16)) {
return CRYPT_FAIL_TESTVECTOR;
}
}
return CRYPT_OK;
}
int rijndael_keysize(int *desired_keysize)
{
_ARGCHK(desired_keysize != NULL);
if (*desired_keysize < 16)
return CRYPT_INVALID_KEYSIZE;
if (*desired_keysize < 24) {
*desired_keysize = 16;
return CRYPT_OK;
} else if (*desired_keysize < 32) {
*desired_keysize = 24;
return CRYPT_OK;
} else {
*desired_keysize = 32;
return CRYPT_OK;
}
}
#endif