Как сгенерировать Rijndael KEY и IV с использованием ключевой фразы? - PullRequest
26 голосов
/ 26 июня 2011

Как сгенерировать Rijndael KEY и IV с использованием ключевой фразы? Длина ключа должна быть в 256 битах.

Ответы [ 5 ]

56 голосов
/ 30 июня 2011

Я думаю, что вы ищете для получения ключа на основе пароля.Существует класс Rfc2898DeriveBytes, который его реализует.

Rfc2898DeriveBytes берет пароль, соль и счетчик итераций, а затем генерирует ключи посредством вызовов метода GetBytes.

RFC 2898 включает методы для создания ключа и вектора инициализации (IV) из пароля и соли.Вы можете использовать PBKDF2, функцию получения ключей на основе пароля, для получения ключей с использованием псевдослучайной функции, которая позволяет генерировать ключи практически неограниченной длины.Класс Rfc2898DeriveBytes можно использовать для создания производного ключа из базового ключа и других параметров.В функции получения ключа на основе пароля базовый ключ представляет собой пароль, а другие параметры - это солт-значение и счетчик итераций.

Для получения дополнительной информации о PBKDF2 см. RFC 2898, «PKCS # 5: Пароль».Спецификация криптографии на основе версии 2.0, ".

Пример:

public static byte[] CreateKey(string password)
{
    var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

    const int Iterations = 9872;
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
        return rfc2898DeriveBytes.GetBytes(32);
}

Вы можете использовать DeriveBytes в любом симметричном алгоритме, а не только Rijndael.
Пример:

public static SymmetricAlgorithm InitSymmetric(SymmetricAlgorithm algorithm, string password, int keyBitLength)
{
    var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };

    const int Iterations = 234;
    using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, salt, Iterations))
    {
        if (!algorithm.ValidKeySize(keyBitLength))
            throw new InvalidOperationException("Invalid size key");

        algorithm.Key = rfc2898DeriveBytes.GetBytes(keyBitLength / 8);
        algorithm.IV = rfc2898DeriveBytes.GetBytes(algorithm.BlockSize / 8);
        return algorithm;
    }
}

private static byte[] Transform(byte[] bytes, Func<ICryptoTransform> selectCryptoTransform)
{
    using (var memoryStream = new MemoryStream())
    {
        using (var cryptoStream = new CryptoStream(memoryStream, selectCryptoTransform(), CryptoStreamMode.Write))
            cryptoStream.Write(bytes, 0, bytes.Length);
        return memoryStream.ToArray();
    }
}

Использование:

public static void Main()
{
    using (var rijndael = InitSymmetric(Rijndael.Create(), "TestPassword", 256))
    {
        var text = "Some text to encrypt";
        var bytes = Encoding.UTF8.GetBytes(text);

        var encryptedBytes = Transform(bytes, rijndael.CreateEncryptor);
        var decryptedBytes = Transform(encryptedBytes, rijndael.CreateDecryptor);

        var decryptedText = Encoding.UTF8.GetString(decryptedBytes);
        Debug.Assert(text == decryptedText);
    }
}

Обязательно измените параметры salt и iterations.

37 голосов
/ 01 июля 2011

Это код plug and play, который я нашел в интернете. Это просто работает:

using System.IO;
using System.Security.Cryptography;

private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c };

public static byte[] Encrypt(byte[] plain, string password)
{
    MemoryStream memoryStream;
    CryptoStream cryptoStream;
    Rijndael rijndael = Rijndael.Create();
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
    rijndael.Key = pdb.GetBytes(32);
    rijndael.IV = pdb.GetBytes(16);
    memoryStream = new MemoryStream();
    cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
    cryptoStream.Write(plain, 0, plain.Length);
    cryptoStream.Close();
    return memoryStream.ToArray();
}

public static byte[] Decrypt(byte[] cipher, string password)
{
    MemoryStream memoryStream;
    CryptoStream cryptoStream;
    Rijndael rijndael = Rijndael.Create();
    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
    rijndael.Key = pdb.GetBytes(32);
    rijndael.IV = pdb.GetBytes(16);
    memoryStream = new MemoryStream();
    cryptoStream = new CryptoStream(memoryStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write);
    cryptoStream.Write(cipher, 0, cipher.Length);
    cryptoStream.Close();
    return memoryStream.ToArray();
}
9 голосов
/ 27 июня 2011

IV должен быть случайным (не должен быть непредсказуемым, достаточно случайным, чтобы их нельзя было использовать повторно).

Что касается генерации ключа из пароля, вы ищете функцию получения ключа , для которой в настоящее время существует по крайней мере три хороших варианта (PBKDF2, bcrypt, scrypt), использующих не повторяющийся хеш как предыдущий плакат чаще всего говорит о небезопасных системах.

Также используйте AES или Rijndael, это не совсем то же самое. Использование комбинации Rijndael, не являющейся частью AES, может позже стать кошмаром для взаимодействия, и безопасность комбинации этих функций в любом случае недостаточно изучена.

4 голосов
/ 26 июня 2011

IV должно быть случайным (обычно вы передаете его вместе с зашифрованными данными), и ключ может быть получен несколькими способами: просто введите пароль с длиной ключа (если пароль короче 32 символов)) или (что более надежно) получить ключ с помощью алгоритма хэширования SHA2 или использовать более сложный способ.

2 голосов
/ 02 июля 2011

Используйте это Rfc2898DeriveBytes Class .

Однако, совет, ваш уровень безопасности упал / ограничен длиной / силой парольной фразы. Так что не делай этого.

...