AES/C

Return to main page



/* ----------------------------------------------------------
//
// An AES implementation for 32-bit platforms
//
// Release 1.4  
//
// Release date: 10th October 2003
//
// Consisting of a principal part (this file) and a (separate) 
// Supplement. 
//
// Author: Mok-Kong Shen, Munich, Germany
//
// Last date of site modification: (currently empty)
//
//
// Design assumptions: Size of unsigned int 32 bits.
//                     Size of unsigned char 8 bits.
//                     Sequential processing model.
//
// See copyright notice further below.
//
// For application runs, include the package as header file
// and invoke in the main program:
//
// (a) one call of aessetup(keylength), where keylength is 
//     one of 128, 192 and 256.
//
// (b) after placing the user-given key in the byte-array 
//     ukey.b[16], one call of aeskeyschedule(encrypt) or 
//     aeskeyschedule(decrypt), depending on whether 
//     encryption or decryption is to be done.
//
// (c) one call of aesprocess() for processing each input 
//     block provided in the byte-array aesin.b[16] to result 
//     in the output block in the byte-array aesout.b[16].
//
// Redo (a), if a different keylength is to be used. Redo 
// (b), if one changes key or switches from encryption to 
// decryption (or vice versa).
//
// For a demonstration with the example vectors of FIPS-197,
// Appendix C, and benchmarking of the individual functions
// mentioned in (a), (b) and (c) above, include the package 
// as header file and invoke in a main program the function
// call aesdemo(). Check carefully with FIPS-197 that the 
// results (ciphertexts and recovered plaintexts) are indeed 
// correct before any practical applications of the package.
//
// The Supplement is informative only and is intended for 
// rendering easier the understanding or checking of certain 
// functions and for benchmark comparisons with other AES 
// implementations.
//
// Release 1.4, as originally issued, is available at 
// http://home.t-online.de/home/mok-kong.shen.
//
------------------------------------------------------------- */

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

typedef unsigned char byte;
typedef unsigned int word;

typedef union 
{ byte b[4];
  word w;
} UU;

typedef union 
{ byte b[16];
  byte bm[4][4];
  word w[4];
} BLOCK;

/* ----------------------------------------------------------
// aesin and aesout are input/output of the function aesprocess.
// These are to be considered by the user as byte-arrays, not as
// arrays of unsigned int. Beware of confusion and potential
// errors due to the endian-ness of hardware, resulting in
// non-interoperability, when implementing CTR mode with integer
// arithmetic operations without due consideration of the
// effect of endian-ness.
------------------------------------------------------------- */

BLOCK aesin,aesout;

const int Nb=4; 

int Nk,Nr,Nr4minus1;  

int ekeywdim,ekeywdimminus1,roundpairs;

int aessetupdone=0;

/* ----------------------------------------------------------
// ukey is the user-given key, ekey is the expanded key.
// Maximum storage space is provided for ukey and ekey. Size of
// ekey provides for a max. of 14 rounds. The actual size in 
// words is Nk for ukey and ekeywdim for ekey. See FIPS-197 and 
// the function aessetup. For ekey, for implementation reasons,
// four additional words are provided but not actually used in 
// encryption/decrpyption processing, see the function 
// aeskeyschedule.
------------------------------------------------------------- */

typedef union 
{ byte b[32];
  byte bm[8][4];
  word w[8];
} USERKEY;

USERKEY ukey;

typedef union 
{ byte b[256];
  byte bm[64][4];
  word w[64];
} EXPANDEDKEY;

EXPANDEDKEY ekey;

/* ----------------------------------------------------------
// For elements of the array sbox, see FIPS-197. 
------------------------------------------------------------- */

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

byte invsbox[256];

byte gfmult(byte a, byte b)
{ byte r,t;
  if (a < b) { t=b; b=a; a=t; }
  r=0;
  do 
  { if (b&0x01) r^=a;
    if (a&0x80) a=(a<<1)^0x1b; else a<<=1;
  } while (b>>=1);
  return r;
}

typedef union 
{ byte b[1024];
  byte bm[256][4];
  word w[256];
} TABLE;

/* ----------------------------------------------------------
// The tables t's and v's are for encryption and decryption 
// respectively. (See the book of Daemen and Rijmen, pp.56-59,
// for detailed explanation of the tables t's.)
// The tables z's are similar to the v's but without the 
// involvement of substitution. The tables u's and w's are 
// similar to the tables t's and v's but use an identity 
// matrix. The table y is the identity of the byte extended 
// with three zero bytes. 
// We have introduced the additional tables u's, w's, y and 
// z's for enabling more efficient processing in the functions
// asekeyschedule and aesprocess.
------------------------------------------------------------- */

TABLE t0,t1,t2,t3,u0,u1,u2,u3,v0,v1,v2,v3,w0,w1,w2,w3,y,
      z0,z1,z2,z3;

void computetables()
{ int i,j;
  byte s,r;
  for (i=0; i<256; i++) invsbox[sbox[i]]=i;
  for (i=0; i<256; i++) 
  { s=sbox[i];
    t0.bm[i][0]=gfmult(s,0x02); t0.bm[i][1]=t0.bm[i][2]=s; 
    t0.bm[i][3]=gfmult(s,0x03);
    u0.bm[i][0]=s; u0.bm[i][1]=u0.bm[i][2]=u0.bm[i][3]=0;
    y.bm[i][0]=i; y.bm[i][1]=y.bm[i][2]=y.bm[i][3]=0;
    r=invsbox[i];
    v0.bm[i][0]=gfmult(r,0x0e); v0.bm[i][1]=gfmult(r,0x09);
    v0.bm[i][2]=gfmult(r,0x0d); v0.bm[i][3]=gfmult(r,0x0b);
    z0.bm[i][0]=gfmult(i,0x0e); z0.bm[i][1]=gfmult(i,0x09);
    z0.bm[i][2]=gfmult(i,0x0d); z0.bm[i][3]=gfmult(i,0x0b);
    w0.bm[i][0]=r; w0.bm[i][1]=w0.bm[i][2]=w0.bm[i][3]=0;
    for (j=0; j<4; j++)
    { t1.bm[i][j]=t0.bm[i][(j+3)%4];
      t2.bm[i][j]=t0.bm[i][(j+2)%4];
      t3.bm[i][j]=t0.bm[i][(j+1)%4];
      u1.bm[i][j]=u0.bm[i][(j+3)%4]; 
      u2.bm[i][j]=u0.bm[i][(j+2)%4];
      u3.bm[i][j]=u0.bm[i][(j+1)%4];
      v1.bm[i][j]=v0.bm[i][(j+3)%4]; 
      v2.bm[i][j]=v0.bm[i][(j+2)%4];
      v3.bm[i][j]=v0.bm[i][(j+1)%4];
      w1.bm[i][j]=w0.bm[i][(j+3)%4]; 
      w2.bm[i][j]=w0.bm[i][(j+2)%4];
      w3.bm[i][j]=w0.bm[i][(j+1)%4];
      z1.bm[i][j]=z0.bm[i][(j+3)%4]; 
      z2.bm[i][j]=z0.bm[i][(j+2)%4];
      z3.bm[i][j]=z0.bm[i][(j+1)%4];
    }
  }
}

