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
作为DES
,DES-EDE
和Blowfish
密码的默认填充方案。 这意味着在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 []的长度吗?
你的代码几乎可以解决所有问题。 首先,您的错误包括:
- 在加密和解密之前生成新的随机对称密钥。 您必须使用相同的密钥来解密用于加密的密钥。
- 使用String作为二进制数据的容器。 除非使用编码(例如base64),否则密码输出无法可靠地生成字符串。
- 您的exception处理不正确。
此外,您的代码对我来说没有例外。