
#include <stdio.h>
#include <stdlib.h>

unsigned char xtimetbl[] = {
  0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
  0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
  0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
  0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
  0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e,
  0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
  0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
  0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
  0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
  0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
  0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
  0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
  0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
  0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
  0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
  0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
  0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15,
  0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
  0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35,
  0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
  0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55,
  0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
  0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75,
  0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
  0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95,
  0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
  0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5,
  0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
  0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5,
  0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
  0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5,
  0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
};

unsigned char Logtable[256] = {
  0,   0,  25,   1,  50,   2,  26, 198,  75, 199,  27, 104,  51, 238, 223,  3,
  100,   4, 224,  14,  52, 141, 129, 239,  76, 113,   8, 200, 248, 105,  28,
  193, 125, 194,  29, 181, 249, 185,  39, 106,  77, 228, 166, 114, 154, 201,
  9, 120, 101,  47, 138,   5,  33,  15, 225,  36,  18, 240, 130,  69,  53,
  147, 218, 142, 150, 143, 219, 189,  54, 208, 206, 148,  19,  92, 210, 241,
  64,  70, 131,  56, 102, 221, 253,  48, 191,   6, 139,  98, 179,  37, 226,
  152,  34, 136, 145,  16, 126, 110,  72, 195, 163, 182,  30,  66,  58, 107,
  40,  84, 250, 133,  61, 186, 43, 121,  10,  21, 155, 159,  94, 202,  78,
  212, 172, 229, 243, 115, 167,  87, 175,  88, 168,  80, 244, 234, 214, 116,
  79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235,  22,  11,
  245,  89, 203,  95, 176, 156, 169,  81, 160, 127,  12, 246, 111,  23, 196,
  73, 236, 216,  67,  31,  45, 164, 118, 123, 183, 204, 187,  62,  90, 251,
  96, 177, 134,  59,  82, 161, 108, 170,  85,  41, 157, 151, 178, 135, 144,
  97, 190, 220, 252, 188, 149, 207, 205,  55,  63,  91, 209, 83,  57, 132,
  60,  65, 162, 109,  71,  20,  42, 158,  93,  86, 242, 211, 171, 68,  17,
  146, 217,  35,  32,  46, 137, 180, 124, 184,  38, 119, 153, 227, 165, 103,  
  74, 237, 222, 197,  49, 254,  24,  13,  99, 140, 128, 192, 247, 112,   7, 
};

unsigned char Alogtable[256] = {
  1,   3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19, 
  53, 95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34,
  102, 170, 229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144,
  171, 230,  49,  83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184,
  211, 110, 178, 205,  76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,
  8,  24,  40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152,
  179, 206,  73, 219, 118, 154, 181, 196,  87, 249,  16,  48,  80, 240,  11,
  29,  39, 105, 187, 214,  97, 163, 254,  25,  43, 125, 135, 146, 173, 236,
  47, 113, 147, 174, 233,  32,  96, 160, 251,  22,  58,  78, 210, 109, 183,
  194,  93, 231,  50,  86, 250,  21,  63,  65, 195,  94, 226,  61,  71, 201,
  64, 192,  91, 237,  44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172,
  239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193,  88,
  232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84, 252,  31,  33,
  99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,  69, 207,
  74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,  18,
  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
  57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246, 1, 
};

unsigned char S[256] = {
  99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171,
  118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164,
  114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113,
  216,  49,  21,  4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226,
  235,  39, 178, 117,  9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214,
  179,  41, 227,  47, 132, 83, 209,   0, 237,  32, 252, 177,  91, 106, 203,
  190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69,
  249,   2, 127,  80,  60, 159, 168, 81, 163,  64, 143, 146, 157,  56, 245,
  188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,
  23, 196, 167, 126,  61, 100,  93,  25, 115, 96, 129,  79, 220,  34,  42,
  144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
  6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109, 
  141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,
  46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62,
  181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
  248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223, 
  140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,
  22, 
};

unsigned char Si[256] = {
  82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215,
  251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222,
  233, 203, 84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66,
  250, 195,  78,  8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73,
  109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92,
  204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,
  70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247,
  228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2,
  193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220,
  234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
  53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29,
  41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75,
  198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
  51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
  127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
  224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
  23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
  125, 
};

unsigned char iG[4][4] = {
  { 0x0e, 0x09, 0x0d, 0x0b }, 
  { 0x0b, 0x0e, 0x09, 0x0d }, 
  { 0x0d, 0x0b, 0x0e, 0x09 }, 
  { 0x09, 0x0d, 0x0b, 0x0e }, 
};