void aessetup(int keylength)
{ 
  if (!aessetupdone) 
  { computetables(); aessetupdone=1;
  }

  switch(keylength)
  { case 128: Nk=4; Nr=10; break;
    case 192: Nk=6; Nr=12; break;
    case 256: Nk=8; Nr=14; break;
    default: printf("\nwrong keylength in aessetup call\n");  
             exit(1);
  }

  Nr4minus1=Nr*4-1;
  ekeywdim=Nb*(Nr+1);
  ekeywdimminus1=ekeywdim-1;
  roundpairs=Nr/2;

}

const byte RC[12]={ 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
                    0x40, 0x80, 0x1b, 0x36, 0x6c };

typedef enum { encrypt, decrypt } PROCESS;

PROCESS encdec;

/* ----------------------------------------------------------
// The function aeskeyschedule utilizes the tables u's and
// the table y, the table z's and partial loop-unrolling to 
// do the same as the function aeskeyschedule_version1 in the 
// Supplement but more efficiently. See FIPS-197 and the function 
// computetables. For elements of the array RC (size provided for 
// max. of 14 rounds), see the book of Daemen and Rijmen, p.214. 
// Before calling aeskeyschedule, key of the user must be
// available in the array ukey.b in the bytes from ukey.b[0] 
// to ukey.b[4*Nk-1].
// It is assumed that aessetup has been called previously
// with the correct keylength.
------------------------------------------------------------- */

void aeskeyschedule(PROCESS kind) 
{ int i,ii;
  word *wp;
  byte *bp;

  if (!aessetupdone)
  { printf(
      "\nerror: aessetup was not called. program aborted\n"); 
    exit(1); 
  }

  encdec=kind;

  for (i=0; i < Nk; i++) ekey.w[i]=ukey.w[i]; 
  ii=0;
  wp=&ekey.w[Nk]; bp=(byte *) &ekey.w[Nk-1];
  if (Nk==4) 
  for (i=0; i < 10; i++)
  { wp[0]=wp[-4]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-3]^wp[0];
    wp[2]=wp[-2]^wp[1];
    wp[3]=wp[-1]^wp[2];
    wp+=4; bp+=16;
  }                 
  else if (Nk==6)  
  for (i=0; i < 8; i++)
  { wp[0]=wp[-6]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-5]^wp[0];
    wp[2]=wp[-4]^wp[1];
    wp[3]=wp[-3]^wp[2];
    wp[4]=wp[-2]^wp[3];
    wp[5]=wp[-1]^wp[4];
    wp+=6; bp+=24;
  }
  else
  for (i=0; i < 7; i++)
  { wp[0]=wp[-8]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-7]^wp[0];
    wp[2]=wp[-6]^wp[1];
    wp[3]=wp[-5]^wp[2];
    bp+=16;
    wp[4]=wp[-4]^
          u0.w[bp[0]]^u1.w[bp[1]]^u2.w[bp[2]]^u3.w[bp[3]];
    wp[5]=wp[-3]^wp[4];
    wp[6]=wp[-2]^wp[5];
    wp[7]=wp[-1]^wp[6];
    wp+=8; bp+=16;
  }

  if (encdec==decrypt)
  {

/* ----------------------------------------------------------
// The first and the last round key are excluded from the
// inverse mixcolumns transform. See the book of Daemen and 
// Rijmen, p.59.
------------------------------------------------------------- */

    bp=(byte *) &ekey.w[4];
    for (ii=4; ii<=Nr4minus1; ii++) 
    { ekey.w[ii]=z0.w[bp[0]]^z1.w[bp[1]]^
                 z2.w[bp[2]]^z3.w[bp[3]];
      bp+=4;
    }
  }

}

/* ----------------------------------------------------------
// Before calling aesprocess, input data must be available 
// in the array aesin.b (bytes aesin.b[0] to aesin.b[15]). 
// Output will be in the array aesout.b (bytes aesout.b[0] 
// to aesout.b[15]). It is assumed (not checked) that 
// aeskeyschedule has been called previously. The function 
// aesprocess employs partial loop-unrolling and two 
// alternating buffers temp0 and temp1 and also the tables u's 
// and w's to do the same as the function aesprocess_version1 
// in the Supplement but more efficiently. The loops operate on 
// pairs of rounds. Note that, for implementation reasons, the 
// matrices involved are the transposes of the corresponding 
// ones in FIPS-197, hence the difference in indexing of their 
// elements. Note also that in AES Nr is always even and that 
// the final round is different, hence the last two rounds 
// are separated from the loop. For decryption, see the book
// of Daemen and Rijmen, p.48-50.
------------------------------------------------------------- */

BLOCK temp0,temp1;

