/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss or reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include <crypto/cipher.h>
#include "crypto.h"

/****************************************************************************/
/*					Local definitions										*/
/****************************************************************************/

/*
*	Rotates the unsigned(!) word w to the right by n bits
*/

#define	R(w,n)	(((w)>>(n))|((w)<<(32-(n))))

/*
*	Adds the round key to the state; {c0..c3} are the four columns
*	and k is the current pointer in the key schedule.
*/

#define	AddRoundKey( c0,c1,c2,c3,k )	\
do {									\
	c0 ^= *k++;							\
	c1 ^= *k++;							\
	c2 ^= *k++;							\
	c3 ^= *k++;							\
} while ( 0 )

/*
*	Rotates the rows of the state
*/

#define	ShiftRows( c0, c1, c2, c3 )		\
do {									\
unsigned int	t0, t1, t2;				\
	t0  = c0 & 0xff000000;				\
	t0 |= c1 & 0x00ff0000;				\
	t0 |= c2 & 0x0000ff00;				\
	t0 |= c3 & 0x000000ff;				\
	t1  = c1 & 0xff000000;				\
	t1 |= c2 & 0x00ff0000;				\
	t1 |= c3 & 0x0000ff00;				\
	t1 |= c0 & 0x000000ff;				\
	t2  = c2 & 0xff000000;				\
	t2 |= c3 & 0x00ff0000;				\
	t2 |= c0 & 0x0000ff00;				\
	t2 |= c1 & 0x000000ff;				\
	c3  = c3 & 0xff000000;				\
	c3 |= c0 & 0x00ff0000;				\
	c3 |= c1 & 0x0000ff00;				\
	c3 |= c2 & 0x000000ff;				\
	c2  = t2;							\
	c1  = t1;							\
	c0  = t0;							\
} while ( 0 )

/*
*	Inverse add the round key to the state; {c0..c3} are the four
*	columns and k is the current pointer in the key schedule.
*/

#define	InvAddRoundKey( c0,c1,c2,c3,k )	\
do {									\
	c3 ^= *--k;							\
	c2 ^= *--k;							\
	c1 ^= *--k;							\
	c0 ^= *--k;							\
} while ( 0 )

/*
*	Inversely rotates the rows of the state
*/

#define	InvShiftRows( c0, c1, c2, c3 )	\
do {									\
unsigned int	t0, t1, t2;				\
	t0  = c0 & 0xff000000;				\
	t0 |= c3 & 0x00ff0000;				\
	t0 |= c2 & 0x0000ff00;				\
	t0 |= c1 & 0x000000ff;				\
	t1  = c1 & 0xff000000;				\
	t1 |= c0 & 0x00ff0000;				\
	t1 |= c3 & 0x0000ff00;				\
	t1 |= c2 & 0x000000ff;				\
	t2  = c2 & 0xff000000;				\
	t2 |= c1 & 0x00ff0000;				\
	t2 |= c0 & 0x0000ff00;				\
	t2 |= c3 & 0x000000ff;				\
	c3  = c3 & 0xff000000;				\
	c3 |= c2 & 0x00ff0000;				\
	c3 |= c1 & 0x0000ff00;				\
	c3 |= c0 & 0x000000ff;				\
	c2  = t2;							\
	c1  = t1;							\
	c0  = t0;							\
} while ( 0 )

/****************************************************************************/
/*					Local prototypes										*/
/****************************************************************************/

static void		AesEncrypt( const int *ksc, const void *clear, void *cipher );
static void		AesDecrypt( const int *ksc, const void *cipher, void *clear );

/****************************************************************************/
/*					Public data												*/
/****************************************************************************/

const struct bc_cipher _bc_cipher_aes = { AesEncrypt, AesDecrypt, 16 };

/****************************************************************************/
/*					Local data												*/
/****************************************************************************/

/*
*	The combined forward S-box and column transformation result
*	Each word in the table contains the following:
*	table[ x ] = X1X1X3X2 where
*	Xn = Sbox[ x ] * n where the '*' means the polynomial multiplication
*	over the 2^8 Galois field. See the standard for details.
*/

