public uint[] Crypt(uint[] input, int dir)
{
if (input.Length != 4)
{
throw new Exception("invalid aes block size");
}
var key = this._key[dir];
// state variables a,b,c,d are loaded with pre-whitened data
uint a = input[0] ^ key[0];
uint b = input[(dir != 0) ? 3 : 1] ^ key[1];
uint c = input[2] ^ key[2];
uint d = input[(dir != 0) ? 1 : 3] ^ key[3];
uint a2, b2, c2;
int nInnerRounds = key.Length / 4 - 2;
uint kIndex = 4;
uint[] outBuffer = new uint[] { 0, 0, 0, 0 };
var table = _tables[dir];
// load up the tables
var t0 = table[0];
var t1 = table[1];
var t2 = table[2];
var t3 = table[3];
uint[] sbox = table[4];
// Inner rounds. Cribbed from OpenSSL.
for (int i = 0; i < nInnerRounds; i++)
{
a2 = t0[a >> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex];
b2 = t0[b >> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
c2 = t0[c >> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
d = t0[d >> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
kIndex += 4;
a = a2; b = b2; c = c2;
}
// Last round.
for (int i = 0; i < 4; i++)
{
outBuffer[(dir != 0) ? 3 & -i : i] =
sbox[a >> 24] << 24 ^
sbox[b >> 16 & 255] << 16 ^
sbox[c >> 8 & 255] << 8 ^
sbox[d & 255] ^
key[kIndex++];
a2 = a; a = b; b = c; c = d; d = a2;
}
return outBuffer;
}