RSA解密时BadPaddingException

paravoice 2008-07-22 01:08:02
public class RSATest2 {

public static void main(String[] args) {
try {
RSATest2 encrypt = new RSATest2();

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
// 私钥,其实私钥是指定好的,与公钥是一对,我这里随便取一个暂时用用。
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// 公钥不用,只用上面的私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

// 假设这是加密后的字符串,我要把它解密
String encryptedStr = "sdfds23fd23";
/*
* 为什么会出现javax.crypto.BadPaddingException: Data must start with zero
* 看了Cipher的文档也不懂是什么意思,“如果此 cipher
* 为解密模式,并且未请求填充或不填充,但解密的数据没有用适当的填充字节所限制” 需要怎么做?
*/
byte[] de = encrypt.decrypt(privateKey, encryptedStr.getBytes());
System.out.println(de.toString());
} catch (Exception e) {
e.printStackTrace();
}
}

protected byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) {
if (privateKey != null) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(obj);
} catch (Exception e) {
e.printStackTrace();
}
}

return null;
}
}

先说说正确的情况,先用Cipher.getInstance("RSA");初始化为加密模式,把一个指定的串加密后返回一个byte数组;如果把这个byte数组传给解密的doFinal方法,解密成功。
但是传给解密doFinal方法的参数是普通的一个字符串产生的byte数组,那么就会抛出
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(DashoA6275)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA6275)
at javax.crypto.Cipher.doFinal(DashoA12275)
at RSATest2.decrypt(RSATest2.java:41)
at RSATest2.main(RSATest2.java:29)
java.lang.NullPointerException
at RSATest2.main(RSATest2.java:30)
为什么呢?
在文档中找到了如下描述,可是可以帮我理解一下么,谢谢。
BadPaddingException - 如果此 cipher 为解密模式,并且未请求填充或不填充,但解密的数据没有用适当的填充字节所限制
...全文
8564 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
myicezone 2010-03-05
  • 打赏
  • 举报
回复
正在做这个东西呢,我也遇到了同样的问题,真是学习到了
paravoice 2008-07-23
  • 打赏
  • 举报
回复
自己连发三贴就不让发了啊
还得弄个马甲结贴。虽然还有一点不明白,不过算了,自己想想吧,结贴。
majiaNotExist 2008-07-23
  • 打赏
  • 举报
回复
终于搞定了,基本功太差,得好好补补了。
加密后产生的byte数组转成string时要在各byte之间加个标识符,我加了个空格,
然后再根据空格分隔转换回byte数组。如果不加标识符,由于byte值可能是一位到三位,无法知道某一个byte是在哪里结束。当然也可以在转成string时补0。或者转成16进制固定为两位长。


