RSA加密遇到的坑

焦世春發表於2019-03-09

讀取私鑰時報錯

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
	at sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:217)
	at java.security.KeyFactory.generatePrivate(KeyFactory.java:372)
複製程式碼

在獲取私鑰時需增加以下程式碼

  if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
      Security.addProvider(new BouncyCastleProvider());
    }
   //需要導包     
  api 'org.bouncycastle:bcprov-jdk16:1.46'
複製程式碼

載入的字串大於117時會報錯

需要分段加密 公鑰加密時,加密的最長位元組時117個 私鑰解密出來長度都是128 注意:必須在每段加密完成後再用Base64加密,否則Base64解密時會出錯

獲取私鑰時報

IllegalArgumentException: Illegal base64 character d
複製程式碼

祕鑰裡面有換行或其他符號,去掉即可

解密時報BadPaddingException

javax.crypto.BadPaddingException: Decryption error
	at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
	at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
	at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363)
	at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
	at javax.crypto.Cipher.doFinal(Cipher.java:2223)
	
複製程式碼

加密和解密的填充模式不一致導致的
統一對齊方式:"RSA/NONE/PKCS1Padding"

RSA加密完整程式碼

  // 返回 RSA 加密的結果
  public static String encryptRSA(Key publicKey, String text) {
    try {
      Cipher rsa = Cipher.getInstance("RSA/NONE/PKCS1Padding");
      rsa.init(Cipher.ENCRYPT_MODE, publicKey);
      byte[] originBytes = text.getBytes();
      //大於117時進行分段 加密
      int subLength = originBytes.length / 117 + (originBytes.length % 117 == 0 ? 0 : 1);
      byte[] finalByte = new byte[128 * subLength];
      for (int i = 0; i < subLength; i++) {
        //需要加密的位元組長度
        int len = i == subLength - 1 ? (originBytes.length - i * 117) : 117;
        //加密完成的位元組陣列
        byte[] doFinal = rsa.doFinal(originBytes, i * 117, len);
        //複製這次加密的陣列
        System.arraycopy(doFinal, 0, finalByte, i * 128, doFinal.length);
      }
      return new String(Base64Utlis.encode(finalByte, Base64Utlis.NO_WRAP),
          Charset.forName("UTF-8"));
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
   * 返回 RSA 解密的結果
   */
  public static String decryptRSA(Key privateKey, String content) {
    try {
      byte[] text = Base64Utlis.decode(content, Base64Utlis.NO_WRAP);
      Cipher rsa = Cipher.getInstance("RSA/NONE/PKCS1Padding");
      rsa.init(Cipher.DECRYPT_MODE, privateKey);
      //大於128時進行分段 解密
      int subLength = text.length / 128;
      StringBuilder finalString = new StringBuilder();
      for (int i = 0; i < subLength; i++) {
        byte[] doFinal = rsa.doFinal(text, i * 128, 128);
        finalString.append(new String(doFinal, Charset.forName("UTF-8")));
      }
      return finalString.toString();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }


  //根據檔案路徑返回公匙
  public static PublicKey readPublicKey(String filePath) throws IOException {
    FileInputStream fis = new FileInputStream(new File(filePath));
    return readPublicKey(fis);
  }

  // 根據輸入流返回公匙
  public static PublicKey readPublicKey(InputStream input) throws IOException {
    final ByteArrayOutputStream output = new ByteArrayOutputStream();
    int n = 0;
    final byte[] buffer = new byte[1024 * 4];
    while (-1 != (n = input.read(buffer))) {
      output.write(buffer, 0, n);
    }
    byte[] keyBytes = output.toByteArray();
    X509EncodedKeySpec spec =
        new X509EncodedKeySpec(Base64Utlis.decode(keyBytes, Base64Utlis.NO_WRAP));
    try {
      KeyFactory kf = KeyFactory.getInstance("RSA");
      return kf.generatePublic(spec);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
      e.printStackTrace();
    }
    return null;
  }

  // 根據檔案路徑返回私匙
  public static PrivateKey readPrivateKey(String filePath) throws IOException {
    FileInputStream fis = new FileInputStream(new File(filePath));
    return readPrivateKey(fis);
  }

  // 根據輸入流返回私匙
  public static PrivateKey readPrivateKey(InputStream input) throws IOException {
    final ByteArrayOutputStream output = new ByteArrayOutputStream();
    int n = 0;
    final byte[] buffer = new byte[1024 * 4];
    while (-1 != (n = input.read(buffer))) {
      output.write(buffer, 0, n);
    }
    if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
      Security.addProvider(new BouncyCastleProvider());
    }
    byte[] keyBytes = output.toByteArray();
    PKCS8EncodedKeySpec spec =
        new PKCS8EncodedKeySpec(Base64Utlis.decode(keyBytes, Base64Utlis.NO_WRAP));
    try {
      KeyFactory kf = KeyFactory.getInstance("RSA");
      return kf.generatePrivate(spec);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
      e.printStackTrace();
    }
    return null;
  }
複製程式碼

相關文章