private long[][] GenerateWorkingKey(
byte[] key)
{
int KC;
int t, rconpointer = 0;
int keyBits = key.Length * 8;
byte[,] tk = new byte[4,MAXKC];
//long[,] W = new long[MAXROUNDS+1,4];
long[][] W = new long[MAXROUNDS+1][];
for (int i = 0; i < MAXROUNDS+1; i++) W[i] = new long[4];
switch (keyBits)
{
case 128:
KC = 4;
break;
case 160:
KC = 5;
break;
case 192:
KC = 6;
break;
case 224:
KC = 7;
break;
case 256:
KC = 8;
break;
default :
throw new ArgumentException("Key length not 128/160/192/224/256 bits.");
}
if (keyBits >= blockBits)
{
ROUNDS = KC + 6;
}
else
{
ROUNDS = (BC / 8) + 6;
}
//
// copy the key into the processing area
//
int index = 0;
for (int i = 0; i < key.Length; i++)
{
tk[i % 4,i / 4] = key[index++];
}
t = 0;
//
// copy values into round key array
//
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
{
for (int i = 0; i < 4; i++)
{
W[t / (BC / 8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % BC);
}
}
//
// while not enough round key material calculated
// calculate new values
//
while (t < (ROUNDS+1)*(BC/8))
{
for (int i = 0; i < 4; i++)
{
tk[i,0] ^= S[tk[(i+1)%4,KC-1] & 0xff];
}
tk[0,0] ^= (byte) rcon[rconpointer++];
if (KC <= 6)
{
for (int j = 1; j < KC; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
}
else
{
for (int j = 1; j < 4; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
for (int i = 0; i < 4; i++)
{
tk[i,4] ^= S[tk[i,3] & 0xff];
}
for (int j = 5; j < KC; j++)
{
for (int i = 0; i < 4; i++)
{
tk[i,j] ^= tk[i,j-1];
}
}
}
//
// copy values into round key array
//
for (int j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
{
for (int i = 0; i < 4; i++)
{
W[t / (BC/8)][i] |= (long)(tk[i,j] & 0xff) << ((t * 8) % (BC));
}
}
}
return W;
}