我正在尝试在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?有什么办法吗?
首先,
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。如果这是生产代码,请考虑获取帮助。
来自Advanced Encryption Standard:
该标准包括三个分组密码,AES-128,AES-192和AES-256,采用最初发布为Rijndael的大型系列。这些密码中的每一个都具有128位块大小,密钥大小分别为128,192和256位
(重点补充)
对于分组密码操作模式,IV通常与密码的块大小一样大
将这两个因素结合在一起,您可以得到AES始终为128位AES,与密钥大小无关。
这里的AES可能是AES-128而不是AES-256。如果要启用AES-256,则必须包含额外的jar,因为有适当的出口控制策略。所以先检查一下。在大多数情况下,AES-128就足够了。
当IV为AES-128时,你的IV不能超过128位,即16字节。所以改变初始化矢量长度。
那必须奏效。另外,请阅读此http://en.wikipedia.org/wiki/Initialization_vector
警告:固定IV不是一个好习惯。它必须是随机的或伪随机的,才能提供更好的安全性。
为什么不使用类似的东西而不是使用“魔术数字”:
SecureRandom random = new SecureRandom();
byte[] iv = random.generateSeed(16);
所以你的iv会得到16个随机字节。
我遇到这个问题的原因是因为我将IV作为字符串读取,并以错误的方式将其转换为字节数组。
正确的方法:
Hex.decodeHex(initializationVector.toCharArray()
使用org.apache.commons.codec.binary.Hex
错误的方法:
initializationVector.getBytes()
这是错误的原因,是因为你打电话的时候
getBytes()
,它只需要代表字符串的所有位并将它们切换成字节。因此,0
最终被编写为组成Unicode表中0
索引的位,该表不是0而是30,并且将写在2个字节上。
相反,你想要的实际上是0
被表示为字节00000000
。