RSA 加密在 Java 和 Android 上面出现的异常:javax.crypto.BadPaddingException

RSA 加密在 Java 和 Android 上面出现的异常:javax.crypto.BadPaddingException

最近在调试遇到了一个 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*..)

有很多人遇到了这个问题,但是各种尝试之后都不能解决我的问题,最后搜索到了一个回答

RSA 加密在 Java 和 Android 上面出现的异常:javax.crypto.BadPaddingException_第1张图片

https://stackoverflow.com/questions/6069369/rsa-encryption-difference-between-java-and-android/7760365#7760365

大概是说 Android 和 Java 的某些虚拟机机制不同导致的。我修改了代码的 Cipher 之后果然就可以了。

下面再对 RSA 加密做一个总结。RSA 加密算法是一种非对称加密算法,加密端使用 public key 对数据进行加密,解密端使用 private key 对数据进行解密。

下面写一个例子大概解释一下整个加密解密过程

  1. 首先生成一个公钥和秘钥供后期使用
/** 生成公钥和秘钥 */
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);
}
  1. 加密过程
/**
 * 加密
 *
 * @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")));
}
  1. 解密过程
/**
 * 解密
 *
 * @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)));
}
  1. 整个加密流程如下:
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();
    }
  }
}
  1. 从控制台可以看到加密之后的数据和解密之后的数据分别是:
  • 加密之后的数据:
l506aM/ruBQOIKZhLTodreceKiQqn1JDIjWt1gk7St7+vLavdnfq/kTspKwc3jhWU4BC0aytz1Vrq6BIJD71dAqVDcyhhzSSwJuwR//0HTGWR5Njl+ey1aSp0sp4yICbqCxp75lkxoRlXagHsKjpSPhAgD0K+eSg+Ujg48p6+cGNncLCiVAHCt6E4rRJPjRn0fKzmPiNsjriNg5qVTxBfbuEbpPjb9v5Km1Hh1us9/M6g2zeCGIe5lvK0Td/CpXKwemhU8ayeBasHUkcB+SE05ieU3T6fRjGJ0/9Oeun1a4PNtBue5ckic2HsVv3XDpQb6eCV21LsOjfBK/I7pMhiQ==
  • 解密之后的数据:
hello world
  1. 总结:RSA 加密是在开发总常用的加密,尤其是前后端数据交互的时候,在开发的过程中我们要对流程有一个熟悉的了解。

全部代码: https://github.com/brainweiyi/java-study

你可能感兴趣的:(Java,Android,Java,RSA,加密,异常)