为什么这种AES加密不起作用?我用Java编写它来测试,但我无法解密。解密后我得到了垃圾。为什么?它如此简单 - 在主要方法中,打印纯文本,加密,打印密文,解密,再次打印纯文本。难道我做错了什么?请帮我弄清楚问题。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class AESTest {
public static void main(String [] args) {
try {
String plainText = "Hello World!!!!!";
String encryptionKey = "E072EDF9534053A0B6C581C58FBF25CC";
System.out.println("Before encryption - " + plainText);
String cipherText = encrypt(plainText, encryptionKey);
System.out.println("After encryption - " + cipherText);
String decrypted = decrypt(cipherText, encryptionKey);
System.out.println("After decryption - " + decrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String encrypt(String plainText, String passkey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(hexStringToByteArray(passkey), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[cipher.getBlockSize()]));
String cipherText = new String(cipher.doFinal(plainText.getBytes()));
return cipherText;
}
public static String decrypt(String cipherText, String passkey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(hexStringToByteArray(passkey), "AES");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[cipher.getBlockSize()]));
String plainText = new String(cipher.doFinal(cipherText.getBytes()));
return plainText;
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
答案 0 :(得分:5)
密码的输出是一系列随机字节。您不能保证这些字节对于系统的默认编码中的字符串是有效的编码。所以这一行:
String cipherText = new String(cipher.doFinal(.....));
可能会丢失您需要解密的信息。
因此,您将无法在decrypt
操作中重建正确的字节。例如,如果您的默认编码是UTF-8,则绝对不可能正确的密文是String.getBytes()
甚至能够生成的密文。
答案 1 :(得分:4)
两件事:
如果使用的密钥大小与128位或16字节完全相同,则填充只能起作用。所以在你的特殊情况下“Hello World !!!!!”。getBytes()实际上是16的倍数,但对任意字符串来说当然不是这样。
使用“AES / CBC / PKCS5Padding”代替解决此问题。
不要将加密数据转换为字符串 - 这将改变加密输出。无法保证新的String(byte [])。getBytes()返回完全相同的字节数组!
因此,您应该将加密数据保留为原样 - 字节流。因此encrypt
应该返回byte[]
而解密应该以{{1}}作为输入 - 这是一个有效的例子:
byte[]
答案 2 :(得分:1)
您需要创建一次SecretKeySpec对象,并将其用于加密和解密。目前,代码为每个操作创建了两个不同的密钥,这肯定会导致错误的结果。