Защита данных в .NET - Улучшенный стандарт шифрования
ОГЛАВЛЕНИЕ
4. Улучшенный стандарт шифрования
AES (именуемый Рийндайл) тоже является блочным шифром, но не использует структуру Фейстеля. Размер блока AES равен 128 бит, но размер ключа различается - 128, 192 или 256 битов.
Блок-схема шифрования/расшифровки AES
4.a Шифрование
Как показывает рисунок, операция шифрования состоит из четырех отдельных функций: замена байтов, перестановка, арифметические операции на конечном поле и XOR с ключом.
protected byte[] Encrypt128Bit(byte[] block)
{
AddRoundKey(block, 0);
//Nr=10,12 или 14 в зависимости от размера ключа
for (int i = 1; i < Nr; i++)
{
SubBytes(block);
ShiftRows(block);
MixColumns(block);
AddRoundKey(block, i);
}
SubBytes(block);
ShiftRows(block);
AddRoundKey(block, Nr);
return block;
}
4.a.1 SubBytes()
Этот метод заменяет каждый байт блока в порядке Sbox. Он обеспечивает обратимое преобразование блоков во время шифрования, с обратной операцией во время расшифровки. Реализация метода очень простая, как показано:
private void SubBytes(byte[] block)
{
for (int i = 0; i < 16; i++)
{
block[i] = Sbox[i];
}
}
4.a.2 ShiftRows()
Операция ShiftRows выполняет круговые сдвиги влево рядов 1, 2 и 3 на 1, 2 и 3, как показано:
void ShiftRows(byte[] state)
{
byte[] t = new byte[4];
for (int r = 1; r < 4; r++)
{
for (int c = 0; c < 4; c++)
t[c] = state[r * 4 + ((c + r) % 4)];
for (int c = 0; c < 4; c++)
state[r * 4 + c] = t[c];
}
}
4.a.3 MixColumns()
Этот метод умножает каждый столбец входного блока на матрицу. Операция умножения аналогична умножению матриц, за исключением того что она использует конечное поле для перемножения двух элементов и выполняет операцию XOR вместо сложения.
Ниже приведен результат умножения столбца выше (точки обозначают умножение на конечном поле, плюсы в кругах обозначают операцию “Исключающее или“):
private void MixColumns(byte[] block)
{
//temp=block
byte[,] t = new byte[4, 4];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
t[i, j] = block[i * 4 + j];
}
}
for (int i = 0; i < 4; i++)
{
block[00 + i] = (byte)(M(2, t[0, i]) ^ M(3, t[1, i]) ^ t[2, i] ^ t[3, i]);
block[04 + i] = (byte)(t[0, i] ^M(2, t[1, i])^ M(3, t[2, i]) ^ t[3, i] );
block[08 + i] = (byte)(t[0, i] ^ t[1, i] ^ M(2, t[2, i]) ^ M(3, t[3, i]));
block[12 + i] = (byte)(M(3, t[0, i]) ^ t[1, i] ^ t[2, i] ^ M(2, t[3, i]));
}
}
4.a.4 AddRoundKey()
Эта операция применяет операцию “Исключающее или“ к каждому байту входного блока и текущей матрице весов (ключу).
private void AddRoundKey(byte[] block, int round)
{
for (int i = 0; i < 16; i++)
{
block[i] = (byte)(block[i] ^ Keys[(round * 4 + i )]);
}
}
4.b Расшифровка
Следующее инвертирует шаги алгоритма шифрования с некоторыми изменениями в методах, давая алгоритм расшифровки:
protected byte[] Decrypt128Bit(byte[] block)
{
AddRoundKey(block, Nr);
//Nr=10,12 или 14 в зависимости от размера ключа
for (int i = Nr - 1; i > 0; i--)
{
InvShiftRows(block);
InvSubBytes(block);
AddRoundKey(block, i);
InvMixColumns(block);
}
InvShiftRows(block);
InvSubBytes(block);
AddRoundKey(block, 0);
return block;
}
У метода есть следующие отличия от операции шифрования:
• Операция InvShiftRows выполняет круговые сдвиги вправо (влево в ShiftRows) рядов 1, 2 и 3 на 1, 2 и 3.
• InvSubBytes отличается от SubBytes, так как использует InvSbox вместо Sbox.
• InvMixColumns умножает каждый столбец на другую матрицу (есть в исходниках).
4.c Генерация ключей
Этот метод иначе называется расширением ключа. Он принимает матрицу в [4,Nk] (Nk = 4, 6 или 8) размерностях и расширяет ее до [4,4*(Nr+1)] (Nr = 10, 12 или 14) размерностей. Ниже приведен алгоритм этого метода, описанный в федеральном стандарте обработки информации-197:
KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk)
begin
word temp
i = 0
while (i < Nk)
w[i] = word(key[4*i], key[4*i+1], key[4*i+2], key[4*i+3])
i = i+1
end while
i = Nk
while (i < Nb * (Nr+1)]
temp = w[i-1]
if (i mod Nk = 0)
temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
else if (Nk > 6 and i mod Nk = 4)
temp = SubWord(temp)
end if
w[i] = w[i-Nk] xor temp
i = i + 1
end while
end