使用 AES-256 加密,我可以使用 256 位 IV 吗?

信息安全 AES 初始化向量
2021-08-21 10:23:26

我想在java中使用AES加密数据,我想用初始化向量初始化密码。我可以使用 256 位 IV 吗?或者我必须只使用 128 位 IV ?

4个回答

IV 取决于操作模式对于大多数模式(例如 CBC),IV 必须与block具有相同的长度AES 使用 128 位块,因此是 128 位 IV。请注意,AES-256 使用 256 位密钥(因此得名),但仍然使用 128 位块。

AES 被选为称为Rijndael的分组密码系列的一个子集。该系列包括不少于 15 个变体,用于三种可能的块大小(128、192 和 256 位)和五种可能的密钥大小(128、160、192、224 和 256 位)。由 NIST 标准化的AES仅包括三个变体,均具有 128 位块,并且具有 128、192 或 256 位的密钥。

更令人困惑的是,一些软件框架弄错了;例如,PHP 使用“MCRYPT_RIJNDAEL_128”来指定具有 128 位密钥和 128 位块(即与 AES-128 相同的东西)的 Rijndael,并使用“MCRYPT_RIJNDAEL_256”来指定具有 256 位密钥和 256 位块的 Rijndael(即不是一个AES 变体,特别是根本不是 AES-256)。

Java 中的 IV 处理取决于所使用的加密提供程序。OpenJDK / Oracle 运行时附带的 SUN 提供程序相当严格;对于大多数操作模式,它要求 IV 的大小与块大小相同即使对于 CTR 模式也是如此,在这种模式下,您可能期望提供一个随机数 - 计数器的第一个/最左边的字节 - 就足够了。ECB 模式当然不需要 IV,因此如果您尝试提供 IV,它将引发异常。

AES 的块大小始终为 128 位,因此对于大多数操作模式来说,256 位 IV 是不可能的。正如在一些答案中已经指出的那样,Rijndael 可以配置为 256 位的块大小,但 Rijndael 不包含在标准运行时中。您需要额外的提供程序或库(例如 Bouncy Castle)才能使用 Rijndael。分组密码 AES 不使用 IV 作为输入,这也是为 ECB 模式提供 IV 失败的原因。其他一些语言/运行时只是忽略 ECB 的 IV

现在有一个密码可以让你指定一个 256 位的 IV(或者实际上是:nonce),那就是 GCM。GCM 最好使用 12 字节的随机数。GCM 在内部将数据(包括随机数)转换为 CTR 模式的 128 位计数器。

请注意,增加 IV 大小不会自动使算法更安全。如果您的 IV 有 256 位输入,那么您可以在输入上使用 SHA-256 位并取而代之的是 128 位。


当我们谈论 Java 时,这里有一些代码,你可以摆弄 IV 大小并尝试一些算法,比如"AES/CFB/NoPadding"你自己。请注意,代码中使用的静态 IV 仅用于演示目的CTR 需要一个唯一的 IV,CBC 需要一个完全不可预测的 IV(通常通过随机化 AES 的所有 16 个字节来实现)。

SecretKey aesKey = new SecretKeySpec(new byte[256 / Byte.SIZE], "AES");
byte[] pt = "owlstead".getBytes(StandardCharsets.US_ASCII);

{
    // === CBC mode requires an IV of the same size as the block size
    Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
    // changing the IV size will result in an exception
    byte[] ivBytes = new byte[c.getBlockSize()];
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
    byte[] ct = c.doFinal(pt);
    System.out.println(Hex.toHexString(ct));
}

{
    // === CTR mode actually requires a complete IV in Java
    // Java (or actually, the SUN provider) requires a 128 bit IV instead of just a nonce
    Cipher c = Cipher.getInstance("AES/CTR/NoPadding");
    // changing the IV size will result in an exception
    byte[] ivBytes = new byte[c.getBlockSize()];
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
    byte[] ct = c.doFinal(pt);
    System.out.println(Hex.toHexString(ct));
}