unsigned char rcon[30] = { 
  0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
  0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
  0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
};

static char shifts[3][4][2] = {
  { { 0, 0 }, { 1, 3 }, { 2, 2 }, { 3, 1 } },

  { { 0, 0 }, { 1, 5 }, { 2, 4 }, { 3, 3 } },
   
  { { 0, 0 }, { 1, 7 }, { 3, 5 }, { 4, 4 } }
};

/* Assembly functions in rijndael_asm.s */
extern void rijndael_encrypt(unsigned char a[16], unsigned char rk[240]);
extern void rijndael_decrypt(unsigned char a[16], unsigned char rk[240]);
extern void rijndael_keygen(unsigned char k[32], unsigned char W[240]);

void print_txt(unsigned char *txt)
{
  int j;

  for (j=0; j<16; j++)
    printf("%02x", txt[j]);
  printf("\n");
}

void print_int(int d)
{
  printf("%d ", d);
}

void print_char(unsigned char c)
{
  printf("%02x\n", c);
}

void print_key(unsigned char *key)
{
  int j;

  for (j=0; j<32; j++)
      printf("%02x", key[j]);
  printf("\n");
}

void print_roundkeys(unsigned char rk[240])
{
  int i;

  for (i=0; i<15; i++)
    print_txt(&rk[i*16]);
}

void print_4bytes(unsigned char a, unsigned char b, unsigned char c,
		  unsigned char d)
{
  printf("%02x", a);
  printf("%02x", b);
  printf("%02x", c);
  printf("%02x\n", d);
}

/* These routines are hardcoded so that Rijndael will use only 256-bit
   keys (32 bytes) and 128-bit blocks (16 bytes) */

/* multiply two elements of GF(2^m)
 * needed for MixColumn and InvMixColumn */
unsigned char mul(unsigned char a, unsigned char b)
{
  if (a && b) return Alogtable[(Logtable[a] + Logtable[b])%255];
  else return 0;
}

/* Exor corresponding text input and round key input bytes */
void key_addition(unsigned char a[16], unsigned char *rk)
{
  int i;

  for(i = 0; i < 16; i++) 
    a[i] ^= rk[i];
}

/* Row 0 remains unchanged
 * The other three rows are shifted a variable amount */
void shift_row(unsigned char a[16], unsigned char d)
{
  unsigned char tmp[4];
  int i, j;

  for(i = 1; i < 4; i++) {
    for(j = 0; j < 4; j++)
      tmp[j] = a[i*4 + (j + shifts[0][i][d]) % 4];
    for(j = 0; j < 4; j++)
      a[i*4 + j] = tmp[j];
  }
}

/* Replace every byte of the input by the byte at that place
 * in the nonlinear S-box */
void s_box(unsigned char a[16], unsigned char box[256])
{
  int i;

  for(i = 0; i < 16; i++)
    a[i] = box[a[i]];
}

/* Mix the four bytes of every column in a linear way */
void mix_column_orig(unsigned char a[16])
{
  unsigned char b[4][4];
  int i, j;

  for(j = 0; j < 4; j++) {
    for(i = 0; i < 4; i++) {
      b[i][j] = mul(2, a[i*4 + j])
	^ mul(3, a[((i + 1) % 4)*4 + j])
	^ a[((i + 2) % 4)*4 + j]
	^ a[((i + 3) % 4)*4 + j];
    }
  }
  for(i = 0; i < 4; i++) {
    for(j = 0; j < 4; j++)
      a[i*4 + j] = b[i][j];
  }
}

/* Mix the four bytes of every column in a linear way.  Uses more efficient
   method. */
void mix_column(unsigned char a[16])
{
  int i, j;
  unsigned char tmp, b[4];

  for(j = 0; j < 4; j++) {
    tmp = a[j] ^ a[j+4] ^ a[j+8] ^ a[j+12];
    for (i=0; i<4; i++)
      b[i] = a[i*4 + j];
    b[0] ^= xtimetbl[a[j] ^ a[j+4]] ^ tmp;
    b[1] ^= xtimetbl[a[j+4] ^ a[j+8]] ^ tmp;
    b[2] ^= xtimetbl[a[j+8] ^ a[j+12]] ^ tmp;
    b[3] ^= xtimetbl[a[j+12] ^ a[j]] ^ tmp;
    for (i=0; i<4; i++)
      a[i*4 + j] = b[i];
  }
}

/* Mix the four bytes of every column in a linear way
 * This is the opposite operation of Mixcolumn */
