【问题标题】:Need solution for wrong IV length in AES需要解决 AES 中错误 IV 长度的方法
【发布时间】:2011-10-07 11:22:41
【问题描述】:

我正在尝试在 Java 中实现 AES,这是我使用的代码:

 byte[] sessionKey = {00000000000000000000000000000000};
 byte[] iv = {00000000000000000000000000000000};
 byte[] plaintext = "6a84867cd77e12ad07ea1be895c53fa3".getBytes();
 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

 cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
 byte[] ciphertext = cipher.doFinal(plaintext);

 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sessionKey, "AES"), new IvParameterSpec(iv));
 byte[] deciphertext = cipher.doFinal(ciphertext);

我需要这个固定密钥和 IV 用于测试目的,但我得到以下异常:

Exception in thread "main"
java.security.InvalidAlgorithmParameterException: 
  Wrong IV length: must be 16 bytes long    at
com.sun.crypto.provider.SunJCE_h.a(DashoA12275)     at
com.sun.crypto.provider.AESCipher.engineInit(DashoA12275)   at
javax.crypto.Cipher.a(DashoA12275)  at
javax.crypto.Cipher.a(DashoA12275)  at
javax.crypto.Cipher.init(DashoA12275)   at
javax.crypto.Cipher.init(DashoA12275)

如何将此固定 IV 与此 AES 实现一起使用?有什么办法吗?

【问题讨论】:

  • 其实我并没有对这个错误感到困惑,我只是不确定如何使用我现在拥有的 curretn IV

标签: java aes initialization-vector


【解决方案1】:

首先,

byte[] iv = {00000000000000000000000000000000};

创建一个大小为 1 的字节数组,而不是大小为 32 的字节数组(如果这是您的意图)。

其次,AES 的 IV 大小应该是 16 字节或 128 位(这是 AES-128 的块大小)。如果您使用 AES-256,IV 大小应为 128 位大,因为 AES 标准仅允许 128 位块大小。原始的 Rijndael 算法允许其他块大小,包括 256 位长的块大小。

第三,如果您打算使用 AES-256,这并不是开箱即用的。您需要下载并安装JCE Unlimited Strength Jurisdiction Policy Files(滚动到页面底部);我还建议阅读随附的许可证。

这将导致您的代码发生以下更改:

byte[] iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

最后,初始化向量是唯一且不可预测的。一个 16 字节的序列,每个字节由值 0 表示,不适合 IV。如果这是生产代码,请考虑寻求帮助。

【讨论】:

  • 非常感谢您的更正,这真的很有帮助。您能否建议我如何更改 AES-256 的代码?实际上 AES-256 是我想要实现的。
  • IV 大小基于块大小,而不是密钥大小。
  • 那么我如何修改块大小以使用我当前的 IV?
  • @Shahed,我认为 JCE 实现不允许这样做。请注意我所做的编辑 - AES 标准仅允许 128 位的块大小。
  • 使用十六进制解码器,如one in Apache Commons Codec 解码十六进制编码值并获取字节数组。如果您还有其他问题,我建议您将其作为一个新问题提出,因为 cmets 区域并不是真正用于提出新问题的。
【解决方案2】:

来自Advanced Encryption Standard

该标准包含 AES-128、AES-192 和 AES-256 三个分组密码,这些密码取自最初以 Rijndael 发布的较大集合。 这些密码中的每一个都有一个 128 位的块大小,密钥大小分别为 128、192 和 256 位

(已添加重点)

来自Initialization Vector

对于块密码操作模式,IV 通常与密码的块大小一样大

将这两个因素结合在一起,您会发现对于 AES,IV 始终为 128 位,与密钥大小无关。

【讨论】:

  • 你能看看我的问题吗?我似乎无法让它工作。 stackoverflow.com/questions/34061675/…
  • 如果 IV 大小基于块大小,那么为什么 mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);返回 32?它是否返回字节大小以生成 IV 字节?
  • @user4271704 - RIJNDAEL 是 AES 的基础,并且确实使用了不同的块大小。您需要决定是使用 AES(始终为 16 字节)还是 RIJNDAEL。
  • 我知道,我在问如何计算IV大小?我应该将块大小从比特转换为 IV 大小的字节吗?
【解决方案3】:

这里的 AES 可能是 AES-128 而不是 AES-256。如果您想启用 AES-256,则必须包含额外的 jar,因为有出口控制政策。所以先检查一下。在大多数情况下,AES-128 就足够了。

当它是 AES-128 时,您的 IV 不能超过 128 位,即 16 字节。所以改变初始化向量长度。

那一定行得通。另外,请阅读此http://en.wikipedia.org/wiki/Initialization_vector

警告:固定 IV 不是一个好习惯。它必须是随机的或伪随机的以提供更好的安全性。

【讨论】:

【解决方案4】:

为什么不直接使用类似的东西而不是使用“幻数”:

SecureRandom random = new SecureRandom();
byte[] iv = random.generateSeed(16);

所以你的 iv 有 16 个随机字节。

【讨论】:

  • 无需手动生成 IV。加密后可以从Cipher中获取:cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
  • 解密你需要相同的IV,所以使用随机IV至少你保存生成的IV是行不通的
【解决方案5】:

我遇到这个问题的原因是因为我将 IV 作为字符串读取,并以错误的方式将其转换为字节数组。

正确的方法:

Hex.decodeHex(initializationVector.toCharArray()

使用org.apache.commons.codec.binary.Hex

错误的方式:

initializationVector.getBytes()

这是错误的,因为当您调用 getBytes() 时,它只获取表示字符串的所有位并将它们切割成字节。所以0 最终被写入 Unicode 表中构成0 索引的位,它不是 0 而是 30,并且将写入 2 个字节。

反之,这里你想要的实际上是将0表示为字节00000000

【讨论】:

    【解决方案6】:

    与此无关,但面临同样的问题。

    IvParameterSpec ivParameterSpec = new IvParameterSpec(key1.getBytes("UTF-8")); SecretKeySpec skeySpec = new SecretKeySpec(key2.getBytes("UTF-8"),"AES"); 我犯的错误是 key1 和 key2 是长度大于 16 的字符串。将它们的长度更改为 16 修复它。

    【讨论】:

      猜你喜欢
      • 2022-09-26
      • 1970-01-01
      • 1970-01-01
      • 2020-02-12
      • 2014-01-20
      • 2015-07-06
      • 1970-01-01
      • 1970-01-01
      • 2020-04-28
      相关资源
      最近更新 更多