对称加密(AES):将IV和Salt与加密数据一起保存是否安全正确



当使用对称加密算法(在本例中为AES)加密和解密数据时,我试图弄清楚如何处理和管理初始化向量和salt(如果适用)。

我从不同的SO线程和各种其他网站推断,IV或salt都不需要是秘密的,只有在抵御密码分析攻击(如暴力攻击)时才是唯一的。考虑到这一点,我认为用加密数据存储我的伪随机IV是可行的。我在问我使用的方法是否正确,此外,我是否应该以同样的方式处理我目前的硬编码盐?将其写入IV 旁边的内存流

我的代码:

private const ushort ITERATIONS = 300;
private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22,  0x3c };
private static byte[] CreateKey(string password, int keySize)
{
DeriveBytes derivedKey = new Rfc2898DeriveBytes(password, SALT, ITERATIONS);
return derivedKey.GetBytes(keySize >> 3);
}
public static byte[] Encrypt(byte[] data, string password)
{
byte[] encryptedData = null;
using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
{
provider.GenerateIV();
provider.Key = CreateKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data.Length))
{
memStream.Write(provider.IV, 0, 16);
using (ICryptoTransform encryptor = provider.CreateEncryptor(provider.Key, provider.IV))
{
using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
}
}
encryptedData = memStream.ToArray();
}
}
return encryptedData;
}
public static byte[] Decrypt(byte[] data, string password)
{
byte[] decryptedData = new byte[data.Length];
using (AesCryptoServiceProvider provider = new AesCryptoServiceProvider())
{
provider.Key = CreateKey(password, provider.KeySize);
provider.Mode = CipherMode.CBC;
provider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream(data))
{
byte[] iv = new byte[16];
memStream.Read(iv, 0, 16);
using (ICryptoTransform decryptor = provider.CreateDecryptor(provider.Key, iv))
{
using (CryptoStream cryptoStream = new CryptoStream(memStream, decryptor, CryptoStreamMode.Read))
{
cryptoStream.Read(decryptedData, 0, decryptedData.Length);
}
}
}
}
return decryptedData;
}

我也愿意接受关于对称加密的任何其他适当做法的信息。

将IV和Salt与密文一起存储是正确的,也是最佳实践。对salt进行硬编码是没有用的,随机性很重要,对迭代进行硬编码完全可以,但通常远高于300(事实上,至少为1000,如果你的机器/使用情况可以处理成千上万)。

因为我看到了很多从堆栈溢出剪切粘贴到开源代码中的c#加密的坏例子(或旧例子),所以我写了一小段剪切粘贴加密代码字符串的对称身份验证加密的现代例子。我努力跟上最新情况并复习。它将iv和salt与密文一起存储,还验证密文和密文中包含的值。

理想情况下,尽管更好的做法是使用高级加密库,为您处理iv等最佳实践,但csharp通常还不存在这些做法。我一直在开发谷歌keyczar库的原生csharp版本。虽然它在功能上已经可以使用了,但我一直希望在第一次正式稳定发布之前更多地关注代码。

是的,IV和salt都是公共值。更重要的是确保这些是每个加密操作的随机值。

要在野外给出一个例子,请查看rncryptor数据格式。在这里,salt和IV与密文和MAC值一起被打包成数据格式。(注意:这是一个objective-c示例)。