工作的时候遇到程序需要进行RSA加密解密的部分,在写第一版测试的时候,出现了:
Exception in thread "main" javax.crypto.BadPaddingException: Data must start with zero at sun.security.rsa.RSAPadding.unpadV15(Unknown Source) at sun.security.rsa.RSAPadding.unpad(Unknown Source) at com.sun.crypto.provider.RSACipher.a(DashoA13*..) at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) at com.pack.RSAUtils.decryptByPrivateKey(RSAUtils.java:164) at com.pack.RSATest.test(RSATest.java:47) at com.pack.RSATest.main(RSATest.java:26)
这样一个错误,代码:
package com.pack; import java.io.File; import java.util.Map; public class RSATest { static String publicKey; static String privateKey; static { try { Map<String, Object> keyMap = RSAUtils.genKeyPair(); publicKey = RSAUtils.getPublicKey(keyMap); privateKey = RSAUtils.getPrivateKey(keyMap); System.err.println("公钥: \n\r" + publicKey); System.err.println("私钥: \n\r" + privateKey); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) throws Exception { test(); }
static void test() throws Exception { System.err.println("公钥加密——私钥解密"); String source = "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\""; System.out.println("\r加密前文字:\r\n" + source); byte[] data = source.getBytes(); byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey); System.out.println("加密后文字:\r\n" + new String(encodedData)); String str = new String(encodedData); byte[] decodedData = RSAUtils.decryptByPrivateKey(str.getBytes(), privateKey); String target = new String(decodedData); System.out.println("解密后文字: \r\n" + target); }
}
但是如果我把加密后的byte数组直接解密,就没有问题,到网上找了很多,但是没有说的特别明白的帖子,后来在http://www.myexception.cn/java-other/BadPaddingException.html这里 看到了一个还算说的明白的帖子,其实就是因为把byte[]数组转化成字符串,写入到文件,但是从字符串转化成byte[]数组的时候,程序无法找到每一个byte[]里元素的临界点在哪里,所以知道了这一点,要解决这个问题也就简单了,就是在加密之后的byte[]元素之间加上一个标志符,可以使空格,也可以是0,.然后在解密的时候要进行字符串的拆分,组装成byte[]数组,然后再进行解密。就可以搞定了。
所有就有了下面的方法:
package com.pack; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Map; /** * RSA对文件或字符串进行加密解密功�? * @author 胡松振 * */ public class RSAUtil { // 把byte[]元素之间添加空格,并转化成字符串返回, public String byteToString(byte[] resouce){ StringBuffer sb = new StringBuffer(); for (int i = 0; i < resouce.length; i++) { if (i == resouce.length-1) { sb.append(Byte.toString(resouce[i])); }else{ sb.append(Byte.toString(resouce[i])); sb.append(" "); } } return sb.toString(); } // 把字符串按照空格进行拆分成数组,然后转化成byte[],返回 public byte[] stringToByte(String resouce){ String[] strArr = resouce.split(" "); int len = strArr.length; byte[] clone = new byte[len]; for (int i = 0; i < len; i++) { clone[i] = Byte.parseByte(strArr[i]); } return clone; } }
那下面就是见证奇迹的时刻了:static void test() throws Exception { RSAUtil ru = new RSAUtil(); System.err.println("公钥加密——私钥解密"); String source = "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\""; System.out.println("\r加密前文字:\r\n" + source); byte[] data = source.getBytes(); byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey); System.out.println("加密后文字:\r\n" + new String(encodedData)); String str = ru.byteToString(encodedData); byte[] resource = ru.stringToByte(str); byte[] decodedData = RSAUtils.decryptByPrivateKey(resource, privateKey); String target = new String(decodedData); System.out.println("解密后文字: \r\n" + target); }
下面的结果就正确了:
加密前文字: <manifest xmlns:android="http://schemas.android.com/apk/res/android" 加密后文字: 殞獒郵L崭'34?︱}库珃??\茕y?曘肭蚐?堏?'d/B眅@XJ佗D=w?桠嫟O褫?鄾埔4 ?w?8I嵀鶮)0+镔霉暺`趕Y緤u侼桝?两?1鏷 解密后文字: <manifest xmlns:android="http://schemas.android.com/apk/res/android"