Как создать ключ Rijndael и IV с помощью парольной фразы?

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

5 ответов


Это подключи и играй код, который я нашел в интернете. Это просто работает:

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();
}

Я думаю, что вы ищете ключ на основе пароля деривации. Есть 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 параметры.


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

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

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


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


использовать Rfc2898DeriveBytes Класс.

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