fix(Android): If StrongBox is not available, fallback to TEE for master key storage

This commit is contained in:
Artem Chepurnoy 2024-07-08 08:53:15 +03:00
parent 3999b41d39
commit 74ef9a34ef
No known key found for this signature in database
GPG Key ID: FAC37D0CF674043E
1 changed files with 22 additions and 2 deletions

View File

@ -2,6 +2,9 @@ package db_key_value.crypto_prefs
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.os.Build
import android.security.keystore.StrongBoxUnavailableException
import androidx.annotation.RequiresApi
import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey import androidx.security.crypto.MasterKey
import com.artemchep.keyguard.common.service.keyvalue.KeyValueStore import com.artemchep.keyguard.common.service.keyvalue.KeyValueStore
@ -94,16 +97,25 @@ private fun getMasterKeyAlias(
): MasterKey { ): MasterKey {
lateinit var exception: Throwable lateinit var exception: Throwable
var strongBox = true
val retryCount = 3 val retryCount = 3
for (i in 0 until retryCount) { for (i in 0 until retryCount) {
try { try {
return MasterKey.Builder(context, alias) return MasterKey.Builder(context, alias)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM) .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setRequestStrongBoxBacked(true) .setRequestStrongBoxBacked(strongBox)
.setUserAuthenticationRequired(false) .setUserAuthenticationRequired(false)
.build() .build()
} catch (e: Exception) { } catch (e: Exception) {
if (e is GeneralSecurityException) { if (e.isStrongBoxUnavailableExceptionCompat()) {
// If the StrongBox Keymaster isn't available for the given algorithm
// and key size associated with a key, the framework throws a
// StrongBoxUnavailableException. If you get this exception,
// try using TEE for your key storage as a fallback option.
//
// https://developer.android.com/privacy-and-security/keystore#HardwareSecurityModule
strongBox = false
} else if (e is GeneralSecurityException) {
exception = e exception = e
onError() onError()
} else { } else {
@ -136,3 +148,11 @@ private fun clearKeystore(
keyStore.load(null) keyStore.load(null)
keyStore.deleteEntry(alias) keyStore.deleteEntry(alias)
} }
private fun Throwable.isStrongBoxUnavailableExceptionCompat(): Boolean =
Build.VERSION.SDK_INT >= 28 && isStrongBoxUnavailableException()
@RequiresApi(Build.VERSION_CODES.P)
private fun Throwable.isStrongBoxUnavailableException(): Boolean =
this is StrongBoxUnavailableException ||
cause?.isStrongBoxUnavailableException() == true