我在Java中使用AES加密/解密时遇到了一个非常奇怪的问题。如果我正在加密/解密一个小于16字节的字符串,则密码可以正常工作,但如果我提供大于16字节的密码,我会收到错误“给定最终块没有正确填充”。我构建了一些小代码作为示例:
package com.company;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Main {
public static void main(String[] args) {
try {
Cipher aesEncrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
Cipher aesDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec key = new SecretKeySpec("ABCDEQWERTASDFGA".getBytes(), "AES");
IvParameterSpec ivSpec = new IvParameterSpec(new byte[16]);
aesDecrypt.init(Cipher.DECRYPT_MODE, key, ivSpec);
aesEncrypt.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] message = "Hello".getBytes();
aesEncrypt.update(message);
byte[] encrypted = aesEncrypt.doFinal();
aesDecrypt.update(encrypted);
byte[] decrypted = aesDecrypt.doFinal();
System.out.println(new String(decrypted, "UTF-8"));
}
catch (Exception e){
e.printStackTrace();
}
}
}
当byte []消息为“Hello”时,加密/解密工作正常,但当我将其更改为“HelloMyBabyHelloMyDarling”时,它会抛出异常。有谁知道我在这里做错了什么?
答案 0 :(得分:3)
Cipher#update(byte[])
会返回您因某些原因未使用的byte[]
。您只是丢弃除最后一个块之外的所有内容(Cipher#doFinal()
在应用填充后返回最后一个加密块)。如果您的消息只包含一个块,则密文和解密的明文将完整。
由于您使用短信,因此您根本不需要使用Cipher#update
。只需使用Cipher#doFinal(byte[])
:
byte[] message = "Hello".getBytes();
byte[] encrypted = aesEncrypt.doFinal(message);
byte[] decrypted = aesDecrypt.doFinal(encrypted);
如果您尝试加密较长的数据(可能不适合内存),那么您应该将Cipher#update
结果写入OutputStream或使用不带update
或{{的CipherOutputStream 1}}来电。