Skip to content

Instantly share code, notes, and snippets.

@eqdw
Created July 6, 2013 00:21
Show Gist options
  • Save eqdw/5938000 to your computer and use it in GitHub Desktop.
Save eqdw/5938000 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
//Input filename typedefs
#define SBOX "aes_sbox.txt"
#define INVSBOX "aes_inv_sbox.txt"
//Number of 32-bit words comprising the state
#define Nb 4
//Number of 32-bit words comprising the key
#define Nk 4
//Number of iterations
#define Nr 10
//The magick numbers
#define MODPOLY 0x1B
//Yay programmatic interfaces!
typedef unsigned int word;
typedef unsigned char byte;
//PROTOTYPES
void printKeySchedule(void);
void initSBox(const char * filename);
void printState(void);
void subBytes(void);
void shiftRows(void);
void shiftLeft(int n);
void mixColumns(void);
byte x3(byte in);
byte xtime(byte in);
void addRoundKey(void);
word wordify(byte a, byte b, byte c, byte d);
void dewordify(word inword, byte * accum);
void keyExpansion(void);
word rotWord(word inword);
word subWord(word inword);
void encrypt(char * infile, char * inkey);
int main(void);
void initInvSBox(const char * filename);
byte xe(byte in);
byte xb(byte in);
byte xd(byte in);
byte x9(byte in);
void invMixColumns(void);
void invSubBytes(void);
void invShiftRows(void);
void shiftRight(int n);
void decrypt(void);
int roundNum;
byte state[4][4];
byte sbox[256];
byte invsbox[256];
byte key[16];
word w[44];
//Round constants!
word Rcon[] = {0x00000000, 0x01000000, 0x02000000, 0x04000000,
0x08000000, 0x10000000, 0x20000000, 0x40000000,
0x80000000, 0x1B000000, 0x36000000};
////////////////////////////////////////////////////////////
/////////////////////UTILITY FUNCTIONS//////////////////////
////////////////////////////////////////////////////////////
void printKeySchedule(void)
{
int i;
for(i=0;i<44;i++)
{
printf("%.8x ",w[i]);
if((i%4)==3)
printf("\n");
}
printf("\n");
}
void initInvSBox(const char * filename)
{
FILE * infile = fopen(filename, "r");
int i;
int temp[256];
for(i=0;i<256;i++)
{
fscanf(infile,"%x", &temp[i]);
}
for(i=0; i< 256; i++)
invsbox[i] = temp[i];
fclose(infile);
}
void initSBox(const char * filename)
{
FILE * infile = fopen(filename, "r");
int i;
int temp[256];
//reads one byte of the table at a time
for(i=0; i < 256; i++)
{
fscanf(infile, "%x", &temp[i]);
}
//now apparently C hates reading in 1-byte numbers. So I had to read them in as
//ints, and now will be implicitly casting them.
//NOTE: This could make bad things happen under normal circumstances, because
//implicit cast from int->char makes data get lost. However, since we know
//that every value read in from the sbox data file is 0<=val<=255, this will
//NEVER occur
for(i=0; i< 256; i++)
sbox[i] = temp[i];
fclose(infile);
}
//Utility method:
void printState(void)
{
int i, j;
// printf("Current State:\n");
for(i=0; i < 4; i++)
{
for(j=0;j<4;j++)
{
printf("%.2x ", state[i][j]);
}
printf("\n");
}
printf("\n");
}
////////////////////////////////////////////////////////////
/////////////////END UTILITY FUNCTIONS//////////////////////
////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////
//THE FOLLOWING SECTION IS WITH REGARDS TO ENCRYPTION//
///////////////////////////////////////////////////////
void subBytes(void)
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state[i][j] = sbox[state[i][j]];
}
/*
//alternative code:
void subBytes(void)
{
int i;
for(i=0;i<16;i++)
state[i/4][i%4] = sbox[state[i/4][i%4]]
}
*/
void shiftRows(void)
{
int i,j;
for(i=0; i<4; i++)
for(j=i; j>0; j--)
shiftLeft(i);
}
//helper function. Shifts a row of state (specified by n) ONE shift left
void shiftLeft(int n)
{
byte temp = state[n][0];
state[n][0] = state[n][1];
state[n][1] = state[n][2];
state[n][2] = state[n][3];
state[n][3] = temp;
}
//This one's the painful one :(
//I'll the the Matrix Mult now so the program doesn't have to
//
//let * = GF(2**8) multiplication and ^ = GF(2**8) addition
//
// for each column
// elem0 = (2*elem0) ^ (3*elem1) ^ elem2 ^ elem3
// elem1 = elem0 ^ (2*elem1) ^ (3*elem2) ^ elem3
// elem2 = elem0 ^ elem1 ^ (2*elem2) ^ (3*elem3)
// elem3 = (3*elem0) ^ elem1 ^ elem2 ^ (2*elem3)
//
//keep in mind that 3 * elem = (elem ^ (2*elem))
void mixColumns(void)
{
byte new[4];
int i,j;
//for each column
for(i=0;i<4;i++)
{
//zero out new[] just in case
for(j=0;j<4;j++)
new[j]=0;
new[0] = xtime(state[0][i]) ^ x3(state[1][i]) ^ state[2][i] ^ state[3][i];
new[1] = state[0][i] ^ xtime(state[1][i]) ^ x3(state[2][i]) ^ state[3][i];
new[2] = state[0][i] ^ state[1][i] ^ xtime(state[2][i]) ^ x3(state[3][i]);
new[3] = x3(state[0][i]) ^ state[1][i] ^ state[2][i] ^ xtime(state[3][i]);
state[0][i] = new[0];
state[1][i] = new[1];
state[2][i] = new[2];
state[3][i] = new[3];
}
}
//for conciseness
// multiplying by x**2 + x is the same as
// a left shift followed by an xor with the original value
byte x3(byte in)
{
return ( in ^ xtime(in));
}
//multiply by x in GF(2**8)
byte xtime(byte in)
{
//check if we need to reduce
// 0x80 = 1000 0000
int flag = (in & 0x80);
//mult by x (ie leftshift
in <<= 1;
if(flag /* != 0 */ )
in ^= MODPOLY;
return in;
}
void addRoundKey(void)
{
// printf("\n AddRoundKey() entered\n");
int i,j;
word colKey;
byte colKeyBytes[4];
//reversed the typical roles of i and j because we're indexing state
//as column-major (effectively). This reminds me so I dont' confuse myself
for(j=0;j<4;j++)
{
//grab current round key word
colKey = w[roundNum*Nb + j];
dewordify(colKey, colKeyBytes);
// printf(" column %d: %x %x %x %x\n", j, colKeyBytes[0],
// colKeyBytes[1], colKeyBytes[2], colKeyBytes[3]);
for(i=0;i<4;i++)
{
state[i][j] = state[i][j] ^ colKeyBytes[i];
}
}
}
///////////////////////////////////////////////////////
//////////////////////END ENCRYPTION///////////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////DECRYPTION FUNCTIONS////////////////////
///////////////////////////////////////////////////////////
// 0 e
// 0000 1110 = x8(in) + x4(in) + xtime(in)
byte xe(byte in)
{
return xtime(xtime(xtime(in))) ^ xtime(xtime(in)) ^ xtime(in);
}
// 0 b
// 0000 1011 = x8(in) + xtime(in) + in
byte xb(byte in)
{
return xtime(xtime(xtime(in))) ^ xtime(in) ^ in;
}
// 0 d
// 0000 1101 = x8(in) + x4(in) + x
byte xd(byte in)
{
return xtime(xtime(xtime(in))) ^ xtime(xtime(in)) ^ in;
}
// 0 9
// 0000 1001 = x8(in) + x
byte x9(byte in)
{
return xtime(xtime(xtime(in))) ^ in;
}
void invMixColumns(void)
{
byte new[4];
int i,j;
//for each column
for(i=0;i<4;i++)
{
//zero out new[] just in case
for(j=0;j<4;j++)
new[j]=0;
new[0] = xe(state[0][i]) ^ xb(state[1][i]) ^ xd(state[2][i]) ^ x9(state[3][i]);
new[1] = x9(state[0][i]) ^ xe(state[1][i]) ^ xb(state[2][i]) ^ xd(state[3][i]);
new[2] = xd(state[0][i]) ^ x9(state[1][i]) ^ xe(state[2][i]) ^ xb(state[3][i]);
new[3] = xb(state[0][i]) ^ xd(state[1][i]) ^ x9(state[2][i]) ^ xe(state[3][i]);
state[0][i] = new[0];
state[1][i] = new[1];
state[2][i] = new[2];
state[3][i] = new[3];
}
}
void invSubBytes(void)
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
state[i][j] = invsbox[state[i][j]];
}
void invShiftRows(void)
{
int i,j;
for(i=0; i<4; i++)
for(j=i; j>0; j--)
shiftRight(i);
}
void shiftRight(int n)
{
byte temp = state[n][3];
state[n][3] = state[n][2];
state[n][2] = state[n][1];
state[n][1] = state[n][0];
state[n][0] = temp;
}
///////////////////////////////////////////////////////////
//////////////////////END DECRYPTION///////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
//THE FOLLOWING SECTION IS WITH REGARDS TO KEY SCHEDULING//
///////////////////////////////////////////////////////////
//turns 4 bytes into a word
word wordify(byte a, byte b, byte c, byte d)
{
word rtn = a;
rtn <<= 8;
rtn += b;
rtn <<= 8;
rtn += c;
rtn <<= 8;
rtn += d;
return rtn;
}
//converts a word into an array of 4 bytes.
//Uses the stupid cumbersome pointer thing to return the array
void dewordify(word inword, byte * accum)
{
/* printf("\n dewordify entered!\n"); */
/* printf(" inword = %x\n", inword); */
word mask = 0x000000FF;
int i;
for(i=3; i>=0; i--)
{
/* printf(" inword & mask: %x\n", inword & mask); */
accum[i] = (byte) inword & mask;
/* printf(" accum[%d] = %x\n", i, accum[i]); */
/* printf(" inword before shift: %x\n", inword); */
inword >>= 8;
/* printf(" inword after shift: %x\n", inword); */
}
}
void keyExpansion(void)
{
word temp;
int i;
for(i=0; i < Nk; i++)
{
w[i] = wordify(key[4*i], key[4*i + 1], key[4*i + 2], key[4*i + 3]);
}
for(i = Nk; i < (Nb*(Nr+1)); i++)
{
temp = w[i-1];
// printf("DEBUG --- temp: %x\n", temp);
if((i % Nk) == 0)
{
temp = rotWord(temp);
// printf("DEBUG --- after RotWord(): %x\n", temp);
temp = subWord(temp);
// printf("DEBUG --- after SubWord(): %x\n", temp);
// printf("DEBUG --- Rcon[%d]: %x\n", i/Nk, Rcon[i/Nk]);
temp ^= Rcon[i/Nk];
// printf("DEBUG --- after XOR with Rcon: %x\n", temp);
}
// printf("DEBUG --- w[%d]: %x\n", i-Nk, w[i-Nk]);
// printf("DEBUG --- temp XOR w[%d]: %x\n", i-Nk, temp ^ w[i-Nk]);
w[i] = w[i-Nk] ^ temp;
}
}
//It's pretty much a transliteration from the FIPS 197 document
word rotWord(word inword)
{
/* printf("\n rotWord() entered!\n"); */
int i;
byte bytes[4];
byte temp;
dewordify(inword, bytes);
/* printf(" dewordified %x\n", inword); */
for(i=0;i<4;i++)
/* printf(" bytes[%d] = %x\n", i, bytes[i]); */
temp = bytes[0];
bytes[0] = bytes[1];
bytes[1] = bytes[2];
bytes[2] = bytes[3];
bytes[3] = temp;
return wordify(bytes[0], bytes[1], bytes[2], bytes[3]);
}
//S-Boxes the crap out of those words!
word subWord(word inword)
{
int i;
byte bytes[4];
//dewordify
dewordify(inword, bytes);
//sub
for(i=0; i < 4; i++)
bytes[i] = sbox[bytes[i]];
return wordify(bytes[0], bytes[1], bytes[2], bytes[3]);
}
///////////////////////////////////////////////////////
///////////////END KEY SCHEDULING SECTION//////////////
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////
//////////////////BEGIN MAENAM SECTION/////////////////
///////////////////////////////////////////////////////
void encrypt(char * infile, char * inkey)
{
printf("PlainText filename: %s\n", infile);
printf("Key filename: %s\n", inkey);
roundNum = 0;
int i,j;
//init state and key
int temp[4][4];
int tempkey[16];
FILE * pfile = fopen(infile,"r");
for(j=0;j<4;j++)
for(i=0;i<4;i++)
{
fscanf(pfile, "%x", &temp[i][j]);
state[i][j] = temp[i][j];
}
fclose(pfile);
FILE * pkey = fopen(inkey, "r");
for(i=0;i<16;i++)
{
fscanf(pkey, "%x", &tempkey[i]);
key[i] = tempkey[i];
}
fclose(pkey);
keyExpansion();
printKeySchedule();
//END STATE INIT
printf("Encryption starting!\n");
printState();
addRoundKey();
printf("After initial addRoundKey:\n");
printState();
for(roundNum=1;roundNum<Nr;roundNum++)
{
// printf("Round: %d\n", roundNum);
// printState() ;
// printf("After SubBytes:\n");
subBytes() ;
// printState() ;
//printf("After ShiftRows:\n");
shiftRows() ;
//printState() ;
//printf("After MixCloumns:\n");
mixColumns() ;
//printState() ;
//printf("After AddRoundKey:\n");
addRoundKey();
printf("After Round %d\n", roundNum);
printState() ;
}
//printf("After final SubBytes:\n");
subBytes();
//printState();
//printf("After final ShiftRows:\n");
shiftRows();
//printState();
//printf("After final AddRoundKey:\n");
addRoundKey();
//printState();
printf("\n\n FINAL CYPHER OUTPUT: ");
for(j=0;j<4;j++)
for(i=0;i<4;i++)
printf("%.2x ", state[i][j]);
printf("\n\n");
}
//uses existing key, and cyphertext will be in state.
void decrypt(void)
{
int i,j;
printf("Beginning decryption!\n");
printState();
addRoundKey();
printf("After initial addRoundKey:\n");
printState();
for(roundNum=9; roundNum>=1;roundNum--)
{
//printf("Round: %d\n", roundNum);
//printState() ;
//printf("After InvShiftRows:\n");
invShiftRows() ;
//printState() ;
//printf("After InvSubBytes:\n");
invSubBytes() ;
//printState() ;
//printf("After AddRoundKey:\n");
addRoundKey() ;
//printState() ;
//printf("After InvMixColumns:\n");
invMixColumns();
printf("After round %d\n", roundNum);
printState() ;
}
//printf("After final InvShiftRows:\n");
invShiftRows();
//printState();
//printf("After final InvSubBytes:\n");
invSubBytes();
//printState();
//printf("After final AddRoundKey:\n");
addRoundKey();
//printState();
printf("\n\n ORIGINAL PLAINTEXT: ");
for(j=0;j<4;j++)
for(i=0;i<4;i++)
printf("%.2x ", state[i][j]);
printf("\n\n");
}
int main(void)
{
initSBox(SBOX);
initInvSBox(INVSBOX);
encrypt("test1plaintext.txt", "test1key.txt");
decrypt();
encrypt("test2plaintext.txt", "test2key.txt");
decrypt();
encrypt("test3plaintext.txt", "test3key.txt");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment