Skip to content

Commit

Permalink
fix: IllegalBlockSizeException on Android while decrypting (#685)
Browse files Browse the repository at this point in the history
  • Loading branch information
DorianMazur authored Nov 13, 2024
1 parent 1cd6076 commit 30f3056
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.oblador.keychain.cipherStorage

import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyInfo
import android.security.keystore.UserNotAuthenticatedException
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.oblador.keychain.SecurityLevel
Expand Down Expand Up @@ -379,6 +381,7 @@ abstract class CipherStorageBase(protected val applicationContext: Context) : Ci
}

/** Decrypt provided bytes to a string. */
@SuppressLint("NewApi")
@Throws(GeneralSecurityException::class, IOException::class)
protected open fun decryptBytes(
key: Key,
Expand All @@ -391,7 +394,19 @@ abstract class CipherStorageBase(protected val applicationContext: Context) : Ci
ByteArrayOutputStream().use { output ->
handler?.initialize(cipher, key, input)

CipherInputStream(input, cipher).use { decrypt -> copy(decrypt, output) }
try {
val decrypted = cipher.doFinal(input.readBytes())
output.write(decrypted)
} catch (e: Exception) {
when {
e is UserNotAuthenticatedException -> throw e
e.cause is android.security.KeyStoreException &&
e.cause?.message?.contains("Key user not authenticated") == true -> {
throw UserNotAuthenticatedException()
}
else -> throw e
}
}

return String(output.toByteArray(), UTF8)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,33 +229,6 @@ class CipherStorageKeystoreAesGcm(reactContext: ReactApplicationContext, private

/** Decrypt provided bytes to a string. */

@Throws(GeneralSecurityException::class, IOException::class)
override fun decryptBytes(
key: Key,
bytes: ByteArray,
handler: DecryptBytesHandler?
): String {
val cipher = getCachedInstance()

return try {
if (IV.IV_LENGTH >= bytes.size)
throw IOException("Insufficient length of input data for IV extracting.")
val iv = ByteArray(IV.IV_LENGTH)
System.arraycopy(bytes, 0, iv, 0, IV.IV_LENGTH)
val spec = GCMParameterSpec(IV.TAG_LENGTH, iv)
cipher.init(Cipher.DECRYPT_MODE, key, spec)

// Decrypt the bytes using cipher.doFinal()
val decryptedBytes = cipher.doFinal(bytes, IV.IV_LENGTH, bytes.size - IV.IV_LENGTH)
String(decryptedBytes, UTF8)
} catch (ex: UserNotAuthenticatedException){
throw ex
} catch (fail: Throwable) {
Log.w(LOG_TAG, fail.message, fail)
throw fail
}
}

// endregion

// region Initialization Vector encrypt/decrypt support
Expand Down

0 comments on commit 30f3056

Please sign in to comment.