void aesprocess()   
{ int grdp;
  word *wp;

  if (encdec==encrypt)

  { wp=&ekey.w[0];
    temp0.w[0]=(*wp++)^aesin.w[0];
    temp0.w[1]=(*wp++)^aesin.w[1];
    temp0.w[2]=(*wp++)^aesin.w[2];
    temp0.w[3]=(*wp++)^aesin.w[3];

    for (grdp=1; grdp < roundpairs; grdp++)
    { temp1.w[0]=(*wp++)^
                 t0.w[temp0.bm[0][0]]^t1.w[temp0.bm[1][1]]^
                 t2.w[temp0.bm[2][2]]^t3.w[temp0.bm[3][3]];
      temp1.w[1]=(*wp++)^
                 t0.w[temp0.bm[1][0]]^t1.w[temp0.bm[2][1]]^
                 t2.w[temp0.bm[3][2]]^t3.w[temp0.bm[0][3]];
      temp1.w[2]=(*wp++)^
                 t0.w[temp0.bm[2][0]]^t1.w[temp0.bm[3][1]]^
                 t2.w[temp0.bm[0][2]]^t3.w[temp0.bm[1][3]];
      temp1.w[3]=(*wp++)^
                 t0.w[temp0.bm[3][0]]^t1.w[temp0.bm[0][1]]^
                 t2.w[temp0.bm[1][2]]^t3.w[temp0.bm[2][3]];

      temp0.w[0]=(*wp++)^
                 t0.w[temp1.bm[0][0]]^t1.w[temp1.bm[1][1]]^
                 t2.w[temp1.bm[2][2]]^t3.w[temp1.bm[3][3]];
      temp0.w[1]=(*wp++)^
                 t0.w[temp1.bm[1][0]]^t1.w[temp1.bm[2][1]]^
                 t2.w[temp1.bm[3][2]]^t3.w[temp1.bm[0][3]];
      temp0.w[2]=(*wp++)^
                 t0.w[temp1.bm[2][0]]^t1.w[temp1.bm[3][1]]^
                 t2.w[temp1.bm[0][2]]^t3.w[temp1.bm[1][3]];
      temp0.w[3]=(*wp++)^
                 t0.w[temp1.bm[3][0]]^t1.w[temp1.bm[0][1]]^
                 t2.w[temp1.bm[1][2]]^t3.w[temp1.bm[2][3]];
    }

    temp1.w[0]=(*wp++)^
               t0.w[temp0.bm[0][0]]^t1.w[temp0.bm[1][1]]^
               t2.w[temp0.bm[2][2]]^t3.w[temp0.bm[3][3]];
    temp1.w[1]=(*wp++)^
               t0.w[temp0.bm[1][0]]^t1.w[temp0.bm[2][1]]^
               t2.w[temp0.bm[3][2]]^t3.w[temp0.bm[0][3]];
    temp1.w[2]=(*wp++)^
               t0.w[temp0.bm[2][0]]^t1.w[temp0.bm[3][1]]^
               t2.w[temp0.bm[0][2]]^t3.w[temp0.bm[1][3]];
    temp1.w[3]=(*wp++)^
               t0.w[temp0.bm[3][0]]^t1.w[temp0.bm[0][1]]^
               t2.w[temp0.bm[1][2]]^t3.w[temp0.bm[2][3]];

    aesout.w[0]=(*wp++)^
                u0.w[temp1.bm[0][0]]^u1.w[temp1.bm[1][1]]^
                u2.w[temp1.bm[2][2]]^u3.w[temp1.bm[3][3]];
    aesout.w[1]=(*wp++)^
                u0.w[temp1.bm[1][0]]^u1.w[temp1.bm[2][1]]^
                u2.w[temp1.bm[3][2]]^u3.w[temp1.bm[0][3]];
    aesout.w[2]=(*wp++)^
                u0.w[temp1.bm[2][0]]^u1.w[temp1.bm[3][1]]^
                u2.w[temp1.bm[0][2]]^u3.w[temp1.bm[1][3]];
    aesout.w[3]=(*wp++)^
                u0.w[temp1.bm[3][0]]^u1.w[temp1.bm[0][1]]^
                u2.w[temp1.bm[1][2]]^u3.w[temp1.bm[2][3]];
  }

  else

  { wp=&ekey.w[ekeywdimminus1];

    temp0.w[3]=(*wp--)^aesin.w[3];
    temp0.w[2]=(*wp--)^aesin.w[2]; 
    temp0.w[1]=(*wp--)^aesin.w[1];
    temp0.w[0]=(*wp--)^aesin.w[0]; 

    for (grdp=1; grdp < roundpairs; grdp++)
    { temp1.w[3]=(*wp--)^
                 v0.w[temp0.bm[3][0]]^v1.w[temp0.bm[2][1]]^
                 v2.w[temp0.bm[1][2]]^v3.w[temp0.bm[0][3]];
      temp1.w[2]=(*wp--)^
                 v0.w[temp0.bm[2][0]]^v1.w[temp0.bm[1][1]]^
                 v2.w[temp0.bm[0][2]]^v3.w[temp0.bm[3][3]];
      temp1.w[1]=(*wp--)^
                 v0.w[temp0.bm[1][0]]^v1.w[temp0.bm[0][1]]^
                 v2.w[temp0.bm[3][2]]^v3.w[temp0.bm[2][3]];     
      temp1.w[0]=(*wp--)^
                 v0.w[temp0.bm[0][0]]^v1.w[temp0.bm[3][1]]^
                 v2.w[temp0.bm[2][2]]^v3.w[temp0.bm[1][3]];

      temp0.w[3]=(*wp--)^
                 v0.w[temp1.bm[3][0]]^v1.w[temp1.bm[2][1]]^
                 v2.w[temp1.bm[1][2]]^v3.w[temp1.bm[0][3]];
      temp0.w[2]=(*wp--)^
                 v0.w[temp1.bm[2][0]]^v1.w[temp1.bm[1][1]]^
                 v2.w[temp1.bm[0][2]]^v3.w[temp1.bm[3][3]];
      temp0.w[1]=(*wp--)^
                 v0.w[temp1.bm[1][0]]^v1.w[temp1.bm[0][1]]^
                 v2.w[temp1.bm[3][2]]^v3.w[temp1.bm[2][3]];
      temp0.w[0]=(*wp--)^
                 v0.w[temp1.bm[0][0]]^v1.w[temp1.bm[3][1]]^
                 v2.w[temp1.bm[2][2]]^v3.w[temp1.bm[1][3]];
    }
        
    temp1.w[3]=(*wp--)^
               v0.w[temp0.bm[3][0]]^v1.w[temp0.bm[2][1]]^
               v2.w[temp0.bm[1][2]]^v3.w[temp0.bm[0][3]];
    temp1.w[2]=(*wp--)^
               v0.w[temp0.bm[2][0]]^v1.w[temp0.bm[1][1]]^
               v2.w[temp0.bm[0][2]]^v3.w[temp0.bm[3][3]];
    temp1.w[1]=(*wp--)^
               v0.w[temp0.bm[1][0]]^v1.w[temp0.bm[0][1]]^
               v2.w[temp0.bm[3][2]]^v3.w[temp0.bm[2][3]];
    temp1.w[0]=(*wp--)^
               v0.w[temp0.bm[0][0]]^v1.w[temp0.bm[3][1]]^
               v2.w[temp0.bm[2][2]]^v3.w[temp0.bm[1][3]];

    aesout.w[3]=(*wp--)^
                w0.w[temp1.bm[3][0]]^w1.w[temp1.bm[2][1]]^
                w2.w[temp1.bm[1][2]]^w3.w[temp1.bm[0][3]];
    aesout.w[2]=(*wp--)^
                w0.w[temp1.bm[2][0]]^w1.w[temp1.bm[1][1]]^
                w2.w[temp1.bm[0][2]]^w3.w[temp1.bm[3][3]];
    aesout.w[1]=(*wp--)^
                w0.w[temp1.bm[1][0]]^w1.w[temp1.bm[0][1]]^
                w2.w[temp1.bm[3][2]]^w3.w[temp1.bm[2][3]];
    aesout.w[0]=(*wp--)^
                w0.w[temp1.bm[0][0]]^w1.w[temp1.bm[3][1]]^
                w2.w[temp1.bm[2][2]]^w3.w[temp1.bm[1][3]];
  }
}