code:
public class RSATest {

public static void main(String[] args) {
try {
RSATest encrypt = new RSATest();

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

String str = "Hello World!";
System.out.println("String will be encrypted: " + str);
byte[] e = encrypt.encrypt(publicKey, str.getBytes());
String tmp1 = encrypt.bytesToString(e);
System.out
.println("encrypted String's bytes, use
bytesToString() method convert bytes to string: " + tmp1);
String[] strArr = tmp1.split(" ");
int len = strArr.length;
byte[] clone = new byte[len];
for (int i = 0; i < len; i++) {
clone[i] = Byte.parseByte(strArr[i]);
}
System.out.println("convert to String, then back to bytes
again: " + encrypt.bytesToString(clone));
byte[] d = encrypt.decrypt(privateKey, clone);
System.out.println("decrypted String's bytes, use
bytesToString() method convert bytes to string:"
+ encrypt.bytesToString(d));
System.out.println("construct a string by decrypted
string's bytes: " + new String(d));
} catch (Exception e) {
e.printStackTrace();
}
}

protected String bytesToString(byte[] encrytpByte) {
String result = "";
for (Byte bytes : encrytpByte) {
result += bytes.toString() + " ";
}
return result;
}

protected byte[] encrypt(RSAPublicKey publicKey, byte[] obj) {
if (publicKey != null) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

protected byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) {
if (privateKey != null) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}

运行结果:
String will be encrypted: Hello World!
encrypted String's bytes, use bytesToString() method convert bytes to
string: 79 62 -105 -47 -61 45 64 -11 -8 -120 30 31 37 -111 49 -30 88
-12 93 -77 3 39 -13 -18 68 -104 0 30 85 26 104 15 -126 -39 12 110 -84
68 -43 73 35 121 -20 -69 -84 85 -33 -123 -48 -68 -85 -106 41 -84 20
-17 87 -81 42 -67 -87 122 -2 37 74 27 103 112 58 -125 -87 -32 96 -56
65 -2 -103 -28 70 107 2 28 87 75 -8 -62 54 12 -7 -108 -123 120 -63 -83
13 -89 -21 58 -51 -84 66 25 103 -114 -14 110 80 58 74 95 -57 -73 -78
-46 56 -83 -72 -38 2 43 25 12 56 12 101 15 91 -37
convert to String, then back to bytes again: 79 62 -105 -47 -61 45 64
-11 -8 -120 30 31 37 -111 49 -30 88 -12 93 -77 3 39 -13 -18 68 -104 0
30 85 26 104 15 -126 -39 12 110 -84 68 -43 73 35 121 -20 -69 -84 85
-33 -123 -48 -68 -85 -106 41 -84 20 -17 87 -81 42 -67 -87 122 -2 37 74
27 103 112 58 -125 -87 -32 96 -56 65 -2 -103 -28 70 107 2 28 87 75 -8
-62 54 12 -7 -108 -123 120 -63 -83 13 -89 -21 58 -51 -84 66 25 103
-114 -14 110 80 58 74 95 -57 -73 -78 -46 56 -83 -72 -38 2 43 25 12 56
12 101 15 91 -37
decrypted String's bytes, use bytesToString() method convert bytes to
string:72 101 108 108 111 32 87 111 114 108 100 33
construct a string by decrypted string's bytes: Hello World!
paravoice 2008-07-22
  • 打赏
  • 举报
回复
丢人了~~
横杠是byte型为负值时的负号
汗~,大家都鄙视我吧,就是不告诉我...
paravoice 2008-07-22
  • 打赏
  • 举报
回复
自己的贴子都不让修改么?补充一下:

code:
public static void main(String[] args) {
try {
RSATest encrypt = new RSATest();

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

String str = "Hello World!";
System.out.println("String will be encrypted: " + str);
byte[] e = encrypt.encrypt(publicKey, str.getBytes());
System.out.println("encrypted String's bytes, use bytesToString() method convert bytes to string: " + encrypt.bytesToString(e));
String tmp1 = encrypt.bytesToString(e);
System.out.println("convert to String, then back to bytes again: " + encrypt.bytesToString(tmp1.getBytes()));
byte[] d = encrypt.decrypt(privateKey, e);
System.out.println("decrypted String's bytes, use bytesToString() method convert bytes to string:" + encrypt.bytesToString(d));
System.out.println("construct a string by decrypted string's bytes: " + new String(d));
} catch (Exception e) {
e.printStackTrace();
}
}


运行结果:
String will be encrypted: Hello World!
encrypted String's bytes, use bytesToString() method convert bytes to string: 10510629-39-7712059-1184078-1878273541-167989-86-985043-97359-24-7-6699-10111410831-41-109912069-62-941139794-48-108-102-23-90-30-12244-110-99-52-10865120-6935-11718-85-46-64-13-1648104-5891-10153101-12334127-113101134138038-1216656-53-76-3830-53-47-239711-17-83102-59-54-17120-127-128-5-42-37-1072-34672-84-2342124100-3138-6196412131-125-110-3
convert to String, then back to bytes again: 4948534948545057455157455555495048535745494956524855564549565556505551535249454954555756574556544557565348525145575551535745505245554554545757454948494949524948565149455249454948575749504854574554504557524949515755575245525645494856454948504550514557484551484549505052524549494845575745535045494856545349504845545751534549495549564556534552544554524549514549545256494852455356574945494849535149484945495051515249505545494951494849495152495156485156454950495454535445535145555445515651484553514552554550515755494945495545565149485045535745535245495549504845495055454950564553455250455155454948555045515254555045565245505152504950524948484551495156455449575452495049514945495053454949484551
decrypted String's bytes, use bytesToString() method convert bytes to string:72101108108111328711111410810033
construct a string by decrypted string's bytes: Hello World!
接7楼,
把密文转成String,然后再转回bytes,发现横杠消失了,打印出来的面目全非,发生什么事了???
paravoice 2008-07-22
  • 打赏
  • 举报
回复
分析一下正常的情况:
code:
public class RSATest {

public static void main(String[] args) {
try {
RSATest encrypt = new RSATest();

KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

String str = "Hello World!";
System.out.println("String will be encrypted: " + str);
byte[] e = encrypt.encrypt(publicKey, str.getBytes());
System.out.println("encrypted String's bytes, use bytesToString() method convert bytes to string: " + encrypt.bytesToString(e));
byte[] d = encrypt.decrypt(privateKey, e);
System.out.println("decrypted String's bytes, use bytesToString() method convert bytes to string:" + encrypt.bytesToString(d));
System.out.println("construct a string by decrypted string's bytes: " + new String(d));
} catch (Exception e) {
e.printStackTrace();
}
}

private String bytesToString(byte[] obj) {
String ret = "";
for (byte b : obj) {
ret += String.valueOf(b);
}
return ret;
}

protected byte[] decrypt(RSAPrivateKey privateKey, byte[] obj) {
if (privateKey != null) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(obj);
} catch (Exception e) {
e.printStackTrace();
}
}

return null;
}

protected byte[] encrypt(RSAPublicKey publicKey, byte[] obj) {
if (publicKey != null) {
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(obj);
} catch (Exception e) {
e.printStackTrace();
}
}

return null;
}
}


运行结果:
String will be encrypted: Hello World!
encrypted String's bytes, use bytesToString() method convert bytes to string: -906583-670-417229118102-121-6912181-16-19-59-1189551079-15845-10110-96-1-2950108-110-52-30-4-63113-1712910181-110-126-696-116-14612054-84-93191266412-675740-34109-42127-3-215810-54-7273-112-16117113-111-116464-109-23-5-399660216-126-6012891051022445-4262120-104-126-6242-84-2855-3155-6780125123-74-125-111-5487-11873-98-10729-741121989-429
decrypted String's bytes, use bytesToString() method convert bytes to string:72101108108111328711111410810033
construct a string by decrypted string's bytes: Hello World!
可以看出解密结果与原文一致(废话)
关键是加密后的密文有一些横杠,而解密后的,也就是普通的字符串转成bytes,然后用bytesToString打印出来没有横杠。

想到RSA加密时是要分组的,把各个分组加密后串在一起,难道横杠是分组的标记?
谁来解说一下。
上山老人 2008-07-22
  • 打赏
  • 举报
回复
帮顶
paravoice 2008-07-22
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 storm1979 的回复:]
那个当然,你的给普通字符串的byte数组都不符合加密后的排列要求,当然会出错。

[/Quote]

非常感谢回复。
1 怎样才能让普通字符串产生的byte数组成功的按RSA解密呢?

2 其实我原来的问题是在于服务器把密文传给客户端由客户端解密,而传递的过程不能传递byte数组,
只能转成String传,客户端把接到的String转回byte数组后出现了上述问题。
请问,是不是转换过程中破坏了加密后的排列要求?怎样才能避免?
storm_huang 2008-07-22
  • 打赏
  • 举报
回复
那个当然,你的给普通字符串的byte数组都不符合加密后的排列要求,当然会出错。
paravoice 2008-07-22
  • 打赏
  • 举报
回复
今天才发现注册两年多了,这还是第一贴
希望哪位专家有空看下。
  • 打赏
  • 举报
回复
没用过,友情帮你顶

50,879

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