static const unsigned int sbox_mixcol[ 256 ] = {

	0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6,
	0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
	0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56,
	0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
	0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa,
	0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
	0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45,
	0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
	0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c,
	0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
	0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9,
	0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
	0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d,
	0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
	0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf,
	0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
	0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34,
	0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
	0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d,
	0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
	0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1,
	0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
	0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72,
	0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
	0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed,
	0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
	0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe,
	0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
	0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05,
	0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
	0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342,
	0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
	0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3,
	0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
	0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a,
	0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
	0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3,
	0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
	0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28,
	0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
	0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14,
	0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
	0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4,
	0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
	0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da,
	0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
	0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf,
	0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
	0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c,
	0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
	0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e,
	0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
	0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc,
	0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
	0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069,
	0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
	0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322,
	0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
	0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9,
	0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
	0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a,
	0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
	0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e,
	0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c
};

/*
*	The inverse column transformation. This table is not combined
*	with the S-box transformation, because they do not commute.
*	Each element is 0xX9XdXbXe where Xn (n is hex) is X * n,
*	where X is the table index and * is the polynomial multiplication
*	in the GF(2^8) field. See the standard for details.
*/

static const unsigned int inv_mixcol[ 256 ] = {

	0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12,
	0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a,
	0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562,
	0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a,
	0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2,
	0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca,
	0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582,
	0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba,
	0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9,
	0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1,
	0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9,
	0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281,
	0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629,
	0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11,
	0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59,
	0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261,
	0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf,
	0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787,
	0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf,
	0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7,
	0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f,
	0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767,
	0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f,
	0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17,
	0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064,
	0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c,
	0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814,
	0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c,
	0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084,
	0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc,
	0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4,
	0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc,
	0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53,
	0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b,
	0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223,
	0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b,
	0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3,
	0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b,
	0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3,
	0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb,
	0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188,
	0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0,
	0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8,
	0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0,
	0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168,
	0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50,
	0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918,
	0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520,
	0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe,
	0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6,
	0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e,
	0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6,
	0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e,
	0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026,
	0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e,
	0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856,
	0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725,
	0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d,
	0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55,
	0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d,
	0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5,
	0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd,
	0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5,
	0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d
};

/*
*	Key schedule correction tags, they are powers of 2 in the GF(2^8).
*/

static const unsigned char rcon[ 10 ] = {

	0x01, 0x02, 0x04, 0x08, 0x10,
	0x20, 0x40, 0x80, 0x1b, 0x36
};

/*
*	The forward S-box
*/

static const unsigned char sbox_enc[ 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
};

/*
*	The inverse S-box
*/

