java中AES解密算法的例外

我在下面的代码中得到了一个例外,用于java中的AES算法。

代码解密加密的字符串并返回原始字符串。

Plz帮助我解决这个问题。

码:

public class AES { public byte[] encrypted; public byte[] original; public String originalString; public static String asHex (byte buf[]) { StringBuffer strbuf = new StringBuffer(buf.length * 2); int i; for (i = 0; i < buf.length; i++) { if (((int) buf[i] & 0xff) < 0x10) strbuf.append("0"); strbuf.append(Long.toString((int) buf[i] & 0xff, 16)); } return strbuf.toString(); } public String AESencryptalgo(byte[] text) { String newtext=""; // Get the KeyGenerator try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); // 192 and 256 bits may not be available // Generate the secret key specs. SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); // Instantiate the cipher Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); encrypted = cipher.doFinal(text); System.out.println("encrypted string: " + asHex(encrypted)); cipher.init(Cipher.DECRYPT_MODE, skeySpec); original = cipher.doFinal(encrypted); originalString = new String(original); System.out.println("Original string: " + originalString + " " + asHex(original)); } catch(Exception e) { } finally { newtext=new String(encrypted); System.out.println("ENCRYPTED "+newtext); //AESdecryptalgo(newtext.getBytes()); return newtext; } } public String AESdecryptalgo(byte[] text) { // Get the KeyGenerator try { KeyGenerator kgen = KeyGenerator.getInstance("AES"); kgen.init(128); // 192 and 256 bits may not be available // Generate the secret key specs. SecretKey skey = kgen.generateKey(); byte[] raw = skey.getEncoded(); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); // Instantiate the cipher Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, skeySpec); original = cipher.doFinal(text); //Exception occurs here originalString = new String(original); System.out.println("Original string: " + originalString + " " + asHex(original)); } catch(Exception e) { System.out.println("exception"); } finally { System.out.println("DECRYPTED "+originalString); return originalString; } } public static void main(String[] args) { AES a=new AES(); a.AESencryptalgo("hello".getBytes()); System.out.println(); }} ` 

例外:

 javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) 

根据Java™加密体系结构(JCA)参考指南 (强调我的):

通过使用Cipher getInstance()静态工厂方法之一获得Cipher对象。 这里,算法名称与其他引擎类略有不同,因为它不仅指定算法名称,还指定“转换”。 转换是一个字符串,它描述要对给定输入执行以产生一些输出的操作(或操作集)。 转换总是包括加密算法的名称(例如, DES ),并且可以跟随模式和填充方案。

转型的forms如下:

  • 算法/模式/填充 ”或
  • 算法

例如,以下是有效的转换:

  • "DES/CBC/PKCS5Padding"
  • "DES"

如果只指定了转换名称,系统将确定环境中是否存在所请求转换的实现,如果有多个,则返回优先级。

如果同时指定了转换名称和包提供程序,系统将确定所请求的包中是否存在请求的转换的实现,如果没有则抛出exception。

如果未指定模式或填充,则使用模式和填充方案的特定于提供程序的默认值。 例如, SunJCE提供程序使用ECB作为默认模式, PKCS5Padding作为DESDES-EDEBlowfish密码的默认填充方案。 这意味着在SunJCE提供商的情况下:

 Cipher c1 = Cipher.getInstance("DES/ECB/PKCS5Padding"); 

 Cipher c1 = Cipher.getInstance("DES"); 

是等同的陈述。

使用CFB和OFB等模式,分组密码可以以小于密码实际块大小的单位加密数据。 请求此类模式时,您可以选择通过将此数字附加到模式名称来指定一次要处理的位数,如“ DES / CFB8 / NoPadding ”和“ DES / OFB32 / PKCS5Padding ”转换中所示。 如果未指定此类数字,则使用特定于提供程序的默认值。 (例如, SunJCE提供程序对DES使用默认的64位。)因此,可以使用8位模式(如CFB8或OFB8)将块密码转换为面向字节的流密码。

本文档的附录A包含标准名称列表,可用于指定转换的算法名称,模式和填充方案组件。

工厂方法返回的对象未初始化,必须在它们可用之前初始化。

由于您的代码未指定模式或填充,因此正在使用特定于提供程序的默认值。 您的提供程序似乎是SunJCE ,它的默认填充可能是"NoPadding" 。 使用此填充,您负责确保加密的字节数组的大小是密钥中字节数的倍数。 通过在转换中指定模式和填充,可以使您的生活更轻松:

 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 

警告:您不应在实际代码中使用ECB模式。 试试CBC吧。

更新:我认为推荐CBC模式并不公平,如果没有提供一些如何工作的样本:

 public static void main(String... args) throws Exception { byte[] data = "hello".getBytes(); KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(128); // 192 and 256 bits may not be available SecretKey secretKey = keyGenerator.generateKey(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // By initializing the cipher in CBC mode, an "initialization vector" has been randomly // generated. This initialization vector will be necessary to decrypt the encrypted data. // It is safe to store the initialization vector in plain text for later use. You can obtain // it's bytes by calling iv.getIV(). cipher.init(Cipher.ENCRYPT_MODE, secretKey); IvParameterSpec iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class); byte[] encryptedData = cipher.doFinal(data); // When decrypting the encrypted data, you must provide the initialization vector used // during the encryption phase. cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); byte[] decryptedData = cipher.doFinal(encryptedData); if (!Arrays.equals(data, decryptedData)) { throw new Exception("Data was not decrypted successfully"); } } 

好吧,如果这是错误,当使用填充密码解密时,输入长度必须是16的倍数。 对于answear来说很明显,缓冲区的长度必须是16的倍数。你检查了buf []的长度吗?

你的代码几乎可以解决所有问题。 首先,您的错误包括:

  1. 在加密和解密之前生成新的随机对称密钥。 您必须使用相同的密钥来解密用于加密的密钥。
  2. 使用String作为二进制数据的容器。 除非使用编码(例如base64),否则密码输出无法可靠地生成字符串。
  3. 您的exception处理不正确。

此外,您的代码对我来说没有例外。