8

我正在尝试在 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 实现一起使用?有什么办法吗?

4

6 回答 6

42

首先,

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

于 2011-07-18T07:44:20.183 回答
15

高级加密标准

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

(重点补充)

初始化向量

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

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

于 2011-07-18T07:41:29.600 回答
2

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

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

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

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

于 2011-07-18T07:41:29.573 回答
2

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

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

因此,您的 iv 获得 16 个随机字节。

于 2014-06-26T15:55:59.860 回答
0

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

正确的路:

Hex.decodeHex(initializationVector.toCharArray()

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

错误的方法:

initializationVector.getBytes()

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

相反,您在这里想要的实际上0是表示为 byte 00000000

于 2019-04-27T20:47:20.110 回答
0

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

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

于 2022-01-07T08:46:33.200 回答