最近在调试遇到了一个 RSA 加密的问题,服务端把 public key 发送给客户端,客户端使用 public key 数据进行加密,再把加密后的数据发送给服务端,但是当我把加密后的数据发送给服务端的时候,服务端发生了一个异常:
javax.crypto.BadPaddingException: Blocktype mismatch: 0
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:311)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:255)
at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
有很多人遇到了这个问题,但是各种尝试之后都不能解决我的问题,最后搜索到了一个回答
https://stackoverflow.com/questions/6069369/rsa-encryption-difference-between-java-and-android/7760365#7760365
大概是说 Android 和 Java 的某些虚拟机机制不同导致的。我修改了代码的 Cipher 之后果然就可以了。
下面再对 RSA 加密做一个总结。RSA 加密算法是一种非对称加密算法,加密端使用 public key 对数据进行加密,解密端使用 private key 对数据进行解密。
下面写一个例子大概解释一下整个加密解密过程
/** 生成公钥和秘钥 */
public static void initKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String pubKey = BaseEncoding.base64().encode(publicKey.getEncoded());
String priKey = BaseEncoding.base64().encode(privateKey.getEncoded());
System.out.println("pubKey:\t" + pubKey);
System.out.println("priKey:\t" + priKey);
}
/**
* 加密
*
* @param data 加密之前的数据
* @param pubKey 公钥
* @return 加密之后的数据
*/
public static String encrypt(String data, String pubKey)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
UnsupportedEncodingException {
// base64编码的公钥
byte[] decoded = BaseEncoding.base64().decode(pubKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(decoded));
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return BaseEncoding.base64().encode(cipher.doFinal(data.getBytes("UTF-8")));
}
/**
* 解密
*
* @param data 解密之前的数据
* @param priKey 秘钥
* @return 解密之后的数据
*/
public static String decrypt(String data, String priKey)
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(BaseEncoding.base64().decode(priKey));
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(BaseEncoding.base64().decode(data)));
}
public class RSAStudy {
// 通过 RSAUtils.initKey() 生成公钥和秘钥
static String pubKey =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAneAdKVzFegZYj2/l5iG95E93EH9R/1KcZt3Gx2hGnIw7qEhL/DK7xOd5r2eOAThUlTmXPpbWF6xed+IZMgptG0Z+tY6/CslWOsbpJ/8ChaA6KBwFLjN0gkQf2XhCgluJoi6txBhCBFaWmgoN84cEG9TtNtqrrq//lgU+T7fptIuzbI39sFQwlYv8WbfXf1aikAkiWid0tI4tf4oXNDdUQrhdWbiMtsRN9vSIJY9d1uYlIiJXIvOXyt38+rUZXSDfxqa4d8LVs0QLNDpdQzC5NnHAnFiu+N0J2Qz4RKU6vipaeKx8TjpSxhp/EG6CrcwBp8Pb2JckOqBtF9u+5xn3gQIDAQAB";
static String priKey =
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCd4B0pXMV6BliPb+XmIb3kT3cQf1H/Upxm3cbHaEacjDuoSEv8MrvE53mvZ44BOFSVOZc+ltYXrF534hkyCm0bRn61jr8KyVY6xukn/wKFoDooHAUuM3SCRB/ZeEKCW4miLq3EGEIEVpaaCg3zhwQb1O022quur/+WBT5Pt+m0i7Nsjf2wVDCVi/xZt9d/VqKQCSJaJ3S0ji1/ihc0N1RCuF1ZuIy2xE329Iglj13W5iUiIlci85fK3fz6tRldIN/Gprh3wtWzRAs0Ol1DMLk2ccCcWK743QnZDPhEpTq+Klp4rHxOOlLGGn8QboKtzAGnw9vYlyQ6oG0X277nGfeBAgMBAAECggEAIvfk/ahixShqrTqnvVVz7gH76VeKHfd6VP6CbOCX40zcWeXJjs7d8DslJMjXF0YW1gavjVlzikLPmdYmpoLQr93pauV3QzhdNR+hvQ4qzNY0i3XJX/ZdtAzK0Sxl7uG/loCoVGrbFILpUK0xceNR8agz8pZ0uHibL+txZc7ioO6Gz/A3s2y8EuSIaR1slWvmXp/udYPZH7e0koiRtAEi3v9l26DTAeqpVCRaLy64OvL31eJmAsQeKGrcPRu1e2Fvjh4FuqE9WCHnGpCQ93JepchreeP5XiaGVqdnZF/PBe38osdn/QFutDmR2qyJhZZCWXPNqbn52Iky6JnOpqC1wQKBgQDjVliZXVOdmBKNEKwhQS890Ce9wZnHAq4SKyyEqUxwAs8Xrbq9rVTIO/VbSVGOOFGV003BLG8Dw+c6XX5t0TGH0/b1G037mKJWvpYiUMcv7U5/73PRYBaCWqWnQ+kbQ27peHuKyIZ4s1CmfMIZPvdXhf4SJJSsPOmtq4Q4+XggBQKBgQCxx8gyqxpCuAyrf/ddlz2wU7KamzGAxEXA/sbjhAZaQ/Zy1iD2kCSegxjh4ahFQWhHwy/MrwU7anteg62PRmYV/5Fusr+gun66qLhp7aCF048pNuKxHghoXROd0/RJI7wsER7n/eHr5Dmwt0FlF6TEYQL20tfeTfAb34aWo6TeTQKBgCK/UuF2G06uLL+0+apHjVH0W+6sBbYeWb7bLH3GZrGELGUhH7bYJGpKh9EBHt8PCqFM38iT4w//RHtuSOG+JMTvCAMkvkGjbcS2croiAJ/5tJLnZZtuBWK9Oi6buah6IRy8Vp260prmRYB89ynmruWIzHG3d6Xv1YO/AIG417yFAoGAR0D2eXBgnxsbYOVyJJ3IiNKTBCpthdmkx3yWBHxW+3i/3zj5jzkopCuRHn+OLOvROun9T4FajHzaI4CNYJ5rrid3h7G24lm9D10uRK6MJvcrKu6nnyuVXRbpFNnt0B61fcgC5iK4mQ4pHS3l1PnL/TWQtZK+GIiOUu2dCOVf4AUCgYBCIjtK9lJPMVT75I5JC2cacgOx4gMFL7VLHw4TzoX7VODKsNinnwEEAODPQzYfXNJ3TYTxOIUOzQ/TKcct6maxu+V0RfJ3kvoY44LNepucoVCFBq+nI5BBaBC7INJEzCNkjPB8vyx+//YoYVj3a93LCOOuyLAG9PERsuPKMkvjmg==";
public static void main(String[] args) {
try {
String newData = "hello world";
String nnewData = RSAUtils.encrypt(newData, pubKey);
System.out.println(nnewData);
String nnnewData = RSAUtils.decrypt(nnewData, priKey);
System.out.println(nnnewData);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
}
l506aM/ruBQOIKZhLTodreceKiQqn1JDIjWt1gk7St7+vLavdnfq/kTspKwc3jhWU4BC0aytz1Vrq6BIJD71dAqVDcyhhzSSwJuwR//0HTGWR5Njl+ey1aSp0sp4yICbqCxp75lkxoRlXagHsKjpSPhAgD0K+eSg+Ujg48p6+cGNncLCiVAHCt6E4rRJPjRn0fKzmPiNsjriNg5qVTxBfbuEbpPjb9v5Km1Hh1us9/M6g2zeCGIe5lvK0Td/CpXKwemhU8ayeBasHUkcB+SE05ieU3T6fRjGJ0/9Oeun1a4PNtBue5ckic2HsVv3XDpQb6eCV21LsOjfBK/I7pMhiQ==
hello world
全部代码: https://github.com/brainweiyi/java-study