【问题标题】:Add salt to data to be encrypted?向要加密的数据添加盐?
【发布时间】:2013-09-16 18:51:27
【问题描述】:

假设使用 256 密钥/IV 使用 AES 对少量数据进行加密。加密的数据可能是已知的。例如:

abcdefghijklmno|axXXyyYY343433553353afsafaadfafdfsafsf|2013-01-01T00:00:00

前两部分(如果你打破管道字符上的数据)很少改变。最后一部分,日期/时间确实会改变,但不会经常改变。我注意到更改日期而不是消息的第一部分会导致密码文本始终以相同的开头,大概是因为纯文本的开头是相同的。

这会让我对加密算法进行任何形式的攻击吗?通过在纯文本的开头添加盐值,我会得到什么吗?

我正在使用 AesManaged 类来生成 IV / Key 并加密 / 解密纯文本,如果这有影响的话。

【问题讨论】:

  • 请显示您用于生成密钥/IV 的代码。
  • @Iridium Key / IV 是通过使用 AesManaged 类并调用 GenerateIV 和 GenerateKey 方法生成的,但它们都是固定的。下面的答案告诉我应该为每条消息更改 IV。

标签: c# encryption aes


【解决方案1】:

为了解决这个问题,通常情况下,IV 是为每个密文随机生成的,并在加密数据前添加未加密的内容。这样一来,每一个加密数据都与其他数据不同。

在代码中应该是

string str = "abcdefghijklmno|axXXyyYY343433553353afsafaadfafdfsafsf|2013-01-01T00:00:00";
byte[] data = Encoding.UTF8.GetBytes(str);
byte[] key = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; // Your random key, I hope more random!

byte[] encrypted;

// Encrypt

using (var am = new AesManaged())
using (var rng = new RNGCryptoServiceProvider())
{
    am.Key = key;

    var iv = new byte[am.BlockSize / 8];
    rng.GetBytes(iv);
    am.IV = iv;

    using (var encryptor = am.CreateEncryptor())
    using (var ms = new MemoryStream())
    {
        ms.Write(iv, 0, iv.Length);

        using (var encStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
            encStream.Write(data, 0, data.Length);
        }

        encrypted = ms.ToArray();
    }
}

// Decrypt

string str2;

using (var am = new AesManaged())
using (var ms = new MemoryStream(encrypted))
{
    am.Key = key;

    var iv = new byte[am.BlockSize / 8];
    ms.Read(iv, 0, iv.Length);
    am.IV = iv;

    using (var decryptor = am.CreateDecryptor())
    using (var decStream = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
    using (var ms2 = new MemoryStream())
    {
        decStream.CopyTo(ms2);

        str2 = Encoding.UTF8.GetString(ms2.GetBuffer(), 0, (int)ms2.Length);
    }
}

请注意,通常 IV 重用会导致加密方面的弱点。参见例如wiki:

对于 CBC 和 CFB,重用 IV 会泄露一些关于第一个明文块以及两条消息共享的任何公共前缀的信息。对于 OFB 和 CTR,重用 IV 会完全破坏安全性。 [6]

【讨论】:

  • 是否需要将IV写入流?我会假设 .Net AES 类会处理这个问题,因为您在其上设置了 IV 属性。如果它对每条消息都是唯一的,那么 IV 是否需要保密,还是它像盐一样假设它会被发现?
  • 可以写在流里。它不需要保密。 Net 类不会将其写入流中,因为对于写入位置没有固定标准。
  • 来自我之前引用的 wiki:“初始化向量与密钥具有不同的安全要求,因此 IV 通常不需要保密”
  • 我想知道加密/解密时设置IV的目的是什么。我对 Wiki 链接的理解是,IV 将在消息之前先写入,因此对于相同的纯文本,第一个块是不同的。
  • @Andy 正是这样。具有相等的 IV(或没有 IV),相同的纯文本 = 相同的密文。有了IV,相同的明文=不同的密文,即使有两个IV你也找不到两个明文是一样的。
【解决方案2】:

这是 IV 的主要目的之一。您应该为您发送的每条消息生成一个随机 IV(如果您已经这样做了,那么您的代码肯定有问题)。

【讨论】:

    【解决方案3】:

    AES256 应混合 256 位(32 字节)块中的数据。由于您的前导文本很长(>32 字节)很少更改,因此使用加密方法的性能会很差。您可以解决此问题,但只要明文字符串在前 32 个字节内更改,就可以使用频繁更改的内容开始。您可以通过创建一些随机种子和实际有用的数据来做到这一点。

    播种的目的是使“已知”字符串在加密后不会生成可识别的模式。这正是您将遇到的问题,因此您需要为数据播种或至少在明文开头附近使用易失性数据。

    编辑: 我看到我有一个底片,想知道为什么。首先,通过性能我打算指的是加密的质量,而不是执行时间。当我指的是盐时,我不小心说了种子。一个小错误,但我明白为什么是负面的。我留下我的答案是因为它是唯一一次解释(或试图解释)频繁变化的盐(或至少是某些东西)确实需要与馈送到 AES-256 的 32 字节明文块一起出现。如果您的加密数据受到字典攻击(例如密码)的影响,通常需要加盐,这对于 OP 来说似乎不太可能,但是您的加密数据永远不应该是“可预测的”,这就是为什么 OP 应该在前 32 个数据中加盐的原因字节。

    【讨论】:

    • 性能不佳在这里不应该是一个问题,至少在安全之前不是。重复明文会导致比更改数据更差的性能肯定不是真的(为什么要这样做?)。术语种子(或播种)通常用于伪随机数生成器 (CSPRNG),而不用于加密算法。使用易失性数据(另一个未使用的加密术语)对于 CBC 加密数据是不够的,它必须与随机数据无法区分。
    猜你喜欢
    • 2020-11-03
    • 2011-05-09
    • 1970-01-01
    • 2011-09-19
    • 2021-09-27
    • 2012-11-18
    • 2014-05-03
    • 2010-11-30
    • 2016-04-09
    相关资源
    最近更新 更多