/* ----------------------------------------------------------
// Timing utility and demo. 
// Note that, for obtaining meaningful results, one needs to 
// have a sufficiently large number of iterations of the task 
// being benchmarked.
------------------------------------------------------------- */

int oldtime;

void mestime1()
{ oldtime=clock();
}

void mestime2(char * st)
{ int t;
  t=clock(); 
  printf("%s    time: %8.2f sec\n",st,
         (double)(t-oldtime)/CLOCKS_PER_SEC);
}

void display(byte b[], int size)
{ int i;
  for (i=0; i < size; i++)
  { printf(" %2.2x",b[i]); if ((i%16)==15) printf("\n"); }
  if ((size%16)!=0) printf("\n"); printf("\n");
}

void aesdemo()
{ int i,keylength,itern1,itern2;

/* ----------------------------------------------------------
// Plaintext of example vectors of FIPS-197 (same in all cases).
------------------------------------------------------------- */

  const byte pt[16]={ 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
                      0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff };

/* ----------------------------------------------------------
// User-key of example vectors of FIPS-197 for keylength 256.
// The first part (16/24 bytes) is used for keylength 128/192.
------------------------------------------------------------- */

  const byte kg[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 };

/* ----------------------------------------------------------
// Setting ukey.b (array is used in all cases of keylength).
------------------------------------------------------------- */

  for (i=0; i<32; i++) ukey.b[i]=kg[i];

labela:
   
  printf("\nFIPS-197 example vector processing:\n");

  printf("enter keylength (128/192/256): (0 for end)\n");
  scanf("%d",&keylength); 
  if (keylength==0) goto labelb;

  aessetup(keylength);
  printf("\nuser-key:\n"); display(ukey.b,Nb*Nk);

  aeskeyschedule(encrypt); 
  
  for (i=0; i<16; i++) aesin.b[i]=pt[i];
  printf("plaintext:\n"); display(aesin.b,16);

  aesprocess();    

  printf("ciphertext:\n"); display(aesout.b,16);
     
  aeskeyschedule(decrypt);

  for (i=0; i<4; i++) aesin.w[i]=aesout.w[i];
  printf("decryption input:\n"); display(aesin.b,16);

  aesprocess();     

  printf("plaintext recovered:\n"); display(aesout.b,16);

  goto labela;

labelb:

  printf("\nbenchmarking:\n");

  printf("enter keylength (128/192/256): (0 for end)\n");
  scanf("%d",&keylength); 
  if (keylength==0) goto termination;

  printf("enter iteration no. of algorithm setup:\n");
  printf("(enter a small number, since much computation)\n");
  scanf("%d",&itern1);
  if (itern1 < 1) goto termination;

  mestime1();
  for (i=0; i < itern1; i++)
  {

/* ----------------------------------------------------------
// Resetting aessetupdone is for benchmarking only, in order to 
// obtain the worst case figure. User should never do the same.
------------------------------------------------------------- */

    aessetupdone=0;

    aessetup(keylength);

  }
  mestime2("algorithm setup       ");

  printf("enter iteration no. of keyscheduling and processing:\n");
  printf("(enter a larger number for better accuracy)\n");
  scanf("%d",&itern2);
  if (itern2 < 1) goto termination;

  mestime1();
  for (i=0; i < itern2; i++) aeskeyschedule(encrypt); 
  mestime2("encryption keyschedule");

  for (i=0; i<16; i++) aesin.b[i]=pt[i];

  mestime1();
  for (i=0; i < itern2; i++) aesprocess(); 
  mestime2("encryption processing ");

  mestime1();
  for (i=0; i < itern2; i++) aeskeyschedule(decrypt);
  mestime2("decryption keyschedule");

  for (i=0; i<4; i++) aesin.w[i]=aesout.w[i];

  mestime1();
  for (i=0; i < itern2; i++) aesprocess();
  mestime2("decryption processing ");

  goto labelb;

termination:

  printf("\naesdemo run ended\n");

}

