Защита данных в .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