{
    // === GCM mode can do it!
    Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
    byte[] ivBytes = new byte[256 / Byte.SIZE];
    GCMParameterSpec gcmSpecWithIV = new GCMParameterSpec(128, ivBytes);
    c.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpecWithIV);
    byte[] ct = c.doFinal(pt);
    System.out.println(Hex.toHexString(ct));
}

{
    // ===  java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
    Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
    byte[] ivBytes = new byte[c.getBlockSize()];
    IvParameterSpec iv = new IvParameterSpec(ivBytes);
    c.init(Cipher.ENCRYPT_MODE, aesKey, iv);
    byte[] ct = c.doFinal(pt);
    System.out.println(Hex.toHexString(ct));
}

您必须使用 128 位 IV。对于 CBC 模式,IV 必须匹配块大小,对于 AES,块大小始终为 128 位。

获胜的 AES 候选者 Rijndael 被定义为 128 和 256 位块,但只有 128 位块被标准化为 AES。一些库支持带有 256 位块的 Rijndael,但是您不再使用 AES。

如果出于某种原因需要更长的 IV,您可以使用 KDF 或哈希将原始密钥和 IV 转换为您实际用于 AES 的密钥。

IV 的目的是稍微“混合”一下。

没有它,具有相同第一个明文块的消息将共享相同的第一个密文块。这种情况并不少见,请考虑以关于其文件类型的标准声明或 SMTP 使用诸如 RCPT TO:、MAIL FROM: 等作为常见元素的方式开始的文件。128bits(AES的块大小)很小,所以会发生这种事情。

有不同的操作模式,但使用 CBC 作为最简单的(也许仍然是最常见的?)来自一个块的密文用于输入下一个块,即使用由第一个明文块制成的加密输出(密文)对块 2 的明文进行异或运算(在此之前加密)。每个块的密文用于异或(异或)下一个块的明文,因此名称为 Cipher block CHAINING问题是第一个块之前没有块(无论如何在CBC中......)

这就是首先描述的问题所在——如果使用相同的密钥加密它们,具有相同第一个明文块的消息将共享相同的第一个密文块。

为了避免这个问题,使用了 IV(初始化向量)。这是一个可用于异或(异或)启动链的第一个块的材料块。IV 随消息一起发送,否则无法开始解密。

即使使用相同的密钥一遍又一遍地重新加密相同的消息,第一个加密块每次都会不同,因此通过链接,整个加密消息每次都会不同。

如果您考虑使用 IV 所做的事情,在我的 CBC 示例中,讨论大于或小于 128 位块大小的任何大小的 IV 根本没有意义,因为这是您需要的第一个块的大小“混合”,从那时起,您使用以前的密文将其链接起来。(好吧,这并非适用于所有模式,一些 IV 可能需要小于第一个块,但我们现在只考虑 CBC)。所以对于 CBC,IV 必须与块大小相同,在 AES 中它总是 128 位(不管密钥大小)。

考虑到 IV 长度,安全性的好处并不多,不要认为更长的 IV 一定意味着更好的安全性,IV 不是关键!

IV 的问题更多是您生成 IV 的内容/方式。它们必须是高质量的(即在统计上与任何先前使用的 IV 无关的统一伪随机材料),如果您的 IV 生成方案或密钥计划不佳,您可能会破坏安全性,可能会基于统计数据进行密码分析技巧。

我真正想说的是,密码学有点复杂:) ,即使犯了一个善意的错误也会导致一些灾难性的后果。一些原本不错的方案已经被小的实现错误完全毁掉了。还记得无线的 WEP 吗?

如果您没有完全深入地理解所涉及的所有因素,请遵守标准,并使用使用良好(经过同行评审)的库和已建立的实践。

除非您了解所有后果,否则即使出于最好的意图,尝试做一些聪明的事情也是极其危险的。我要非常礼貌地说的是,如果您需要问这样的问题:要使用的 IV 大小是多少,您不应该尝试尝试如何实现,只需坚持标准值即可。

祝您编码愉快,享受...