void inv_mix_column(unsigned char a[16])
{
  unsigned char b[4][4];
  int i, j;

  for(j = 0; j < 4; j++) {
    for(i = 0; i < 4; i++) {
      b[i][j] = mul(0xe, a[i*4 + j])
	^ mul(0xb, a[((i + 1) % 4)*4 + j])
	^ mul(0xd, a[((i + 2) % 4)*4 + j])
	^ mul(0x9, a[((i + 3) % 4)*4 + j]);
    }
  }
  for(i = 0; i < 4; i++) {
    for(j = 0; j < 4; j++)
      a[i*4 + j] = b[i][j];
  }
}

/* Many thanks to Vincent Rijmen for clarifying matters here... */
void rijndael_keygen_c(unsigned char k[32], unsigned char W[240])
{
  int i, j;
  unsigned char temp[4], tmp;

  for (i=0; i<4; i++) {
    for (j=0; j<4; j++)
      W[j*4 + i] = k[i*4 + j];
    for (j=0; j<4; j++)
      W[j*4 + i + 16] = k[i*4 + j + 16];
  }

  for (i=8; i<60; i++) {
    for (j=0; j<4; j++)
      temp[j] = W[(((i-1)&0xfc)<<2) + ((i-1)&0x03) + j*4];
    if (i % 8 == 0) {
      for (j=0; j<4; j++)
	temp[j] = S[temp[j]];
      tmp = temp[0];
      for (j=1; j<4; j++)
	temp[j-1] = temp[j];
      temp[3] = tmp;
      temp[0] ^= rcon[i/8-1];
    } else if (i % 8 == 4) {
      for (j=0; j<4; j++)
	temp[j] = S[temp[j]];
    }
    for (j=0; j<4; j++)
      W[((i&0xfc)<<2) + (i&0x03) + j*4] =
	W[(((i-8)&0xfc)<<2) + ((i-8)&0x03) + j*4] ^ temp[j];
  }
}

/* Encryption of one block. */      
int rijndael_encrypt_c(unsigned char a[16], unsigned char rk[240])
{
  int r, ROUNDS=14;

  /* begin with a key addition */
  key_addition(a, &rk[0]);

  /* ROUNDS-1 ordinary rounds */
  for(r = 1; r < ROUNDS; r++) {
    s_box(a, S);
    shift_row(a, 0);
    mix_column(a);
    key_addition(a, &rk[r*16]);
  }

  /* Last round is special: there is no MixColumn */
  s_box(a, S);
  shift_row(a,0);
  key_addition(a, &rk[16*ROUNDS]);

  return 0;
}   

/* To decrypt: apply the inverse operations of the encrypt routine,
 *             in opposite order
 * 
 * (KeyAddition is an involution: it's equal to its inverse)
 * (the inverse of Substitution with table S is Substitution with the inverse
 * table of S)
 * (the inverse of Shiftrow is Shiftrow over a suitable distance)
 */
int rijndael_decrypt_c(unsigned char a[16], unsigned char rk[240])
{
  int r, ROUNDS=14;

  /* First the special round:
   *   without InvMixColumn
   *   with extra KeyAddition */
  key_addition(a, &rk[ROUNDS*16]);
  s_box(a, Si);
  shift_row(a, 1);

  /* ROUNDS-1 ordinary rounds */
  for(r = ROUNDS-1; r > 0; r--) {
    key_addition(a, &rk[r*16]);
    inv_mix_column(a);
    s_box(a, Si);
    shift_row(a, 1);
  }

  /* End with the extra key addition */
  key_addition(a, &rk[0]);

  return 0;
}

int main(void)
{
  unsigned char txt[16], key[32];
  unsigned char subkeys[240];
  int i, j;

  j = 3;
  for (i=0; i<4; i++) {
    txt[i*4 + 3] = (unsigned char)j--;
    txt[i*4] = txt[i*4 + 1] = txt[i*4 + 2] = 0;
  }
  for (i=0; i<32; i++)
    key[i] = i;

  rijndael_keygen_c(key, subkeys);
  printf("Results of encryption:\n\n");
  printf("Plaintext = ");
  print_txt(txt);
  printf("Key = ");
  print_key(key);
  rijndael_encrypt_c(txt, subkeys);
  printf("Ciphertext (C) = ");
  print_txt(txt);
  rijndael_decrypt_c(txt, subkeys);
  printf("Decrypted plaintext (C) = ");
  print_txt(txt);
  rijndael_keygen(key, subkeys);
  rijndael_encrypt(txt, subkeys);
  printf("Ciphertext (asm) = ");
  print_txt(txt);
  printf("Decrypted plaintext (asm) = ");
  rijndael_decrypt(txt, subkeys);
  print_txt(txt);
  return(0);
}