/* ----------------------------------------------------------
//
// Copyright (C) Mok-Kong Shen 2003.  mok-kong.shen@t-online.de
//
//
// Free license:
//
// This work and all modified versions of it may be freely 
// copied, modified, redistributed and used for all legal 
// civilian purposes without formality albeit at licensee's
// own risk and responsibility, subject to the following 
// conditions:
//
// (1) A copy of this copyright notice with the release history
//     list and the site modification history list must be 
//     included in any copy of this work or any modified version 
//     of it. 
//
// (2) If this work or any modified version of it forms part
//     of a software in object code or binary code, a document
//     for users should accompany the software stating this 
//     fact and include this copyright notice as well as an
//     URL of the licensee where the source code of the package 
//     in the version actually being used in the software can 
//     be found.
//    
// (3) Any modification (except dropping of the Supplement) 
//     should be appropriately documented in the site 
//     modification history list below. The last date of site 
//     modification (at the beginning of the package) is to be 
//     updated.
//
// (4) In case of non-trivial modifications, i.e. those 
//     stemming from efficiency or correctness considerations
//     or from issues of interoperability with other AES 
//     implementations, a copy of the modified package is to be 
//     immediately sent to the copyright owner at the address 
//     above.
//
// (5) Eventual negative or unfavourable consequences and
//     losses or damages of any form to any persons in 
//     connection with the use of this work or its modified 
//     versions do not constitute any liabilities on the part 
//     of the copyright owner.
//
// This free license is unlimited in time [1]. Any attempt of
// non-compliance with the above terms or any occurence of
// their practical unsatisfiability due to whatever reasons, 
// however, automatically terminates the license. Such 
// termination does not affect other licensees who have 
// previously obtained materials from the person with the 
// terminated license but who continue to comply with the 
// above terms.
//
// Other licenses:
//
// Any usages of the contents of the package that don't qualify
// for a free license as stated in the above require explicit
// specific licenses from the copyright owner.
//
//
// [1] Since copyright grants could be revoked after 35 years 
// (see http://www.copyright.gov/title17/92chap2.html#203), it
// could be argued that this license is not timeless for sure. 
// On the other hand, the lifespan of AES itself isn't likely 
// to exceed that period. So the issue is not practically 
// relevant in our context.
//
//
// Release history list:
//
// Release 1.0.
//
//   Posted to sci.crypt on 10th June 2003.
//
// Release 1.1.
//
//   Released on 1st July 2003. 
//
//   A few coding errors of trivial nature removed.
//
//   Syntax changed to conform to both the C and the C++ 
//   standard.
//
//   Function ekeyinvmixcolumnstransform is replaced by a 
//   more efficient version that makes use of the newly 
//   introduced tables z's.
//
//   Function aesprocess is replaced by a more efficient one
//   through partial loop-unrolling and use of two alternating 
//   buffers.
//   
//   Instead of having two separate parts, the package is now
//   a monolithic one, with the functions aespackageinstall
//   and aesdemo performing installation and demonstration
//   respectively.
//
//   Release 1.2
//
//   Released on 10th July 2003.
//
//   Functions userkeyexpansion and aesprocess are replaced by 
//   more efficient versions. The tables u's and w's are
//   introduced for use by the function aesprocess.
//
//   An informative Annex is introduced to help understanding
//   of the program logic.
//
//   Release 1.3
// 
//   Released on 3rd August 2003.
//
//   Functions userkeyexpansion and ekeyinvmixcolumnstransform
//   are merged into the function aeskeyschedule and optimized.
//   A table y is thereby introduced. Functions aesprocess and 
//   aesdemo are unessentially modified.
//
//   A (separate) Supplement is provided containing keyscheduling 
//   and processing functions in the form with input/output 
//   parameters for enabling a fairer benchmark comparison with 
//   other AES implementations that have input/output parameters 
//   in such functions.
//
//   Release 1.4
//
//   Function aespackageinstall is removed, the tables being
//   now generated at application run time when the function 
//   aessetup is called. There is no longer a separate 
//   installation run, nor any permanent disk storage for the 
//   tables.
// 
//   Function aeskeyschedule is optimized. Function aesprocess 
//   is unessentially modified. The Annex is merged into the 
//   Supplement.
//
//
// Site modification history list: 
// (currently empty)
//
//
------------------------------------------------------------- */

/* ----------------------------------------------------------
// 
// End of principal part of AES package release 1.4
// 
------------------------------------------------------------- */





/* ----------------------------------------------------------
//
// Supplement of AES package release 1.4
//
// Author: Mok-Kong Shen, Munich, Germany
// 
// This Supplement is informative only and is intended for 
// rendering easier the understanding or checking of certain 
// functions in the principal part of the package. It also 
// contains the keyscheduling and processing functions in the 
// form with input/output parameters. These are slower than the 
// corresponding ones in the principal part of the package and 
// are provided mainly for enabling a fairer benchmark comparison 
// with other AES implementations that have input/output 
// parameters in such functions. These functions have the suffix 
// 'pp'. A corresponding demo is also provided. To run it, 
// include both the principal part of the package and this 
// Supplement as header files and invoke in a main program the 
// function call aesdemopp().
//
// The copyright notice at the end of principal part of the 
// package applies also to this Supplement.
------------------------------------------------------------- */

void aeskeyschedule_version1(PROCESS kind)
{ UU temp;
  byte t,rr,r,a,b;
  int ii,i,j,ii1,ii2;

const byte matrix[4][4]=
  { { 0x0e, 0x0b, 0x0d, 0x09 }, { 0x09, 0x0e, 0x0b, 0x0d },
    { 0x0d, 0x09, 0x0e, 0x0b }, { 0x0b, 0x0d, 0x09, 0x0e } };

  if (!aessetupdone)
  { printf(
      "\nerror: aessetup was not called. program aborted\n"); 
    exit(1); 
  }

  encdec=kind;

  for (i=0; i < Nk; i++) ekey.w[i]=ukey.w[i];
  for (i=Nk; i < ekeywdim; i++)
  { temp.w=ekey.w[i-1];
    if ((i%Nk)==0)
    { t=temp.b[0]; temp.b[0]=sbox[temp.b[1]]^RC[i/Nk]; 
      temp.b[1]=sbox[temp.b[2]]; temp.b[2]=sbox[temp.b[3]]; 
      temp.b[3]=sbox[t];
    } else if (Nk > 6 && (i%Nk)==4)
    { temp.b[0]=sbox[temp.b[0]]; temp.b[1]=sbox[temp.b[1]];
      temp.b[2]=sbox[temp.b[2]]; temp.b[3]=sbox[temp.b[3]];
    }
    ekey.w[i]=ekey.w[i-Nk]^temp.w;
  }

  if (encdec==decrypt)
  { ii1=4; ii2=Nr*4-1;
    for (ii=ii1; ii<=ii2; ii++)
    { temp.w=ekey.w[ii];  
      for (i=0; i<4; i++)
      { rr=0; 
        for (j=0; j<4; j++)
        { a=matrix[i][j]; b=temp.b[j]; r=0;

/* ----------------------------------------------------------
// The do-while loop performs GF multiplication.
------------------------------------------------------------- */

          do 
          { if (b&0x01) r^=a;
            if (a&0x80) a=(a<<1)^0x1b; else a<<=1;
          } while (b>>=1);
          rr^=r;
        }
        ekey.bm[ii][i]=rr;
      }
    }
  }

}

