如何使用密码短语生成Rijndael KEY和IV?

Pre*_*tor 26 .net c# vb.net cryptography rijndael

如何使用密码短语生成Rijndael KEY和IV?密钥长度必须为256位.

Ale*_*Aza 58

我认为您正在寻找基于密码的密钥派生.有Rfc2898DeriveBytes类实现它.

Rfc2898DeriveBytes获取密码,salt和迭代计数,然后通过调用GetBytes方法生成密钥.

RFC 2898包括用于从密码和salt创建密钥和初始化向量(IV)的方法.您可以使用基于密码的密钥派生函数PBKDF2来使用伪随机函数导出密钥,该函数允许生成几乎无限长度的密钥.Rfc2898DeriveBytes类可用于从基本密钥和其他参数生成派生密钥.在基于密码的密钥派生函数中,基本密钥是密码,其他参数是salt值和迭代计数.

有关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);
}
Run Code Online (Sandbox Code Playgroud)

您可以使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

确保更改saltiterations参数.


Pan*_*zza 37

这是我在互联网上找到的即插即用代码.它只是工作:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • @Gens - 我一直认为应该选择最佳答案,这个答案对所有用户最有用.我花了很多时间来制作可重用的API和示例.虽然你鼓励新用户,但对于旧用户来说这绝对是不公平和令人沮丧的. (17认同)
  • 这甚至没有开始涉及重复使用相同的IV的问题.不要这样做.每当你重新使用静脉注射时,小猫的熵就会以惊人的速度迅速增加. (8认同)
  • 关于line-rijndael.Key = pdb.GetBytes(32); rijndael.IV = pdb.GetBytes(16); 这是否意味着IV只是Key的前半部分?这有安全隐患吗? (5认同)

Bru*_*hée 9

IV必须是随机的(不需要是一个不可预测的随机,只是随机的,它们不会被重用).

至于从密码生成密钥,你正在寻找一个密钥派生函数,现在至少有三个不错的选择(PBKDF2,bcrypt,scrypt),使用非迭代哈希作为前一个海报建议更多的是不安全的系统.

也使用AES或Rijndael,这不完全相同.使用Rijndael组合不是AES的一部分可能是后来的互操作性噩梦,并且这些功能组合的安全性无论如何都没有得到很好的研究.