java rsa 解密報:javax.crypto.BadPaddingException: Decryption error
阿新 • • 發佈:2019-01-31
Exception in thread "main" 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:356)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2223)
at com.asymmetric.rsa.TestRSA.testDecrypt(TestRSA.java:115)
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:356)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2223)
at com.asymmetric.rsa.TestRSA.testDecrypt(TestRSA.java:115)
at com.asymmetric.rsa.TestRSA.main(TestRSA.java:34)
簡單解釋:
字面意思就是解密的時候填充錯誤,rsa 加解密都是把資料必須滿足一定的長度,如果 不滿足就要進行填充(一般是補0)直到滿足特定的長度
測試程式碼
package com.asymmetric.rsa; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class TestRSA { public static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQgEoj3z9JrdPNI23DbMQkl3gkGuDke7iBr5yrYyqolkTyxuBLWFwHNuGv4VKOj9fXg61QxpaJ/fxDBvMvmkBSRowHBloGFceVTx8wV/8u0DcjvTCu0IZ1zp6wjG6xBn5j66Sg/q+9hvaY2p7fkKmsvcW6VoNPgQHU1Cf01DLZmQIDAQAB+oXcINOiE3AsuZ4VJmwNZg9Y/7fY+OFRS2JAh5YMsrv2qyoGP+Z9ksre26NYR+Lt91B2lhdwJHLpQpziaANZm/ONb31fj/lwIDAQAB"; public static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANCASiPfP0mt080jbcNsxCSXeCQa4OR7uIGvnKtjKqiWRPLG4EtYXAc24a/hUo6P19eDrVDGlon9/EMG8y+aQFJGjAcGWgYVx5VPHzBX/y7QNyO9MK7QhnXOnrCMbrEGfmPrpKD+r72G9pjant+Qqay9xbpWg0+BAdTUJ/TUMtmZAgMBAAECgYBSozY/Z4FW+31h5fPgK+DFu/8TGFAgXuTvCaJnz2Md9IkZTDejxT6cYWUr53toI5zhvz/XLw6FXNQ54KxMJq/s9PiZYUgq/PMrnyU4gBSTm5BmiWjdaGicVEZ1lofHjpkAchPNW/CzwxD8AeKI7QaObE+EkWbLAi6sa+nRdHKgrQJBAOwYLD2DncU15XCKS0RNzTrNohdBQcisOPHdtQO0CGZlxx3xjuU4WL6/EpdmbjTeYbOSDKCmY5vyVbYZdOWfEs8CQQDiFIwWpvW2WLxLVw3i2P55WmMMXuecwEzg++ae3Ht7nW0zNcWSsyvHh40sM8XqEzmWOzMY6JOePbkuVfWTc4cXAkBRzf5mQhiEoKwjVofF3v9hhKbJT/8vPR1uENgLtHHEqTdZFL3ihqeZUDNs6jz9bKCFy/E8KOsSueEg+6kZdwjZAkEAj2RW4fstd2VasDJb5ViaNqAEmJENOBej60L6KCJR07qqy0M8t+oaR2iLOtDvo6Jj8QxFQXQqRMCDVodAxjANKwJAL3KuaqA6kdy9RxdV3uP8nRXLY7C/1ZIK6U0pyZqKXEwpD+7Ar3hwwhPz9TeuoqjB/cCknZjw70BQFQ0/VUHW2g=="; private static String algorithm = "RSA"; //$NON-NLS-1$ private static final int MAX_ENCRYPT_BLOCK = 117; private static final int MAX_DECRYPT_BLOCK = 128; private static String data = "test jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihg"; //$NON-NLS-1$ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException { String test = testEncrypt(privateKey,data); String testDecrypt = testDecrypt(publicKey, test); System.out.println(testDecrypt); } /** * 加密 * @param key * @param data * @return * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidKeyException * @throws IOException */ public static String testEncrypt(String key,String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException{ byte[] decode = Base64.getDecoder().decode(key); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode); KeyFactory kf = KeyFactory.getInstance(algorithm); PrivateKey generatePrivate = kf.generatePrivate(pkcs8EncodedKeySpec); Cipher ci = Cipher.getInstance(algorithm); ci.init(Cipher.ENCRYPT_MODE, generatePrivate); byte[] bytes = data.getBytes(); int inputLen = bytes.length; int offLen = 0;//偏移量 int i = 0; ByteArrayOutputStream bops = new ByteArrayOutputStream(); while(inputLen - offLen > 0){ byte [] cache; if(inputLen - offLen > 117){ cache = ci.doFinal(bytes, offLen,117); }else{ cache = ci.doFinal(bytes, offLen,inputLen - offLen); } bops.write(cache); i++; offLen = 117 * i; } bops.close(); byte[] encryptedData = bops.toByteArray(); String encodeToString = Base64.getEncoder().encodeToString(encryptedData); return encodeToString; } /** * 解密 * @param key * @param data * @return * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws BadPaddingException * @throws IllegalBlockSizeException * @throws IOException */ public static String testDecrypt(String key,String data) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, IOException{ byte[] decode = Base64.getDecoder().decode(key); // PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode); //java底層 RSA公鑰只支援X509EncodedKeySpec這種格式 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode); KeyFactory kf = KeyFactory.getInstance(algorithm); PublicKey generatePublic = kf.generatePublic(x509EncodedKeySpec); Cipher ci = Cipher.getInstance(algorithm); ci.init(Cipher.DECRYPT_MODE,generatePublic); int inputLen = data.getBytes().length; byte[] bytes = data.getBytes(); int offLen = 0; int i = 0; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); while(inputLen - offLen > 0){ byte[] cache; if(inputLen - offLen > 128){ cache = ci.doFinal(bytes,offLen,128); }else{ cache = ci.doFinal(bytes,offLen,inputLen - offLen); } byteArrayOutputStream.write(cache); i++; offLen = 128 * i; } byteArrayOutputStream.close(); byte[] byteArray = byteArrayOutputStream.toByteArray(); return new String(byteArray); } }
問題點:
後來發現確實是我自己的錯誤,rsa 加密後返回的字串使用Base64編碼的,忘了解密直接getBytes()就出錯了
api 指出: - 如果此 Cipher 為解密模式,並且未請求填充(或不填充),但解密的資料沒有用適當的填充位元組進行限制
只要是cipher.doFinal()解密時報 肯定是傳入的位元組陣列有問題,傳的不是加密時生成的陣列
修正後的程式碼:
package com.asymmetric.rsa; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; public class TestRSA { public static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQgEoj3z9JrdPNI23DbMQkl3gkGuDke7iBr5yrYyqolkTyxuBLWFwHNuGv4VKOj9fXg61QxpaJ/fxDBvMvmkBSRowHBloGFceVTx8wV/8u0DcjvTCu0IZ1zp6wjG6xBn5j66Sg/q+9hvaY2p7fkKmsvcW6VoNPgQHU1Cf01DLZmQIDAQAB+oXcINOiE3AsuZ4VJmwNZg9Y/7fY+OFRS2JAh5YMsrv2qyoGP+Z9ksre26NYR+Lt91B2lhdwJHLpQpziaANZm/ONb31fj/lwIDAQAB"; public static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANCASiPfP0mt080jbcNsxCSXeCQa4OR7uIGvnKtjKqiWRPLG4EtYXAc24a/hUo6P19eDrVDGlon9/EMG8y+aQFJGjAcGWgYVx5VPHzBX/y7QNyO9MK7QhnXOnrCMbrEGfmPrpKD+r72G9pjant+Qqay9xbpWg0+BAdTUJ/TUMtmZAgMBAAECgYBSozY/Z4FW+31h5fPgK+DFu/8TGFAgXuTvCaJnz2Md9IkZTDejxT6cYWUr53toI5zhvz/XLw6FXNQ54KxMJq/s9PiZYUgq/PMrnyU4gBSTm5BmiWjdaGicVEZ1lofHjpkAchPNW/CzwxD8AeKI7QaObE+EkWbLAi6sa+nRdHKgrQJBAOwYLD2DncU15XCKS0RNzTrNohdBQcisOPHdtQO0CGZlxx3xjuU4WL6/EpdmbjTeYbOSDKCmY5vyVbYZdOWfEs8CQQDiFIwWpvW2WLxLVw3i2P55WmMMXuecwEzg++ae3Ht7nW0zNcWSsyvHh40sM8XqEzmWOzMY6JOePbkuVfWTc4cXAkBRzf5mQhiEoKwjVofF3v9hhKbJT/8vPR1uENgLtHHEqTdZFL3ihqeZUDNs6jz9bKCFy/E8KOsSueEg+6kZdwjZAkEAj2RW4fstd2VasDJb5ViaNqAEmJENOBej60L6KCJR07qqy0M8t+oaR2iLOtDvo6Jj8QxFQXQqRMCDVodAxjANKwJAL3KuaqA6kdy9RxdV3uP8nRXLY7C/1ZIK6U0pyZqKXEwpD+7Ar3hwwhPz9TeuoqjB/cCknZjw70BQFQ0/VUHW2g=="; private static String algorithm = "RSA"; //$NON-NLS-1$ private static final int MAX_ENCRYPT_BLOCK = 117; private static final int MAX_DECRYPT_BLOCK = 128; private static String data = "test jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihgtest jiojiogeiojigouihg"; //$NON-NLS-1$ public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException { String test = testEncrypt(privateKey,data); String testDecrypt = testDecrypt(publicKey, test); System.out.println(testDecrypt); } /** * 加密 * @param key * @param data * @return * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws InvalidKeyException * @throws IOException */ public static String testEncrypt(String key,String data) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, IOException{ byte[] decode = Base64.getDecoder().decode(key); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode); KeyFactory kf = KeyFactory.getInstance(algorithm); PrivateKey generatePrivate = kf.generatePrivate(pkcs8EncodedKeySpec); Cipher ci = Cipher.getInstance(algorithm); ci.init(Cipher.ENCRYPT_MODE, generatePrivate); byte[] bytes = data.getBytes(); int inputLen = bytes.length; int offLen = 0;//偏移量 int i = 0; ByteArrayOutputStream bops = new ByteArrayOutputStream(); while(inputLen - offLen > 0){ byte [] cache; if(inputLen - offLen > 117){ cache = ci.doFinal(bytes, offLen,117); }else{ cache = ci.doFinal(bytes, offLen,inputLen - offLen); } bops.write(cache); i++; offLen = 117 * i; } bops.close(); byte[] encryptedData = bops.toByteArray(); String encodeToString = Base64.getEncoder().encodeToString(encryptedData); return encodeToString; } /** * 解密 * @param key * @param data * @return * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws NoSuchPaddingException * @throws InvalidKeySpecException * @throws BadPaddingException * @throws IllegalBlockSizeException * @throws IOException */ public static String testDecrypt(String key,String data) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, IOException{ byte[] decode = Base64.getDecoder().decode(key); // PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode); //java底層 RSA公鑰只支援X509EncodedKeySpec這種格式 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(decode); KeyFactory kf = KeyFactory.getInstance(algorithm); PublicKey generatePublic = kf.generatePublic(x509EncodedKeySpec); Cipher ci = Cipher.getInstance(algorithm); ci.init(Cipher.DECRYPT_MODE,generatePublic); byte[] bytes = Base64.getDecoder().decode(data); int inputLen = bytes.length; int offLen = 0; int i = 0; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); while(inputLen - offLen > 0){ byte[] cache; if(inputLen - offLen > 128){ cache = ci.doFinal(bytes,offLen,128); }else{ cache = ci.doFinal(bytes,offLen,inputLen - offLen); } byteArrayOutputStream.write(cache); i++; offLen = 128 * i; } byteArrayOutputStream.close(); byte[] byteArray = byteArrayOutputStream.toByteArray(); return new String(byteArray); } }