为什么这种简单的AES加密不起作用?

时间:2011-08-18 21:55:49

标签: java encryption aes

为什么这种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; } }

3 个答案:

答案 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对象,并将其用于加密和解密。目前,代码为每个操作创建了两个不同的密钥,这肯定会导致错误的结果。