工作的時候遇到程序需要進行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"