/* ----------------------------------------------------------
// Note that, for implementation reasons, the matrices
// involved are the transposes of the corresponding ones in 
// FIPS-197, hence the difference in indexing of their elements.
------------------------------------------------------------- */

void aesprocess_version1()
{ BLOCK temp;
  int j,grd,ekeyw0;
  if (encdec==encrypt)
  { ekeyw0=0;
    for (j=0; j<4; j++) aesout.w[j]=aesin.w[j]^ekey.w[ekeyw0++];
    for (grd=1; grd < Nr; grd++)
    { for (j=0; j<4; j++) temp.w[j]=aesout.w[j];
      for (j=0; j<4; j++) aesout.w[j]=t0.w[temp.bm[j][0]]^
        t1.w[temp.bm[(j+1)%4][1]]^t2.w[temp.bm[(j+2)%4][2]]^
        t3.w[temp.bm[(j+3)%4][3]]^ekey.w[ekeyw0++];
    }
    for (j=0; j<4; j++) temp.w[j]=aesout.w[j];
    for (j=0; j<4; j++)
    { aesout.bm[j][0]=
        sbox[temp.bm[j][0]]^ekey.bm[ekeyw0][0];
      aesout.bm[j][1]=
        sbox[temp.bm[(j+1)%4][1]]^ekey.bm[ekeyw0][1];
      aesout.bm[j][2]=
        sbox[temp.bm[(j+2)%4][2]]^ekey.bm[ekeyw0][2];
      aesout.bm[j][3]=
        sbox[temp.bm[(j+3)%4][3]]^ekey.bm[ekeyw0][3];
      ekeyw0++;
    }
  }
  else
  { ekeyw0=ekeywdim-4;
    for (j=0; j<4; j++) aesout.w[j]=aesin.w[j]^ekey.w[ekeyw0++];
    ekeyw0-=8;
    for (grd=1; grd < Nr; grd++)
    { for (j=0; j<4; j++) temp.w[j]=aesout.w[j];
      for (j=0; j<4; j++) aesout.w[j]=v0.w[temp.bm[j][0]]^
        v1.w[temp.bm[(j+3)%4][1]]^v2.w[temp.bm[(j+2)%4][2]]^
        v3.w[temp.bm[(j+1)%4][3]]^ekey.w[ekeyw0++];
      ekeyw0-=8;
    }
    for (j=0; j<4; j++) temp.w[j]=aesout.w[j];
    for (j=0; j<4; j++)
    { aesout.bm[j][0]=
        invsbox[temp.bm[j][0]]^ekey.bm[ekeyw0][0];
      aesout.bm[j][1]=
        invsbox[temp.bm[(j+3)%4][1]]^ekey.bm[ekeyw0][1];
      aesout.bm[j][2]=
        invsbox[temp.bm[(j+2)%4][2]]^ekey.bm[ekeyw0][2];
      aesout.bm[j][3]=
        invsbox[temp.bm[(j+1)%4][3]]^ekey.bm[ekeyw0][3]; 
      ekeyw0++;
    }
  }
}

void aeskeyschedulepp(PROCESS kind, word ukeyw[], word ekeyw[])
{ int i,ii;
  word *wp;
  byte *bp;

  if (!aessetupdone)
  { printf(
      "\nerror: aessetup was not called. program aborted\n"); 
    exit(1); 
  }

  encdec=kind;

  for (i=0; i < Nk; i++) ekeyw[i]=ukeyw[i]; 
  ii=0;
  wp=&ekeyw[Nk]; bp=(byte *) &ekeyw[Nk-1];
  if (Nk==4) 
  for (i=0; i < 10; i++)
  { wp[0]=wp[-4]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-3]^wp[0];
    wp[2]=wp[-2]^wp[1];
    wp[3]=wp[-1]^wp[2];
    wp+=4; bp+=16;
  }                 
  else if (Nk==6)  
  for (i=0; i < 8; i++)
  { wp[0]=wp[-6]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-5]^wp[0];
    wp[2]=wp[-4]^wp[1];
    wp[3]=wp[-3]^wp[2];
    wp[4]=wp[-2]^wp[3];
    wp[5]=wp[-1]^wp[4];
    wp+=6; bp+=24;
  }
  else
  for (i=0; i < 7; i++)
  { wp[0]=wp[-8]^y.w[RC[++ii]]^
          u0.w[bp[1]]^u1.w[bp[2]]^u2.w[bp[3]]^u3.w[bp[0]];
    wp[1]=wp[-7]^wp[0];
    wp[2]=wp[-6]^wp[1];
    wp[3]=wp[-5]^wp[2];
    bp+=16;
    wp[4]=wp[-4]^
          u0.w[bp[0]]^u1.w[bp[1]]^u2.w[bp[2]]^u3.w[bp[3]];
    wp[5]=wp[-3]^wp[4];
    wp[6]=wp[-2]^wp[5];
    wp[7]=wp[-1]^wp[6];
    wp+=8; bp+=16;
  }

  if (encdec==decrypt)
  {

/* ----------------------------------------------------------
// The first and the last round key are excluded from the
// inverse mixcolumns transform. See the book of Daemen and 
// Rijmen, p.59.
------------------------------------------------------------- */

    bp=(byte *) &ekeyw[4];
    for (ii=4; ii<=Nr4minus1; ii++) 
    { ekey.w[ii]=z0.w[bp[0]]^z1.w[bp[1]]^
                 z2.w[bp[2]]^z3.w[bp[3]];
      bp+=4;
    }
  }

}

