1

I get a BadPaddingException when trying to decrypt some encrypted data. The byte array is 128 bytes when the data is encrypted (before converting to base64) and it's also 128 bytes when converting the encrypted data from base64, so this part seems correct.

fun encryptWithRSA(dataToEncrypt: String): String { val modulus = BigInteger("F70F9BC271DD6ED93EE9...F29901", 16) val pubExp = BigInteger("010001", 16) val keyFactory = KeyFactory.getInstance("RSA") val pubKeySpec = RSAPublicKeySpec(modulus, pubExp) val key: RSAPublicKey = keyFactory.generatePublic(pubKeySpec) as RSAPublicKey val cipher = Cipher.getInstance("RSA/ECB/NoPadding") cipher.init(Cipher.ENCRYPT_MODE, key) val encryptedBytes = cipher.doFinal(dataToEncrypt.toByteArray()) val encryptedData = Base64.getEncoder().encodeToString(encryptedBytes) return encryptedData } fun decryptWithRSA(dataToDecrypt: String): String { val PRIVATE_RSA_KEY_PKCS8 = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPcPm8Jx3W7ZPulQ\n" + "..." + "g4Ba8WBhgQ7D/tCAww4l8VhyGJm5/88O+xq2Kr69RIHcWTvhck76n08CQQDSPVB6\n" + "+MhX/txtOjY8Y+FOFXOeb0EIMhaMQR02+3+wIbN/IMJUyz2Eq/mDX8oX8BwMGlah\n" + "WSWouLwHaZFcDn7Q" val keySpec = PKCS8EncodedKeySpec(parseBase64Binary(PRIVATE_RSA_KEY_PKCS8)) val keyFactory = KeyFactory.getInstance("RSA") val privateKey = keyFactory.generatePrivate(keySpec) val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding") cipher.init(Cipher.DECRYPT_MODE, privateKey) val bytes = Base64.getDecoder().decode(dataToDecrypt) val decryptedBytes = cipher.doFinal(bytes) val decryptedData = Base64.getEncoder().encodeToString(decryptedBytes) return decryptedData } 

Here's the full exception log:

javax.crypto.BadPaddingException: Decryption error at sun.security.rsa.RSAPadding.unpadOAEP(RSAPadding.java:502) at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:296) 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:2164) at dev.wirespec.security.Encryption.decryptWithRSA(Encryption.kt:162) at dev.wirespec.services.accounts.AccountsServlet$doGet$1.invokeSuspend(AccountsServlet.kt:31) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594) at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740) 
3
  • Can you share the BadPaddingException log Commented Apr 1, 2020 at 7:38
  • Are you sure it is Java? Commented Apr 1, 2020 at 8:00
  • @AymanArif Added the details of the exception to my post. Commented Apr 1, 2020 at 8:19

2 Answers 2

3

There is mismatch of padding parameter in Encrpyt and Decrypt:

In encryptWithRSA() method it is:

val cipher = Cipher.getInstance("RSA/ECB/NoPadding") 

In decryptWithRSA() method it is:

val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding") 

Choose one type of padding for encryption and decryption, and it should work.

Note: As Dave pointed out, having no pad is a serious security flaw, so it's better to include it for your cipher.

Sign up to request clarification or add additional context in comments.

2 Comments

Agree, but for encryption don't choose NoPadding because, although it will 'work' in the sense of decrypt(encrypt(x))=x, it is almost always easily broken by an adversary and not secure, and people normally use encryption when they want security. Search 'textbook RSA' on crypto.SX and security.SX. Also 128 bytes = 1024 bits and RSA-1024, although not yet actually broken as a primitive, is no longer considered to provide an acceptable safety margin for any but very low-value data.
I applied this "val cipher = Cipher.getInstance("RSA") to both encryption and decryption and it worked. Even though my solution worked, I'll make your solution the accepted one.
0

I got it to work with this:

fun encryptWithRSA(dataToEncrypt: String): String { // See: https://stackoverflow.com/questions/5789685/rsa-encryption-with-given-public-key-in-java val modulus = BigInteger("F70F9B...0F29901", 16) val pubExp = BigInteger("010001", 16) val keyFactory = KeyFactory.getInstance("RSA") val pubKeySpec = RSAPublicKeySpec(modulus, pubExp) val key: RSAPublicKey = keyFactory.generatePublic(pubKeySpec) as RSAPublicKey val cipher = Cipher.getInstance("RSA") cipher.init(Cipher.ENCRYPT_MODE, key) val encryptedBytes = cipher.doFinal(dataToEncrypt.toByteArray()) val encryptedData = Base64.getEncoder().encodeToString(encryptedBytes) return encryptedData } fun decryptWithRSA(dataToDecrypt: String): String { val PRIVATE_RSA_KEY_PKCS8 = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAPcPm8Jx3W7ZPulQ\n" + "..." + "+MhX/txtOjY8Y+FOFXOeb0EIMhaMQR02+3+wIbN/IMJUyz2Eq/mDX8oX8BwMGlah\n" + "WSWouLwHaZFcDn7Q" val keySpec = PKCS8EncodedKeySpec(parseBase64Binary(PRIVATE_RSA_KEY_PKCS8)) val keyFactory = KeyFactory.getInstance("RSA") val privateKey = keyFactory.generatePrivate(keySpec) val cipher = Cipher.getInstance("RSA") cipher.init(Cipher.DECRYPT_MODE, privateKey) val bytes = Base64.getDecoder().decode(dataToDecrypt) val decryptedBytes = cipher.doFinal(bytes) val d = decryptedBytes.toString(Charsets.UTF_8) val decryptedData = Base64.getEncoder().encodeToString(decryptedBytes) return decryptedData } 

The most important thing here is that when encrypting/decrypting, you have to use the same initialization:

val keyFactory = KeyFactory.getInstance("RSA") 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.