如何使用口令生成Rijndael KEY和IV?密钥长度必须为256位。
如何使用口令生成Rijndael KEY和IV?密钥长度必须为256位。
我认为你正在寻找基于密码的密钥派生方法。有一个实现它的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
参数。
这是我在互联网上找到的即插即用代码。它只需要运行:
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();
}
IV必须是随机的(不需要是无法预测的随机,只需要足够随机以避免被重用)。
关于从密码生成密钥,您需要寻找一个key derivation function,现在至少有三个好选择(PBKDF2,bcrypt,scrypt),使用先前某位帖子建议的非迭代哈希往往会导致不安全的系统。
另外不要使用AES或Rijndael,它们并不完全相同。使用不属于AES的Rijndael组合可能会在以后造成互操作性问题,而这些函数组合的安全性也没有得到很好的研究。
IV必须是随机的(通常与加密数据一起传递),而密钥可以通过多种方式派生:如果密码长度小于32个字符,只需将密码填充到密钥长度即可(这种方法不够可靠),或者使用SHA2哈希算法派生密钥(更可靠),也可以使用一些更复杂的方式。
// use something more random in real life
var salt = new byte[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
string password = "my-password";
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt);
var key = pdb.GetBytes(32);
var iv = pdb.GetBytes(16);