【问题标题】:Symmetric Encryption (AES): Is saving the IV and Salt alongside the encrypted data safe and proper?对称加密 (AES):将 IV 和 Salt 与加密数据一起保存是否安全且正确?
【发布时间】:2012-12-16 13:03:01
【问题描述】:

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

我从不同的 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;
}

我也愿意接受有关正确实践的对称加密的任何其他信息。

【问题讨论】:

  • 如果您没有将它们与加密数据一起存储,则需要将它们存储在某个地方 - 所以 YMMV。
  • 在 CBC 模式下,每个加密块都充当下一个块的 IV,因此作为公共值的 IV 不能与安全相关 - 否则 CBC 操作模式将不安全。 :)
  • @vhallac 好吧,V(向量)作为IV(初始化向量)显然只能是第一个。
  • Salt 和 IV 不是 keyplaintext 的一部分,这两件事必须保密。重要的是你的盐是加密强度随机的。不要使用一些弱随机源。
  • 附带说明:我强烈建议添加 MAC。缺少 MAC 通常会导致主动攻击,例如填充预言机。

标签: c# encryption cryptography encryption-symmetric


【解决方案1】:

将 IV 和 Salt 与密文一起存储是正确的,也是最佳实践。对盐进行硬编码是没有用的,随机很重要,对迭代进行硬编码是完全可以的,但通常远高于 300(实际上至少 1000,如果你的机器/使用可以在 10 秒内处理它,你通常会更高数千)。

因为我已经看到了很多糟糕(或旧)的 c# 加密示例,从堆栈溢出剪切和粘贴到开源代码中,我写了一小段剪切和粘贴加密代码 Modern Examples of Symmetric Authenticated Encryption of a string.,我试图跟上迄今为止和审查。它将 iv 和 salt 与密文一起存储它还验证密文和密文中包含的值。

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

【讨论】:

    【解决方案2】:

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

    要举一个实际的例子,请查看rncryptor data format。在这里,盐和 IV 与密文和 MAC 值一起打包成数据格式。 (注意:这是一个objective-c的例子)。

    【讨论】:

      猜你喜欢
      • 2017-07-07
      • 1970-01-01
      • 2012-02-21
      • 1970-01-01
      • 2012-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多