需要解决AES中错误的IV长度问题

问题描述 投票:5回答:5

我正在尝试在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)

如何在此AES实现中使用此固定IV?有什么办法吗?

java aes initialization-vector
5个回答
38
投票

首先,

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。如果这是生产代码,请考虑获取帮助。


14
投票

来自Advanced Encryption Standard

该标准包括三个分组密码,AES-128,AES-192和AES-256,采用最初发布为Rijndael的大型系列。这些密码中的每一个都具有128位块大小,密钥大小分别为128,192和256位

(重点补充)

来自Initialization Vector

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

将这两个因素结合在一起,您可以得到AES始终为128位AES,与密钥大小无关。


2
投票

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

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

那必须奏效。另外,请阅读此http://en.wikipedia.org/wiki/Initialization_vector

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


2
投票

为什么不使用类似的东西而不是使用“魔术数字”:

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

所以你的iv会得到16个随机字节。


0
投票

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

正确的方法:

Hex.decodeHex(initializationVector.toCharArray()

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

错误的方法:

initializationVector.getBytes()

这是错误的原因,是因为你打电话的时候 getBytes() ,它只需要代表字符串的所有位并将它们切换成字节。因此,0最终被编写为组成Unicode表中0索引的位,该表不是0而是30,并且将写在2个字节上。

相反,你想要的实际上是0被表示为字节00000000

© www.soinside.com 2019 - 2024. All rights reserved.