密码学:为什么我的加密初始化向量只影响前16个字节?

5
我想尝试加密一个文件,使用了以下stackoverflow response,但在测试初始化向量时,我发现它只影响前16个字节。当我将一个空的iv传递给解密密码(除了前16个字节之外),数据被意外地解密了。[我假设库没有问题,我做错了什么;但其他人可能也处于同样的困境,却没有意识到。]

Example:

    Initial bytes ..... 2222222222222222222222222222222222222222222222222222
    Encrypted bytes ... b35b3945cdcd08e2f8a65b353ff754c32a48d9624e16b616d432
    Decrypted bytes ... 3c4154f7f33a2edbded5e5af5d3d39b422222222222222222222
Q: Why isn't the entire decryption failing?

假设我可以通过每次迭代16个字节并通过哈希先前加密的16个字节块更新iv来进行加密。然而,这似乎是繁琐的工作,我本来期望库会自己完成。我也希望这些专家在提供实施指南时会提到它。但我只是在瞎猜。说不定安全社区只担心对第一个块的黑客攻击。
注意:刚才我找到了一个5.5年前的stack overflow post,发现了同样的问题;不幸的是,它仍然没有得到回应。


``` package test;
import java.security.AlgorithmParameters; import java.security.spec.KeySpec; import java.util.Formatter; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec;
/* * 问题:使用“AES/CBC/PKCS5Padding”加密时,初始化向量只影响第一个块?! * * 示例输出: *    iv 1e6376d5d1180cf9fcf7c78d7f1f1b96 *    bv 00000000000000000000000000000000 *    I: 222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 *    E: b35b3945cdcd08e2f8a65b353ff754c32a48d9624e16b616d432ee5f78a26aa295d83625634d1048bf2dbb51fc657b7f796b60066129da5e1e7d3c7b51a30c1d962db75ac6666d4b32513c154b47f18eb66f62d7417cfd77f07f81f27f08d7d818e6910ca5849da3e6cff852bc06317e2d51907879598c8d3ae74074f4c27f7b8e2f74ca04d3ed6ac839b819a0f4cb462d0a4d9497cd917b8bd0aafb590ddd593b5b652cf8f642d3b2cd9dc0981dc1c913d52d065a844ea65e72cd7738eee3b488c4304e884109320dc54668ac4659d6014de9cf19422f7f68157d4330478589533571434d07b1939e56259fb8828823361bc912b84dc6ccdd5878b1d05801e0a6ce099bc86f1356fd145338163d59a07f2efdb1a6f91f4a35e6304f2d15d9972b0dda3c2275b5942a7f032ab6f90138 *    D: 3c4154f7f33a2edbded5e5af5d3d39b422222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222 */ public class IvBug {
public static void main(String[] args) throws Exception { // 初始化。 final char[] password = "foo".toCharArray(); final byte[] salt = "bar".getBytes();
byte[] iData = new byte[300]; java.util.Arrays.fill(iData, (byte)0x22); // 使问题更容易看到。 // for (int i=0; i<msg.length; i++) msg[i] = (byte) i; // 替

1个回答

4

您似乎误解了我们使用 IV 的原因。您观察到的行为是预期的行为。请参考来自Wikipedia的 CBC 模式工作示意图:

CBC Decryption

当我们解密时,IV仅用于派生加密数据的第一个块。请注意,在图表中,我们实际上不需要IV来解密任何后续块。
我觉得你可能(错误地)认为IV与密码的安全性相关。事实并非如此。密钥是秘密值。IV不需要保密。对IV的唯一要求是它在密码学上是随机且不可预测的。

我现在看到 IV 状态的维基描述是:“对于 CBC 和 CFB,重复使用一个 IV 会泄漏有关明文的第一个块以及两个消息共享的任何公共前缀的某些信息。” 因此,我认为他们一定要保护第一个块中的某些标题信息。我猜 PCBC 可以满足我的期望。并且知道他们只是保护头部信息,你改变了我的期望。谢谢! - robertf
没有头信息。IV重用只是将第一个密文块以与ECB模式相同的方式变得容易受攻击。可能值得更多地阅读这个主题。很高兴我能帮助。 - Luke Joshua Park
如果任意两条消息分享跨越多个块的“公共前缀”,那么除了第一个块外,其他所有块都会有这种漏洞吗? - robertf
如果我理解您的意思正确,那么不是的。这是在CBC模式下的关键之处。通过将每个结果的密文块与下一个明文块进行异或运算,我们确保没有有意义的重复。由于在第一个块中没有可以使用的密文块,因此IV用于第一个块。 - Luke Joshua Park
啊,漏洞就在生成的密文本身(而不是解密过程中)。所以正如你所说,确实只有第一个块需要随机IV。 - robertf
@robertf IV应该是每个加密过程中不同的随机值。一种常见的方法是创建一个随机IV,用于加密,并在解密时使用前缀IV以进行解密数据的提取。 - zaph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接