void aesprocesspp(word aesinw[], word aesoutw[], word ekeyw[])   
{ int grdp;
  word *wp;

  if (encdec==encrypt)

  { wp=&ekeyw[0];
    temp0.w[0]=(*wp++)^aesinw[0];
    temp0.w[1]=(*wp++)^aesinw[1];
    temp0.w[2]=(*wp++)^aesinw[2];
    temp0.w[3]=(*wp++)^aesinw[3];

    for (grdp=1; grdp < roundpairs; grdp++)
    { temp1.w[0]=(*wp++)^
                 t0.w[temp0.bm[0][0]]^t1.w[temp0.bm[1][1]]^
                 t2.w[temp0.bm[2][2]]^t3.w[temp0.bm[3][3]];
      temp1.w[1]=(*wp++)^
                 t0.w[temp0.bm[1][0]]^t1.w[temp0.bm[2][1]]^
                 t2.w[temp0.bm[3][2]]^t3.w[temp0.bm[0][3]];
      temp1.w[2]=(*wp++)^
                 t0.w[temp0.bm[2][0]]^t1.w[temp0.bm[3][1]]^
                 t2.w[temp0.bm[0][2]]^t3.w[temp0.bm[1][3]];
      temp1.w[3]=(*wp++)^
                 t0.w[temp0.bm[3][0]]^t1.w[temp0.bm[0][1]]^
                 t2.w[temp0.bm[1][2]]^t3.w[temp0.bm[2][3]];

      temp0.w[0]=(*wp++)^
                 t0.w[temp1.bm[0][0]]^t1.w[temp1.bm[1][1]]^
                 t2.w[temp1.bm[2][2]]^t3.w[temp1.bm[3][3]];
      temp0.w[1]=(*wp++)^
                 t0.w[temp1.bm[1][0]]^t1.w[temp1.bm[2][1]]^
                 t2.w[temp1.bm[3][2]]^t3.w[temp1.bm[0][3]];
      temp0.w[2]=(*wp++)^
                 t0.w[temp1.bm[2][0]]^t1.w[temp1.bm[3][1]]^
                 t2.w[temp1.bm[0][2]]^t3.w[temp1.bm[1][3]];
      temp0.w[3]=(*wp++)^
                 t0.w[temp1.bm[3][0]]^t1.w[temp1.bm[0][1]]^
                 t2.w[temp1.bm[1][2]]^t3.w[temp1.bm[2][3]];
    }

    temp1.w[0]=(*wp++)^
               t0.w[temp0.bm[0][0]]^t1.w[temp0.bm[1][1]]^
               t2.w[temp0.bm[2][2]]^t3.w[temp0.bm[3][3]];
    temp1.w[1]=(*wp++)^
               t0.w[temp0.bm[1][0]]^t1.w[temp0.bm[2][1]]^
               t2.w[temp0.bm[3][2]]^t3.w[temp0.bm[0][3]];
    temp1.w[2]=(*wp++)^
               t0.w[temp0.bm[2][0]]^t1.w[temp0.bm[3][1]]^
               t2.w[temp0.bm[0][2]]^t3.w[temp0.bm[1][3]];
    temp1.w[3]=(*wp++)^
               t0.w[temp0.bm[3][0]]^t1.w[temp0.bm[0][1]]^
               t2.w[temp0.bm[1][2]]^t3.w[temp0.bm[2][3]];

    aesoutw[0]=(*wp++)^
               u0.w[temp1.bm[0][0]]^u1.w[temp1.bm[1][1]]^
               u2.w[temp1.bm[2][2]]^u3.w[temp1.bm[3][3]];
    aesoutw[1]=(*wp++)^
               u0.w[temp1.bm[1][0]]^u1.w[temp1.bm[2][1]]^
               u2.w[temp1.bm[3][2]]^u3.w[temp1.bm[0][3]];
    aesoutw[2]=(*wp++)^
               u0.w[temp1.bm[2][0]]^u1.w[temp1.bm[3][1]]^
               u2.w[temp1.bm[0][2]]^u3.w[temp1.bm[1][3]];
    aesoutw[3]=(*wp++)^
               u0.w[temp1.bm[3][0]]^u1.w[temp1.bm[0][1]]^
               u2.w[temp1.bm[1][2]]^u3.w[temp1.bm[2][3]];
  }

  else

  { wp=&ekeyw[ekeywdimminus1];

    temp0.w[3]=(*wp--)^aesinw[3];
    temp0.w[2]=(*wp--)^aesinw[2]; 
    temp0.w[1]=(*wp--)^aesinw[1];
    temp0.w[0]=(*wp--)^aesinw[0]; 

    for (grdp=1; grdp < roundpairs; grdp++)
    { temp1.w[3]=(*wp--)^
                 v0.w[temp0.bm[3][0]]^v1.w[temp0.bm[2][1]]^
                 v2.w[temp0.bm[1][2]]^v3.w[temp0.bm[0][3]];
      temp1.w[2]=(*wp--)^
                 v0.w[temp0.bm[2][0]]^v1.w[temp0.bm[1][1]]^
                 v2.w[temp0.bm[0][2]]^v3.w[temp0.bm[3][3]];
      temp1.w[1]=(*wp--)^
                 v0.w[temp0.bm[1][0]]^v1.w[temp0.bm[0][1]]^
                 v2.w[temp0.bm[3][2]]^v3.w[temp0.bm[2][3]];     
      temp1.w[0]=(*wp--)^
                 v0.w[temp0.bm[0][0]]^v1.w[temp0.bm[3][1]]^
                 v2.w[temp0.bm[2][2]]^v3.w[temp0.bm[1][3]];

      temp0.w[3]=(*wp--)^
                 v0.w[temp1.bm[3][0]]^v1.w[temp1.bm[2][1]]^
                 v2.w[temp1.bm[1][2]]^v3.w[temp1.bm[0][3]];
      temp0.w[2]=(*wp--)^
                 v0.w[temp1.bm[2][0]]^v1.w[temp1.bm[1][1]]^
                 v2.w[temp1.bm[0][2]]^v3.w[temp1.bm[3][3]];
      temp0.w[1]=(*wp--)^
                 v0.w[temp1.bm[1][0]]^v1.w[temp1.bm[0][1]]^
                 v2.w[temp1.bm[3][2]]^v3.w[temp1.bm[2][3]];
      temp0.w[0]=(*wp--)^
                 v0.w[temp1.bm[0][0]]^v1.w[temp1.bm[3][1]]^
                 v2.w[temp1.bm[2][2]]^v3.w[temp1.bm[1][3]];
    }
        
    temp1.w[3]=(*wp--)^
               v0.w[temp0.bm[3][0]]^v1.w[temp0.bm[2][1]]^
               v2.w[temp0.bm[1][2]]^v3.w[temp0.bm[0][3]];
    temp1.w[2]=(*wp--)^
               v0.w[temp0.bm[2][0]]^v1.w[temp0.bm[1][1]]^
               v2.w[temp0.bm[0][2]]^v3.w[temp0.bm[3][3]];
    temp1.w[1]=(*wp--)^
               v0.w[temp0.bm[1][0]]^v1.w[temp0.bm[0][1]]^
               v2.w[temp0.bm[3][2]]^v3.w[temp0.bm[2][3]];
    temp1.w[0]=(*wp--)^
               v0.w[temp0.bm[0][0]]^v1.w[temp0.bm[3][1]]^
               v2.w[temp0.bm[2][2]]^v3.w[temp0.bm[1][3]];

    aesoutw[3]=(*wp--)^
               w0.w[temp1.bm[3][0]]^w1.w[temp1.bm[2][1]]^
               w2.w[temp1.bm[1][2]]^w3.w[temp1.bm[0][3]];
    aesoutw[2]=(*wp--)^
               w0.w[temp1.bm[2][0]]^w1.w[temp1.bm[1][1]]^
               w2.w[temp1.bm[0][2]]^w3.w[temp1.bm[3][3]];
    aesoutw[1]=(*wp--)^
               w0.w[temp1.bm[1][0]]^w1.w[temp1.bm[0][1]]^
               w2.w[temp1.bm[3][2]]^w3.w[temp1.bm[2][3]];
    aesoutw[0]=(*wp--)^
               w0.w[temp1.bm[0][0]]^w1.w[temp1.bm[3][1]]^
               w2.w[temp1.bm[2][2]]^w3.w[temp1.bm[1][3]];
  }
}

