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