static const unsigned char sbox_dec[ 256 ] = {

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

/****************************************************************************/
/*						Inline functions									*/
/****************************************************************************/

/*
*	Multiplies a 4-element byte vector with a transformation matrix.
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	The elementary multiplication results with the matrix elements are
*	stored as a 256 word precalculated table. In the encryption direction
*	the table also does the Sbox() transformation, thus a single run
*	of this function does both the MixColumns() and the Sbox() operations.
*	The 'x' argument is a column from the state and 't' is a pointer
*	to the multiplication table.
*/

static inline unsigned int MatrixMul( unsigned int x, const unsigned int *t )
{
unsigned int r;

	// First, we rotate x to the left by 2 bit positions. This
	// can be achieved by rotating it to the right by 30 bits.

	x = R( x, 30 );

	// Now we want to fetch the table element that is indexed by the
	// low 8 bits of x before we rotated it. That would mean masking
	// x by 0xff and then shift the result 2 bits to the left to get
	// a byte offset. Now that we have x rotated, if we mask it with
	// 0x3fc we get the byte offset immediately.

	r = *((unsigned int *) ((char *) t + ( x & 0x3fc ) ) );

	// Now we want to fetch the table element indexed by the next byte
	// of the original x. That means that if we rotate x to the right
	// by 8 bits and use the same trick as before, we get what we want.
	// Note that we can not shift, because we store the former top two
	// bits temporarily in our bottom 2 bits and they have to be kept.

	x = R( x, 8 );

	// Now we fetch the element and rotate it right by 24 bits, then XOR
	// it with the partial result. This operation calculates the partial
	// sum of the result vector as we multiply with the next row of the
	// matrix.

	r ^= R( *((unsigned int *) ((char *) t + ( x & 0x3fc ) ) ), 24 );

	// Now we repeat the above, except that we rotate the fetched element
	// by 16 and 8 bits, respectively; luckily the matrix is such that a
	// simple rotation is all we need in each step.

	x  = R( x, 8 );
	r ^= R( *((unsigned int *) ((char *) t + ( x & 0x3fc ) ) ), 16 );
	x  = R( x, 8 );
	r ^= R( *((unsigned int *) ((char *) t + ( x & 0x3fc ) ) ),  8 );

	// We are done. On the ARM right rotations are essentially free
	// because they can be combined into other operations. Fortunately gcc
	// is smart enough to recognise them and combine them, so this whole
	// business of matrix multiplication can be done real fast.

	return( r );
}

/*
*	Substitutes the bytes of a word
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	Each individual byte in the 32-bit word c will be substituted by the
*	value found in the byte array s indexed by the byte.
*/

static inline unsigned int SubBytes( unsigned int c, const unsigned char *s )
{
unsigned int t;

	t  = 0;
	t |= s[ ( c >>  0 ) & 255 ] <<  0;
	t |= s[ ( c >>  8 ) & 255 ] <<  8;
	t |= s[ ( c >> 16 ) & 255 ] << 16;
	t |= s[ ( c >> 24 ) & 255 ] << 24;

	return( t );
}

/****************************************************************************/
/*						User API											*/
/****************************************************************************/

/** @addtogroup cipher */
/** @{ */

/**
*	Prepares an AES encryption or decryption.
*
*	This function generates the key schedule to be used when encrypting or
*	decrypting data using the given key. After this call the key itself
*	can be destroyed and only the key schedule must be kept. The function
*	supports 128, 196 and 256 bit key lengths.
*
*	@param	ksc		Pointer to an array of 32-bit ints where the calculated
*					key schedule will be stored. The required storage is
*					45, 53 or 61 words for the 128, 192 and 256 bit keys,
*					respectively. The key schedule must not be changed but
*					must be passed to the encrypt and decrypt routines verbatim.
*
*	@param	key		Pointer to the key. It must be 16, 24 or 32 bytes, that is
*					128, 196 or 256 bits long.
*
*	@param	len		The key length in bits, one of 128, 196 or 256. If the
*					argument is not one of these numbers, then the function
*					does nothing.
*/

void	BC_AesKeySched( int *ksc, const void *key, int len )
{
unsigned int	t, c, r;
signed int		i, j, k;
unsigned char	*kptr;

	kptr = (unsigned char *) key;

	// Alas, gcc is not smart enough to see that it is not possible
	// for 't' being used uninitialised. So we initialise it.

	t = 0;

	// Work out the number of initial words

	switch ( len ) {

		case 128:

			k = 4;
			r = 10;
			break;

		case 192:

			k = 6;
			r = 12;
			break;

		case 256:

			k = 8;
			r = 14;
			break;

		default:

			return;
	}

	// Store the key schedule length in the first word of the buffer

	*ksc++ = r;

	// This is a line-by-line implementation of the standard's
	// pseudocode, with only the absolutely obvious elimination
	// of divisions and changing array indexing to pointers.

	for ( i = 0 ; i < k ; i++ ) {

		t  = *kptr++ << 24;
		t |= *kptr++ << 16;
		t |= *kptr++ <<  8;
		t |= *kptr++ <<  0;
		*ksc++ = t;
	}

	for ( j = k, i = 4 * ( r + 1 ) - k, c = 0 ; i-- ; j++ ) {

		if ( j == k ) {

			t = SubBytes( R( t,24 ), sbox_enc ) ^ ( rcon[ c++ ] << 24 );
			j = 0;
		}
		else if ( k == 8 && j == 4 ) {

			t = SubBytes( t, sbox_enc );
		}

		t ^= ksc[ -k ];
		*ksc++ = t;
	}
}

/****************************************************************************/
/*						Local functions										*/
/****************************************************************************/

/*
*	AES encrypts a 16-byte block.
*
*	ksc		The key schedule, obtained by a call to BC_AesKeySched().
*
*	clear	Pointer to the 16 bytes of cleartext
*
*	cipher	Pointer to a 16-byte buffer where the ciphertext will
*			be stored. It may overlap with the cleartext.
*/

static void		AesEncrypt( const int *ksc, const void *clear, void *cipher )
{
unsigned int	c0, c1, c2, c3;
unsigned int	rnd, len;
unsigned char	*ucp;

	// Work out the number of rounds

	len = *ksc++;
	ucp = (unsigned char *) clear;

	// Load the data, it is in big-endian format

	c0 = ( ucp[  0 ] << 24 ) | ( ucp[  1 ] << 16 ) |
		 ( ucp[  2 ] <<  8 ) | ( ucp[  3 ] <<  0 );
	c1 = ( ucp[  4 ] << 24 ) | ( ucp[  5 ] << 16 ) |
		 ( ucp[  6 ] <<  8 ) | ( ucp[  7 ] <<  0 );
	c2 = ( ucp[  8 ] << 24 ) | ( ucp[  9 ] << 16 ) |
		 ( ucp[ 10 ] <<  8 ) | ( ucp[ 11 ] <<  0 );
	c3 = ( ucp[ 12 ] << 24 ) | ( ucp[ 13 ] << 16 ) |
		 ( ucp[ 14 ] <<  8 ) | ( ucp[ 15 ] <<  0 );

	// First, we do a key addition

	AddRoundKey( c0, c1, c2, c3, ksc );

	// Now we do the relevant number of rounds (one less than the
	// actual number of rounds, as the last round is special).

	for ( rnd = 1 ; rnd < len ; rnd++ ) {

		// The standard defines the first two steps to be SubBytes() then
		// ShiftRows(). They commute, so we do the ShiftRows() first.

		ShiftRows( c0, c1, c2, c3 );

		// Now we have to do a SubBytes() and a MixColumns(). The
		// MixColumns() is four matrix - vector multiplications using
		// a constant matrix. We do it using a table lookup and the table
		// is constructed so that it also contains the SubBytes() operation.
		// Thus, here we can omit the SubBytes() step and do only the four
		// matrix multiplies.

		c0 = MatrixMul( c0, sbox_mixcol );
		c1 = MatrixMul( c1, sbox_mixcol );
		c2 = MatrixMul( c2, sbox_mixcol );
		c3 = MatrixMul( c3, sbox_mixcol );

		// We have to add the round key

		AddRoundKey( c0, c1, c2, c3, ksc );
	}

	// The finishing step is a SubBytes(), ShiftRows() and AddRoundKey()

	c0 = SubBytes( c0, sbox_enc );
	c1 = SubBytes( c1, sbox_enc );
	c2 = SubBytes( c2, sbox_enc );
	c3 = SubBytes( c3, sbox_enc );
	ShiftRows( c0, c1, c2, c3 );
	AddRoundKey( c0, c1, c2, c3, ksc );

	// Store the result the same way as we fetched it

	((char *) cipher)[  0 ] = (char) ( c0 >> 24 );
	((char *) cipher)[  1 ] = (char) ( c0 >> 16 );
	((char *) cipher)[  2 ] = (char) ( c0 >>  8 );
	((char *) cipher)[  3 ] = (char) ( c0 >>  0 );
	((char *) cipher)[  4 ] = (char) ( c1 >> 24 );
	((char *) cipher)[  5 ] = (char) ( c1 >> 16 );
	((char *) cipher)[  6 ] = (char) ( c1 >>  8 );
	((char *) cipher)[  7 ] = (char) ( c1 >>  0 );
	((char *) cipher)[  8 ] = (char) ( c2 >> 24 );
	((char *) cipher)[  9 ] = (char) ( c2 >> 16 );
	((char *) cipher)[ 10 ] = (char) ( c2 >>  8 );
	((char *) cipher)[ 11 ] = (char) ( c2 >>  0 );
	((char *) cipher)[ 12 ] = (char) ( c3 >> 24 );
	((char *) cipher)[ 13 ] = (char) ( c3 >> 16 );
	((char *) cipher)[ 14 ] = (char) ( c3 >>  8 );
	((char *) cipher)[ 15 ] = (char) ( c3 >>  0 );
}

/*
*	AES decrypts a 16-byte block.
*
*	ksc		The key schedule, obtained by a call to BC_AesKeySched().
*
*	clear	Pointer to the 16 bytes of ciphertext
*
*	cipher	Pointer to a 16-byte buffer where the cleartext will
*			be stored. It may overlap with the ciphertext.
*/

static void		AesDecrypt( const int *ksc, const void *cipher, void *clear )
{
unsigned int	c0, c1, c2, c3;
unsigned int	rnd, len;
unsigned char	*ucp;

	// Work out the number of rounds

	len = *ksc++;
	ucp = (unsigned char *) cipher;

	// Load the data, it is in big-endian format

	c0 = ( ucp[  0 ] << 24 ) | ( ucp[  1 ] << 16 ) |
		 ( ucp[  2 ] <<  8 ) | ( ucp[  3 ] <<  0 );
	c1 = ( ucp[  4 ] << 24 ) | ( ucp[  5 ] << 16 ) |
		 ( ucp[  6 ] <<  8 ) | ( ucp[  7 ] <<  0 );
	c2 = ( ucp[  8 ] << 24 ) | ( ucp[  9 ] << 16 ) |
		 ( ucp[ 10 ] <<  8 ) | ( ucp[ 11 ] <<  0 );
	c3 = ( ucp[ 12 ] << 24 ) | ( ucp[ 13 ] << 16 ) |
		 ( ucp[ 14 ] <<  8 ) | ( ucp[ 15 ] <<  0 );

	// We will use the key schedule in reverse order

	ksc += len * 4 + 4;
	InvAddRoundKey( c0, c1, c2, c3, ksc );

	for ( rnd = 1 ; rnd <= len ; rnd++ ) {

		// Unfortunately, because SubBytes() and MixColumns() do
		// not commute, we can't do any shortcuts, we have to spell
		// everything out.

		InvShiftRows( c0, c1, c2, c3 );
		c0 = SubBytes( c0, sbox_dec );
		c1 = SubBytes( c1, sbox_dec );
		c2 = SubBytes( c2, sbox_dec );
		c3 = SubBytes( c3, sbox_dec );
		InvAddRoundKey( c0, c1, c2, c3, ksc );
		if ( rnd == len ) break;
		c0 = MatrixMul( c0, inv_mixcol );
		c1 = MatrixMul( c1, inv_mixcol );
		c2 = MatrixMul( c2, inv_mixcol );
		c3 = MatrixMul( c3, inv_mixcol );
	}

	// Store the result the same way as we fetched it

	((char *) clear)[  0 ] = (char) ( c0 >> 24 );
	((char *) clear)[  1 ] = (char) ( c0 >> 16 );
	((char *) clear)[  2 ] = (char) ( c0 >>  8 );
	((char *) clear)[  3 ] = (char) ( c0 >>  0 );
	((char *) clear)[  4 ] = (char) ( c1 >> 24 );
	((char *) clear)[  5 ] = (char) ( c1 >> 16 );
	((char *) clear)[  6 ] = (char) ( c1 >>  8 );
	((char *) clear)[  7 ] = (char) ( c1 >>  0 );
	((char *) clear)[  8 ] = (char) ( c2 >> 24 );
	((char *) clear)[  9 ] = (char) ( c2 >> 16 );
	((char *) clear)[ 10 ] = (char) ( c2 >>  8 );
	((char *) clear)[ 11 ] = (char) ( c2 >>  0 );
	((char *) clear)[ 12 ] = (char) ( c3 >> 24 );
	((char *) clear)[ 13 ] = (char) ( c3 >> 16 );
	((char *) clear)[ 14 ] = (char) ( c3 >>  8 );
	((char *) clear)[ 15 ] = (char) ( c3 >>  0 );
}

/** @} */