void aesdemopp()
{ int i,keylength,itern1,itern2;

/* ----------------------------------------------------------
// Plaintext of example vectors of FIPS-197 (same in all cases).
------------------------------------------------------------- */

  const byte pt[16]={ 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
                      0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff };

/* ----------------------------------------------------------
// User-key of example vectors of FIPS-197 for keylength 256.
// The first part (16/24 bytes) is used for keylength 128/192.
------------------------------------------------------------- */

  const byte kg[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 };

/* ----------------------------------------------------------
// Setting ukey.b (array is used in all cases of keylength).
------------------------------------------------------------- */

  for (i=0; i<32; i++) ukey.b[i]=kg[i];

labela:
   
  printf("\nFIPS-197 example vector processing:\n");

  printf("enter keylength (128/192/256): (0 for end)\n");
  scanf("%d",&keylength); 
  if (keylength==0) goto labelb;

  aessetup(keylength);
  printf("\nuser-key:\n"); display(ukey.b,Nb*Nk);

  aeskeyschedulepp(encrypt,ukey.w,ekey.w); 
  
  for (i=0; i<16; i++) aesin.b[i]=pt[i];
  printf("plaintext:\n"); display(aesin.b,16);

  aesprocesspp(aesin.w,aesout.w,ekey.w);    

  printf("ciphertext:\n"); display(aesout.b,16);
     
  aeskeyschedulepp(decrypt,ukey.w,ekey.w);

  for (i=0; i<4; i++) aesin.w[i]=aesout.w[i];
  printf("decryption input:\n"); display(aesin.b,16);

  aesprocesspp(aesin.w,aesout.w,ekey.w);     

  printf("plaintext recovered:\n"); display(aesout.b,16);

  goto labela;

labelb:

  printf("\nbenchmarking:\n");

  printf("enter keylength (128/192/256): (0 for end)\n");
  scanf("%d",&keylength); 
  if (keylength==0) goto termination;

  printf("enter iteration no. of algorithm setup:\n");
  printf("(enter a small number, since much computation)\n");
  scanf("%d",&itern1);
  if (itern1 < 1) goto termination;

  mestime1();
  for (i=0; i < itern1; i++)
  {

/* ----------------------------------------------------------
// Resetting aessetupdone is for benchmarking only, in order to 
// obtain the worst case figure. User should never do the same.
------------------------------------------------------------- */

    aessetupdone=0;

    aessetup(keylength);

  }
  mestime2("algorithm setup       ");

  printf("enter iteration no. of keyscheduling and processing:\n");
  printf("(enter a larger number for better accuracy)\n");
  scanf("%d",&itern2);
  if (itern2 < 1) goto termination;

  mestime1();
  for (i=0; i < itern2; i++) 
    aeskeyschedulepp(encrypt,ukey.w,ekey.w); 
  mestime2("encryption keyschedule");

  for (i=0; i<16; i++) aesin.b[i]=pt[i];

  mestime1();
  for (i=0; i < itern2; i++) 
    aesprocesspp(aesin.w,aesout.w,ekey.w); 
  mestime2("encryption processing ");

  mestime1();
  for (i=0; i < itern2; i++) 
    aeskeyschedulepp(decrypt,ukey.w,ekey.w);
  mestime2("decryption keyschedule");

  for (i=0; i<4; i++) aesin.w[i]=aesout.w[i];

  mestime1();
  for (i=0; i < itern2; i++) 
    aesprocesspp(aesin.w,aesout.w,ekey.w);
  mestime2("decryption processing ");

  goto labelb;

termination:

  printf("\naesdemopp run ended\n");

}


Return to main page