1

I looked for the past 2 days at possible solutions but couldn't find anything helpful. I have an Android app that needs to handle some encryption and decryption operations using Android KeyStore. Key generation and encryption seem to work fine, but I get some exceptions at decryption. More precisely an android.security.KeyStoreException is thrown with the explication: invalid input length. I will post below the code and the exceptions, and after that I'll describe what I have tried

Here is the key generation function:

     private var provider = 
     fun generateKeys(): KeyPair {
        val keyStore = KeyStore.getInstance(provider)
        val kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, provider);
        val parmeterSpec = KeyGenParameterSpec.Builder(
            ALIAS,
            KeyProperties.PURPOSE_DECRYPT or KeyProperties.PURPOSE_ENCRYPT
        ).run {
            setUserAuthenticationRequired(false)
            setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
            setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP)
            // post (1) suggested this for a previous issue:
            setRandomizedEncryptionRequired(true) 
            build()
        }

        kpg.initialize(parmeterSpec)
        val kp = kpg.generateKeyPair()

        return kp
    }

Here is the encryption function:

    private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
    fun encrypt(message: String, publicKey: PublicKey) : String? {
        // MFG SHA1 used because of post (2)
        val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
        val cipher = Cipher.getInstance(method)
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)

        val encryptedBytes = cipher.doFinal(message.toByteArray())
        return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
    }

The decrypt function:

    private var method = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"
    fun decrypt(encrypted: String, privateKey: PrivateKey) : String? {
        val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)
        val cipher = Cipher.getInstance(method)
        cipher.init(Cipher.DECRYPT_MODE, privateKey, spec)
        val decryptedBytes = cipher.doFinal(encrypted.toByteArray())
        return Base64.encodeToString(decryptedBytes, Base64.DEFAULT)
    }

And at last here is an extract from which I call those functions:

val keyPair = generateKeys()
val message = "a simple message"

val encryptedMessage = encrypt(message, keyPair.public)
val result = decrypt(encryptedMessage, keyPair.private)

Post 1: here Post 2: here

I also saw a this post suggesting that RSA cannot decrypt messages longer than 256. For me is not the case since in this case the encrypted message length is 175 bytes, and I'm not planning to use longer messages. Another suggestion I saw (forgot where) was that Base64 might add unwanted characters, and before decryption I should replace '\n' with '' - but that doesn't work either... Is there something I am overlooking?

Here are the exception:

     Caused by: javax.crypto.IllegalBlockSizeException
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:513)
        at javax.crypto.Cipher.doFinal(Cipher.java:2055)
        at com.sandwich.testkeystore.MainActivity.decrypt(MainActivity.kt:132)
        at com.sandwich.testkeystore.MainActivity.onCreate(MainActivity.kt:65)
        at android.app.Activity.performCreate(Activity.java:7822)
        at android.app.Activity.performCreate(Activity.java:7811)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1328)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3452)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3620) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2183) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:241) 
        at android.app.ActivityThread.main(ActivityThread.java:7604) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941) 
     Caused by: android.security.KeyStoreException: Invalid input length
        at android.security.KeyStore.getKeyStoreException(KeyStore.java:1303)
        at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.update(KeyStoreCryptoOperationChunkedStreamer.java:132)
        at android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.doFinal(KeyStoreCryptoOperationChunkedStreamer.java:217)
        at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineDoFinal(AndroidKeyStoreCipherSpiBase.java:506)
        at javax.crypto.Cipher.doFinal(Cipher.java:2055) 
        at com.sandwich.testkeystore.MainActivity.decrypt(MainActivity.kt:132) 
        at com.sandwich.testkeystore.MainActivity.onCreate(MainActivity.kt:65) 
        at android.app.Activity.performCreate(Activity.java:7822) 
        at android.app.Activity.performCreate(Activity.java:7811) 
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1328) 
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3452) 
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3620) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2183) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:241) 
        at android.app.ActivityThread.main(ActivityThread.java:7604) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941) 

  • 2
    In `decrypt()` the ciphertext must be Base64 decoded (and not UTF8 encoded) and the decrypted data must be UTF8 decoded (and not Base64 encoded). – Topaco Jun 09 '22 at 18:43
  • How long a RSA encrypted message can be depends on the key size and the used padding scheme. In the lower part of [this answer](https://crypto.stackexchange.com/a/42100/744) you find a table describing how many bytes your massage is allowed to have. – Robert Jun 10 '22 at 17:15
  • the same error I am getting from my app center reports on android 11 have you got any fix. – Sultan May 30 '23 at 02:37

0 Answers0