#include "aes.h"
|
|
|
const unsigned char kTable[32] =
|
{
|
0x21, 0x05, 0x04, 0x19, 0x89, 0x12, 0x13, 0x00,
|
0x18, 0xDE, 0xCA, 0x01, 0x30, 0x52, 0x01, 0x23,
|
0x13, 0x05, 0x33, 0x19, 0x93, 0x07, 0x08, 0x00,
|
0x20, 0x5B, 0xA3, 0x4A, 0x21, 0xBA, 0xF9, 0xFC
|
};
|
/*
|
21 05 04 19 89 12 13 00 18 DE CA 01 30 52 01 23 13 05 33 19 93 07 08 00 20 5B A3 4A 21 BA F9 FC
|
*/
|
|
unsigned char block1[256]; //!< Workspace 1.
|
unsigned char block2[256]; //!< Worksapce 2.
|
unsigned char tempbuf[256];
|
|
unsigned char *powTbl; //!< Final location of exponentiation lookup table.
|
unsigned char *logTbl; //!< Final location of logarithm lookup table.
|
unsigned char *sBox; //!< Final location of s-box.
|
unsigned char *sBoxInv; //!< Final location of inverse s-box.
|
unsigned char *expandedKey; //!< Final location of expanded key.
|
|
void CalcPowLog(unsigned char *powTbl, unsigned char *logTbl)
|
{
|
unsigned char i = 0;
|
unsigned char t = 1;
|
|
do {
|
// Use 0x03 as root for exponentiation and logarithms.
|
powTbl[i] = t;
|
logTbl[t] = i;
|
i++;
|
|
// Muliply t by 3 in GF(2^8).
|
t ^= (t << 1) ^ (t & 0x80 ? BPOLY : 0);
|
} while( t != 1 ); // Cyclic properties ensure that i < 255.
|
|
powTbl[255] = powTbl[0]; // 255 = '-0', 254 = -1, etc.
|
}
|
|
|
|
void CalcSBox( unsigned char * sBox )
|
{
|
unsigned char i, rot;
|
unsigned char temp;
|
unsigned char result;
|
|
// Fill all entries of sBox[].
|
i = 0;
|
do {
|
//Inverse in GF(2^8).
|
if( i > 0 )
|
{
|
temp = powTbl[ 255 - logTbl[i] ];
|
}
|
else
|
{
|
temp = 0;
|
}
|
|
// Affine transformation in GF(2).
|
result = temp ^ 0x63; // Start with adding a vector in GF(2).
|
for( rot = 4; rot > 0; rot-- )
|
{
|
// Rotate left.
|
temp = (temp<<1) | (temp>>7);
|
|
// Add rotated byte in GF(2).
|
result ^= temp;
|
}
|
|
// Put result in table.
|
sBox[i] = result;
|
} while( ++i != 0 );
|
}
|
|
|
|
void CalcSBoxInv( unsigned char * sBox, unsigned char * sBoxInv )
|
{
|
unsigned char i = 0;
|
unsigned char j = 0;
|
|
// Iterate through all elements in sBoxInv using i.
|
do {
|
// Search through sBox using j.
|
do {
|
// Check if current j is the inverse of current i.
|
if( sBox[ j ] == i )
|
{
|
// If so, set sBoxInc and indicate search finished.
|
sBoxInv[ i ] = j;
|
j = 255;
|
}
|
} while( ++j != 0 );
|
} while( ++i != 0 );
|
}
|
|
|
|
void CycleLeft( unsigned char * row )
|
{
|
// Cycle 4 bytes in an array left once.
|
unsigned char temp = row[0];
|
|
row[0] = row[1];
|
row[1] = row[2];
|
row[2] = row[3];
|
row[3] = temp;
|
}
|
|
|
void CalcCols(unsigned char *col)
|
{
|
unsigned char i;
|
|
for(i = 4; i > 0; i--)
|
{
|
*col = (*col << 1) ^ (*col & 0x80 ? BPOLY : 0);
|
col++;
|
}
|
}
|
|
void InvMixColumn( unsigned char * column )
|
{
|
unsigned char r[4];
|
|
r[0] = column[1] ^ column[2] ^ column[3];
|
r[1] = column[0] ^ column[2] ^ column[3];
|
r[2] = column[0] ^ column[1] ^ column[3];
|
r[3] = column[0] ^ column[1] ^ column[2];
|
|
/*column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0);
|
column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0);
|
column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0);
|
column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);*/
|
CalcCols(column);
|
|
r[0] ^= column[0] ^ column[1];
|
r[1] ^= column[1] ^ column[2];
|
r[2] ^= column[2] ^ column[3];
|
r[3] ^= column[0] ^ column[3];
|
|
/*column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0);
|
column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0);
|
column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0);
|
column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);*/
|
CalcCols(column);
|
|
r[0] ^= column[0] ^ column[2];
|
r[1] ^= column[1] ^ column[3];
|
r[2] ^= column[0] ^ column[2];
|
r[3] ^= column[1] ^ column[3];
|
|
/*column[0] = (column[0] << 1) ^ (column[0] & 0x80 ? BPOLY : 0);
|
column[1] = (column[1] << 1) ^ (column[1] & 0x80 ? BPOLY : 0);
|
column[2] = (column[2] << 1) ^ (column[2] & 0x80 ? BPOLY : 0);
|
column[3] = (column[3] << 1) ^ (column[3] & 0x80 ? BPOLY : 0);*/
|
CalcCols(column);
|
|
column[0] ^= column[1] ^ column[2] ^ column[3];
|
r[0] ^= column[0];
|
r[1] ^= column[0];
|
r[2] ^= column[0];
|
r[3] ^= column[0];
|
|
column[0] = r[0];
|
column[1] = r[1];
|
column[2] = r[2];
|
column[3] = r[3];
|
|
//CopyBytes(column, r, 4);
|
}
|
|
|
|
void SubBytes( unsigned char * bytes, unsigned char count )
|
{
|
do {
|
*bytes = sBox[ *bytes ]; // Substitute every byte in state.
|
bytes++;
|
} while( --count );
|
}
|
|
|
|
void InvSubBytesAndXOR( unsigned char * bytes, unsigned char * key, unsigned char count )
|
{
|
do {
|
// *bytes = sBoxInv[ *bytes ] ^ *key; // Inverse substitute every byte in state and add key.
|
*bytes = block2[ *bytes ] ^ *key; // Use block2 directly. Increases speed.
|
bytes++;
|
key++;
|
} while( --count );
|
}
|
|
|
void InvShiftRows( unsigned char * state )
|
{
|
unsigned char temp;
|
|
// Note: State is arranged column by column.
|
|
// Cycle second row right one time.
|
temp = state[ 1 + 3*4 ];
|
state[ 1 + 3*4 ] = state[ 1 + 2*4 ];
|
state[ 1 + 2*4 ] = state[ 1 + 1*4 ];
|
state[ 1 + 1*4 ] = state[ 1 + 0*4 ];
|
state[ 1 + 0*4 ] = temp;
|
|
// Cycle third row right two times.
|
temp = state[ 2 + 0*4 ];
|
state[ 2 + 0*4 ] = state[ 2 + 2*4 ];
|
state[ 2 + 2*4 ] = temp;
|
temp = state[ 2 + 1*4 ];
|
state[ 2 + 1*4 ] = state[ 2 + 3*4 ];
|
state[ 2 + 3*4 ] = temp;
|
|
// Cycle fourth row right three times, ie. left once.
|
temp = state[ 3 + 0*4 ];
|
state[ 3 + 0*4 ] = state[ 3 + 1*4 ];
|
state[ 3 + 1*4 ] = state[ 3 + 2*4 ];
|
state[ 3 + 2*4 ] = state[ 3 + 3*4 ];
|
state[ 3 + 3*4 ] = temp;
|
}
|
|
|
/*
|
void InvMixColumns( unsigned char * state )
|
{
|
InvMixColumn( state + 0*4 );
|
InvMixColumn( state + 1*4 );
|
InvMixColumn( state + 2*4 );
|
InvMixColumn( state + 3*4 );
|
}
|
*/
|
|
|
void XORBytes( unsigned char * bytes1, unsigned char * bytes2, unsigned char count )
|
{
|
do {
|
*bytes1 ^= *bytes2; // Add in GF(2), ie. XOR.
|
bytes1++;
|
bytes2++;
|
} while( --count );
|
}
|
|
|
|
void CopyBytes( unsigned char * to, unsigned char * from, unsigned char count )
|
{
|
do {
|
*to = *from;
|
to++;
|
from++;
|
} while( --count );
|
}
|
|
|
|
void KeyExpansion( unsigned char * expandedKey )
|
{
|
unsigned char temp[4];
|
unsigned char i;
|
unsigned char Rcon[4] = { 0x01, 0x00, 0x00, 0x00 }; // Round constant.
|
|
const unsigned char * key = kTable;
|
|
// Copy key to start of expanded key.
|
i = KEYLENGTH;
|
do {
|
*expandedKey = *key;
|
expandedKey++;
|
key++;
|
} while( --i );
|
|
// Prepare last 4 bytes of key in temp.
|
/*expandedKey -= 4;
|
temp[0] = *(expandedKey++);
|
temp[1] = *(expandedKey++);
|
temp[2] = *(expandedKey++);
|
temp[3] = *(expandedKey++);*/
|
CopyBytes(temp, expandedKey-4, 4);
|
|
// Expand key.
|
i = KEYLENGTH;
|
//j = BLOCKSIZE*(ROUNDS+1) - KEYLENGTH;
|
while( i < BLOCKSIZE*(ROUNDS+1) )
|
{
|
// Are we at the start of a multiple of the key size?
|
if( (i % KEYLENGTH) == 0 )
|
{
|
CycleLeft( temp ); // Cycle left once.
|
SubBytes( temp, 4 ); // Substitute each byte.
|
XORBytes( temp, Rcon, 4 ); // Add constant in GF(2).
|
*Rcon = (*Rcon << 1) ^ (*Rcon & 0x80 ? BPOLY : 0);
|
}
|
|
// Keysize larger than 24 bytes, ie. larger that 192 bits?
|
#if KEYLENGTH > 24
|
// Are we right past a block size?
|
else if( (i % KEYLENGTH) == BLOCKSIZE ) {
|
SubBytes( temp, 4 ); // Substitute each byte.
|
}
|
#endif
|
|
// Add bytes in GF(2) one KEYLENGTH away.
|
XORBytes( temp, expandedKey - KEYLENGTH, 4 );
|
|
// Copy result to current 4 bytes.
|
*(expandedKey++) = temp[ 0 ];
|
*(expandedKey++) = temp[ 1 ];
|
*(expandedKey++) = temp[ 2 ];
|
*(expandedKey++) = temp[ 3 ];
|
//CopyBytes(expandedKey, temp, 4);
|
//expandedKey += 4;
|
|
i += 4; // Next 4 bytes.
|
}
|
}
|
|
|
|
void InvCipher( unsigned char * block, unsigned char * expandedKey )
|
{
|
unsigned char i, j;
|
unsigned char round = ROUNDS-1;
|
expandedKey += BLOCKSIZE * ROUNDS;
|
|
XORBytes( block, expandedKey, 16 );
|
expandedKey -= BLOCKSIZE;
|
|
do {
|
InvShiftRows( block );
|
InvSubBytesAndXOR( block, expandedKey, 16 );
|
expandedKey -= BLOCKSIZE;
|
//InvMixColumns( block );
|
for(i = 4, j = 0; i > 0; i--, j+=4)
|
InvMixColumn( block + j );
|
} while( --round );
|
|
InvShiftRows( block );
|
InvSubBytesAndXOR( block, expandedKey, 16 );
|
}
|
|
|
void aesDecInit(void)
|
{
|
powTbl = block1;
|
logTbl = block2;
|
CalcPowLog( powTbl, logTbl );
|
|
sBox = tempbuf;
|
CalcSBox( sBox );
|
|
expandedKey = block1;
|
KeyExpansion( expandedKey );
|
|
sBoxInv = block2; // Must be block2.
|
CalcSBoxInv( sBox, sBoxInv );
|
}
|
|
void aesDecrypt( unsigned char * buffer, unsigned char * chainBlock )
|
{
|
aesDecInit();
|
CopyBytes( tempbuf, buffer, BLOCKSIZE );
|
InvCipher( buffer, expandedKey );
|
XORBytes( buffer, chainBlock, BLOCKSIZE );
|
CopyBytes( chainBlock, tempbuf, BLOCKSIZE );
|
}
|
|
unsigned char Multiply( unsigned char num, unsigned char factor )
|
{
|
unsigned char mask = 1;
|
unsigned char result = 0;
|
|
while( mask != 0 )
|
{
|
// Check bit of factor given by mask.
|
if( mask & factor )
|
{
|
// Add current multiple of num in GF(2).
|
result ^= num;
|
}
|
|
// Shift mask to indicate next bit.
|
mask <<= 1;
|
|
// Double num.
|
num = (num << 1) ^ (num & 0x80 ? BPOLY : 0);
|
}
|
|
return result;
|
}
|
|
|
unsigned char DotProduct( const unsigned char * vector1, unsigned char * vector2 )
|
{
|
unsigned char result = 0 ,i;
|
|
//result ^= Multiply( *vector1++, *vector2++ );
|
//result ^= Multiply( *vector1++, *vector2++ );
|
//result ^= Multiply( *vector1++, *vector2++ );
|
//result ^= Multiply( *vector1 , *vector2 );
|
|
for(i = 4; i > 0; i--)
|
result ^= Multiply( *vector1++, *vector2++ );
|
|
return result;
|
}
|
|
|
void MixColumn( unsigned char * column )
|
{
|
const unsigned char row[8] = {
|
0x02, 0x03, 0x01, 0x01,
|
0x02, 0x03, 0x01, 0x01
|
}; // Prepare first row of matrix twice, to eliminate need for cycling.
|
|
unsigned char result[4];
|
|
// Take dot products of each matrix row and the column vector.
|
result[0] = DotProduct( row+0, column );
|
result[1] = DotProduct( row+3, column );
|
result[2] = DotProduct( row+2, column );
|
result[3] = DotProduct( row+1, column );
|
|
// Copy temporary result to original column.
|
//column[0] = result[0];
|
//column[1] = result[1];
|
//column[2] = result[2];
|
//column[3] = result[3];
|
CopyBytes(column, result, 4);
|
}
|
/*
|
void MixColumns( unsigned char * state )
|
{
|
MixColumn( state + 0*4 );
|
MixColumn( state + 1*4 );
|
MixColumn( state + 2*4 );
|
MixColumn( state + 3*4 );
|
}
|
*/
|
void ShiftRows( unsigned char * state )
|
{
|
unsigned char temp;
|
|
// Note: State is arranged column by column.
|
|
// Cycle second row left one time.
|
temp = state[ 1 + 0*4 ];
|
state[ 1 + 0*4 ] = state[ 1 + 1*4 ];
|
state[ 1 + 1*4 ] = state[ 1 + 2*4 ];
|
state[ 1 + 2*4 ] = state[ 1 + 3*4 ];
|
state[ 1 + 3*4 ] = temp;
|
|
// Cycle third row left two times.
|
temp = state[ 2 + 0*4 ];
|
state[ 2 + 0*4 ] = state[ 2 + 2*4 ];
|
state[ 2 + 2*4 ] = temp;
|
temp = state[ 2 + 1*4 ];
|
state[ 2 + 1*4 ] = state[ 2 + 3*4 ];
|
state[ 2 + 3*4 ] = temp;
|
|
// Cycle fourth row left three times, ie. right once.
|
temp = state[ 3 + 3*4 ];
|
state[ 3 + 3*4 ] = state[ 3 + 2*4 ];
|
state[ 3 + 2*4 ] = state[ 3 + 1*4 ];
|
state[ 3 + 1*4 ] = state[ 3 + 0*4 ];
|
state[ 3 + 0*4 ] = temp;
|
}
|
|
|
void Cipher( unsigned char * block, unsigned char * expandedKey )
|
{
|
unsigned char i, j;
|
unsigned char round = ROUNDS-1;
|
|
XORBytes( block, expandedKey, 16 );
|
expandedKey += BLOCKSIZE;
|
|
do {
|
SubBytes( block, 16 );
|
ShiftRows( block );
|
//MixColumns( block );
|
for(i = 4, j = 0; i > 0; i--, j+=4)
|
MixColumn( block + j );
|
XORBytes( block, expandedKey, 16 );
|
expandedKey += BLOCKSIZE;
|
} while( --round );
|
|
SubBytes( block, 16 );
|
ShiftRows( block );
|
XORBytes( block, expandedKey, 16 );
|
}
|
|
void aesEncInit(void)
|
{
|
powTbl = block1;
|
logTbl = block2;
|
CalcPowLog( powTbl, logTbl );
|
|
sBox = block2;
|
CalcSBox( sBox );
|
|
expandedKey = block1;
|
KeyExpansion( expandedKey );
|
}
|
|
void aesEncrypt( unsigned char * buffer, unsigned char * chainBlock )
|
{
|
aesEncInit();
|
XORBytes( buffer, chainBlock, BLOCKSIZE );
|
Cipher( buffer, expandedKey );
|
CopyBytes( chainBlock, buffer, BLOCKSIZE );
|
}
|