Подтвердить что ты не робот

Могу ли я использовать AES в режиме CTR в .NET?

.NET AES не реализует CTR напрямую. Он реализует только CBC, CFB, CTS, ECB и OFB.

Могу ли я использовать любой из этих режимов и безопасно применять CTR вокруг них, или мне нужно вообще использовать другую библиотеку?

4b9b3361

Ответ 1

Да, вы можете построить CTR с использованием .NET AES в режиме ECB и счетчика, который вы сами инициализируете и увеличиваете, для каждого блока, зашифрованного.

Примером этого является поток шифрования WinZipAes, который является частью DotNetZip с открытым исходным кодом.
WinZip определяет использование AES-шифрования для зашифрованных ZIP файлов, используя AES в режиме CTR. DotNetZip реализует режим CTR с использованием ECB и счетчика.

См. здесь для некоторых комментариев.

Ответ 2

Все, что вам нужно сделать, это использовать AES в режиме ECB с ключом (без прокладки, нет IV) для шифрования 128-битного счетчика. Простой текст затем XORed с зашифрованным выходом счетчика. Для каждого блока счетчик увеличивается. Шифрование и дешифрование одинаковы из-за свойств оператора XOR.

Здесь вы можете найти реализацию (мой собственный) для режима CTR AES128:

https://gist.github.com/hanswolff/8809275

Он должен быть прост в использовании.

Ответ 3

Компактная автономная реализация, основанная на коде @quadfinity.

(Несмотря на название класса в исходном коде). Он может работать с ключами любого размера: 128, 192 и 256. Просто предоставьте key правильного размера. salt должен иметь 128 бит (16 байтов).

Этот метод работает как для шифрования, так и для дешифрования.

public static void AesCtrTransform(
    byte[] key, byte[] salt, Stream inputStream, Stream outputStream)
{
    SymmetricAlgorithm aes =
        new AesManaged { Mode = CipherMode.ECB, Padding = PaddingMode.None };

    int blockSize = aes.BlockSize / 8;

    if (salt.Length != blockSize)
    {
        throw new ArgumentException(
            string.Format(
                "Salt size must be same as block size (actual: {0}, expected: {1})",
                salt.Length, blockSize));
    }

    byte[] counter = (byte[])salt.Clone();

    Queue<byte> xorMask = new Queue<byte>();

    var zeroIv = new byte[blockSize];
    ICryptoTransform counterEncryptor = aes.CreateEncryptor(key, zeroIv);

    int b;
    while ((b = inputStream.ReadByte()) != -1)
    {
        if (xorMask.Count == 0)
        {
            var counterModeBlock = new byte[blockSize];

            counterEncryptor.TransformBlock(
                counter, 0, counter.Length, counterModeBlock, 0);

            for (var i2 = counter.Length - 1; i2 >= 0; i2--)
            {
                if (++counter[i2] != 0)
                {
                    break;
                }
            }

            foreach (var b2 in counterModeBlock)
            {
                xorMask.Enqueue(b2);
            }
        }

        var mask = xorMask.Dequeue();
        outputStream.WriteByte((byte)(((byte)b) ^ mask));
    }
}

См. также версию кода PowerShell.

Ответ 4

Функция симметричного шифрования Bouncy Castle, похоже, поддерживает CTR:

  • Алгоритмы симметричного ключа: AES, Blowfish, Camellia, CAST5, CAST6, DESede, DES, GOST28147, HC-128, HC-256, IDEA, NaccacheStern, RC2, RC4, RC5-32, RC5-64, RC6, Rijndael, "Змей", "Skipjack", "TEA/XTEA", "Twofish" и "VMPC".
  • Симметричные ключевые режимы: CBC, CFB, CTS, GOFB, OFB, OpenPGPCFB и SIC (также CTR).

http://www.bouncycastle.org/csharp/

Ответ 5

Зашифруйте и расшифруйте, используя алгоритм AES/CTR/NoPadding с 16-байтовым вектором инициализации (IV), состоящим из всех нулей, и одноразовым 256-битным ключом дешифрования AES, используя криптографически безопасный генератор.

Используя метод AesCtrTransform из кода @martin, у меня есть пример использования ниже. Обратите внимание, что я оставляю здесь байтовый массив вектора инициализации (IV) пустым, но вы должны заполнить его, если хотите повысить безопасность (Подробнее: безопасно ли повторно использовать IV), но тогда вы где-то должны хранить IV и ключ.

const string text = "Hello world";
var key = new byte[32];
var initializationVector = new byte[16];

using (var random = new RNGCryptoServiceProvider())
{
    random.GetNonZeroBytes(key);
}

string output;
string outputEncrypted;

using (var outputEncryptedStream = new MemoryStream())
{
    using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(text)))
    {
        AesCtrTransform(key, initializationVector, inputStream, outputEncryptedStream);
    }

    outputEncryptedStream.Position = 0;
    using (var reader = new StreamReader(outputEncryptedStream, Encoding.UTF8, true, 1024, true))
    {
        outputEncrypted = reader.ReadToEnd();
    }
    outputEncryptedStream.Position = 0;

    using (var outputDecryptedStream = new MemoryStream())
    {
        AesCtrTransform(key, initializationVector, outputEncryptedStream, outputDecryptedStream);

        outputDecryptedStream.Position = 0;
        using (var reader = new StreamReader(outputDecryptedStream))
        {
            output = reader.ReadToEnd();
        }
    }
}

Assert.IsTrue(!string.IsNullOrEmpty(outputEncrypted));
Assert.AreEqual(text, output);