You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

425 lines
16 KiB
C#

9 months ago
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
namespace POSV.Utils
{
public static class Aes
{
static Byte[,] Sbox = {
{ 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 }
};
static Byte[,] InvSbox = {
{ 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 }
};
static uint[] Rcon = { 0x00000000, // Rcon[] is 1-based, so the first entry is just a place holder
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000, 0x6C000000, 0xD8000000,
0xAB000000, 0x4D000000, 0x9A000000, 0x2F000000,
0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
0x97000000, 0x35000000, 0x6A000000, 0xD4000000,
0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000,
0xC5000000, 0x91000000, 0x39000000, 0x72000000,
0xE4000000, 0xD3000000, 0xBD000000, 0x61000000,
0xC2000000, 0x9F000000, 0x25000000, 0x4A000000,
0x94000000, 0x33000000, 0x66000000, 0xCC000000,
0x83000000, 0x1D000000, 0x3A000000, 0x74000000,
0xE8000000, 0xCB000000, 0x8D000000};
public static Byte ffAdd(Byte b1, Byte b2)
{
return (Byte)(b1 ^ b2);
}
public static Byte xtime(Byte b1)
{
Byte b = b1;
// if higher order bit is 1, shift left, then XOR with {1b}
if ((b & 0x80) == 0x80)
{
b = (Byte)(b << 1);
b = (Byte)(b ^ 0x1b);
}
else // just left shift
{
b = (Byte)(b << 1);
}
return b;
}
public static Byte ffMultiply(Byte inb1, Byte inb2)
{
Byte b1, b2;
Byte intermediateB;
Byte answerB = 0;
Byte total = 0;
Byte checker = 1;
if (inb1 < inb2)
{
b2 = inb1;
b1 = inb2;
}
else
{
b1 = inb1;
b2 = inb2;
}
if (b2 == 0)
return 0;
if (b2 == 1)
return b1;
intermediateB = b1;
while (total < b2)
{
if ((checker | b2) == b2)
{
answerB = (Byte)(intermediateB ^ answerB);
total += checker;
}
checker = (Byte)(checker << 1);
intermediateB = xtime(intermediateB);
}
return answerB;
}
public static Byte[][] ExpandKey(Byte[] key, int nK)
{
int nR = nK + 6;
int nB = 4;
int numWords = nB * (nR + 1);
Byte[][] wordArr = new Byte[numWords][];
for (int k = 0; k < numWords; k++)
{
wordArr[k] = new Byte[4];
}
for (int i = 0; i < nK; i++)
{
wordArr[i][0] = key[4 * i];
wordArr[i][1] = key[4 * i + 1];
wordArr[i][2] = key[4 * i + 2];
wordArr[i][3] = key[4 * i + 3];
}
Byte[] tempWord;
for (int i = nK; i < numWords; i++)
{
tempWord = wordArr[i - 1];
if ((i % nK) == 0)
{
tempWord = XORWordAndUint(SubWord(RotWord(tempWord)), Rcon[i / nK]);
}
else if ((nK > 6) && ((i % nK == 4)))
{
tempWord = SubWord(tempWord);
}
wordArr[i] = XORWords(wordArr[i - nK], tempWord);
}
return wordArr;
}
public static Byte[] XORWords(Byte[] word1, Byte[] word2)
{
Byte[] newWord = new Byte[4];
for (int i = 0; i < 4; i++)
{
newWord[i] = (Byte)(word1[i] ^ word2[i]);
}
return newWord;
}
public static Byte[] XORWordAndUint(Byte[] inWord, uint inUint)
{
Byte[] newWord = new Byte[4];
newWord[0] = (Byte)(inWord[0] ^ (inUint >> 24));
newWord[1] = inWord[1];
newWord[2] = inWord[2];
newWord[3] = inWord[3];
return newWord;
}
public static Byte[] SubWord(Byte[] inWord)
{
Byte[] newWord = new Byte[4];
Byte sRow;
Byte sCol;
for (int i = 0; i < 4; i++)
{
sRow = (Byte)(inWord[i] >> 4);
sCol = (Byte)(inWord[i] & 0x0f);
newWord[i] = Sbox[sRow, sCol];
}
return newWord;
}
public static Byte[] RotWord(Byte[] inWord)
{
Byte[] newWord = new Byte[4];
newWord[0] = inWord[1];
newWord[1] = inWord[2];
newWord[2] = inWord[3];
newWord[3] = inWord[0];
return newWord;
}
public static Byte[][,] Cipher(Byte[,] state, Byte[][] keyExpansion, int nR)
{
Byte[][,] allStates = new Byte[nR + 1][,];
Byte[,] newState = new Byte[4, 4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
newState[i, j] = state[i, j];
newState = AddRoundKey(newState, keyExpansion, 0);
allStates[0] = newState;
for (int r = 1; r < nR; r++)
{
newState = SubBytes(newState);
newState = ShiftRows(newState);
newState = MixColumns(newState);
newState = AddRoundKey(newState, keyExpansion, r);
allStates[r] = newState;
}
newState = SubBytes(newState);
newState = ShiftRows(newState);
newState = AddRoundKey(newState, keyExpansion, nR);
allStates[nR] = newState;
return allStates;
}
public static Byte[,] SubBytes(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
Byte sRow;
Byte sCol;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
sRow = (Byte)(state[i, j] >> 4);
sCol = (Byte)(state[i, j] & 0x0f);
newState[i, j] = Sbox[sRow, sCol];
}
}
return newState;
}
public static Byte[,] ShiftRows(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
// first row doesn't change
newState[0, 0] = state[0, 0];
newState[1, 0] = state[1, 0];
newState[2, 0] = state[2, 0];
newState[3, 0] = state[3, 0];
// second row shift left 1
newState[0, 1] = state[1, 1];
newState[1, 1] = state[2, 1];
newState[2, 1] = state[3, 1];
newState[3, 1] = state[0, 1];
// third row shift left 2 (double switch)
newState[0, 2] = state[2, 2];
newState[2, 2] = state[0, 2];
newState[1, 2] = state[3, 2];
newState[3, 2] = state[1, 2];
// fourth row shift left 3 (shift right 1)
newState[3, 3] = state[2, 3];
newState[2, 3] = state[1, 3];
newState[1, 3] = state[0, 3];
newState[0, 3] = state[3, 3];
return newState;
}
public static Byte[,] MixColumns(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
for (int col = 0; col < 4; col++)
{
newState[col, 0] = (Byte)(ffMultiply(0x02, state[col, 0]) ^
ffMultiply(0x03, state[col, 1]) ^
state[col, 2] ^ state[col, 3]);
newState[col, 1] = (Byte)(state[col, 0] ^ ffMultiply(0x02, state[col, 1]) ^
ffMultiply(0x03, state[col, 2]) ^ state[col, 3]);
newState[col, 2] = (Byte)(state[col, 0] ^ state[col, 1] ^
ffMultiply(0x02, state[col, 2]) ^
ffMultiply(0x03, state[col, 3]));
newState[col, 3] = (Byte)(ffMultiply(0x03, state[col, 0]) ^
state[col, 1] ^ state[col, 2] ^
ffMultiply(0x02, state[col, 3]));
}
return newState;
}
public static Byte[,] AddRoundKey(Byte[,] state, Byte[][] keyExpansion, int round)
{
Byte[,] newState = new Byte[4, 4];
// for each column in the state, XOR it with
// the corresponding word in the current round key
for (int col = 0; col < 4; col++)
{
Byte[] tempWord = keyExpansion[round * 4 + col];
for (int row = 0; row < 4; row++)
{
newState[col, row] = (Byte)(state[col, row] ^ tempWord[row]);
}
}
return newState;
}
public static Byte[][,] InvCipher(Byte[,] state, Byte[][] keyExpansion, int nR)
{
Byte[][,] allStates = new Byte[nR + 1][,];
Byte[,] newState = new Byte[4, 4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
newState[i, j] = state[i, j];
newState = AddRoundKey(newState, keyExpansion, nR - 0);
allStates[0] = newState;
for (int r = 1; r < nR; r++)
{
newState = InvShiftRows(newState);
newState = InvSubBytes(newState);
newState = AddRoundKey(newState, keyExpansion, nR - r);
newState = InvMixColumns(newState);
allStates[r] = newState;
}
newState = InvShiftRows(newState);
newState = InvSubBytes(newState);
newState = AddRoundKey(newState, keyExpansion, nR - nR);
allStates[nR] = newState;
return allStates;
}
public static Byte[,] InvShiftRows(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
// first row doesn't change
newState[0, 0] = state[0, 0];
newState[1, 0] = state[1, 0];
newState[2, 0] = state[2, 0];
newState[3, 0] = state[3, 0];
// second row shift right 1
newState[3, 1] = state[2, 1];
newState[2, 1] = state[1, 1];
newState[1, 1] = state[0, 1];
newState[0, 1] = state[3, 1];
// third row shift left 2 (double switch)
newState[0, 2] = state[2, 2];
newState[2, 2] = state[0, 2];
newState[1, 2] = state[3, 2];
newState[3, 2] = state[1, 2];
// fourth row shift right 3 (left 1)
newState[0, 3] = state[1, 3];
newState[1, 3] = state[2, 3];
newState[2, 3] = state[3, 3];
newState[3, 3] = state[0, 3];
return newState;
}
public static Byte[,] InvSubBytes(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
Byte sRow;
Byte sCol;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
sRow = (Byte)(state[i, j] >> 4);
sCol = (Byte)(state[i, j] & 0x0f);
newState[i, j] = InvSbox[sRow, sCol];
}
}
return newState;
}
public static Byte[,] InvMixColumns(Byte[,] state)
{
Byte[,] newState = new Byte[4, 4];
for (int col = 0; col < 4; col++)
{
newState[col, 0] = (Byte)(ffMultiply(0x0e, state[col, 0]) ^
ffMultiply(0x0b, state[col, 1]) ^
ffMultiply(0x0d, state[col, 2]) ^
ffMultiply(0x09, state[col, 3]));
newState[col, 1] = (Byte)(ffMultiply(0x09, state[col, 0]) ^
ffMultiply(0x0e, state[col, 1]) ^
ffMultiply(0x0b, state[col, 2]) ^
ffMultiply(0x0d, state[col, 3]));
newState[col, 2] = (Byte)(ffMultiply(0x0d, state[col, 0]) ^
ffMultiply(0x09, state[col, 1]) ^
ffMultiply(0x0e, state[col, 2]) ^
ffMultiply(0x0b, state[col, 3]));
newState[col, 3] = (Byte)(ffMultiply(0x0b, state[col, 0]) ^
ffMultiply(0x0d, state[col, 1]) ^
ffMultiply(0x09, state[col, 2]) ^
ffMultiply(0x0e, state[col, 3]));
}
return newState;
}
}
}