mirror of
https://github.com/bitwarden/android.git
synced 2026-03-22 06:11:38 -05:00
PM-19389: Handle encoding error when migrating biometric key (#4900)
This commit is contained in:
@@ -557,31 +557,46 @@ class VaultRepositoryImpl(
|
||||
error = MissingPropertyException("Biometric key"),
|
||||
)
|
||||
val iv = authDiskSource.getUserBiometricInitVector(userId = userId)
|
||||
val decryptedUserKey = iv
|
||||
?.let {
|
||||
try {
|
||||
cipher
|
||||
.doFinal(biometricsKey.toByteArray(Charsets.ISO_8859_1))
|
||||
.decodeToString()
|
||||
} catch (e: GeneralSecurityException) {
|
||||
return VaultUnlockResult.BiometricDecodingError(error = e)
|
||||
}
|
||||
}
|
||||
?: biometricsKey
|
||||
val encryptedBiometricsKey = if (iv == null) {
|
||||
// Attempting to setup an encrypted pin before unlocking, if this fails we send back
|
||||
// the biometrics error and users will need to sign in another way and re-setup
|
||||
// biometrics.
|
||||
try {
|
||||
cipher
|
||||
.doFinal(biometricsKey.encodeToByteArray())
|
||||
.toString(Charsets.ISO_8859_1)
|
||||
} catch (e: GeneralSecurityException) {
|
||||
return VaultUnlockResult.BiometricDecodingError(error = e)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return this
|
||||
.unlockVaultForUser(
|
||||
userId = userId,
|
||||
initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey(
|
||||
decryptedUserKey = iv
|
||||
?.let {
|
||||
try {
|
||||
cipher
|
||||
.doFinal(biometricsKey.toByteArray(Charsets.ISO_8859_1))
|
||||
.decodeToString()
|
||||
} catch (e: GeneralSecurityException) {
|
||||
return VaultUnlockResult.BiometricDecodingError(error = e)
|
||||
}
|
||||
}
|
||||
?: biometricsKey,
|
||||
decryptedUserKey = decryptedUserKey,
|
||||
),
|
||||
)
|
||||
.also {
|
||||
if (it is VaultUnlockResult.Success) {
|
||||
if (iv == null) {
|
||||
encryptedBiometricsKey?.let {
|
||||
// If this key is present, we store it and the associated IV for future use
|
||||
// since we want to migrate the user to a more secure form of biometrics.
|
||||
authDiskSource.storeUserBiometricUnlockKey(
|
||||
userId = userId,
|
||||
biometricsKey = cipher
|
||||
.doFinal(biometricsKey.encodeToByteArray())
|
||||
.toString(Charsets.ISO_8859_1),
|
||||
biometricsKey = it,
|
||||
)
|
||||
authDiskSource.storeUserBiometricInitVector(userId = userId, iv = cipher.iv)
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ import org.junit.jupiter.api.Test
|
||||
import retrofit2.HttpException
|
||||
import java.io.File
|
||||
import java.net.UnknownHostException
|
||||
import java.security.GeneralSecurityException
|
||||
import java.security.MessageDigest
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
@@ -1296,6 +1297,33 @@ class VaultRepositoryTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `unlockVaultWithBiometrics with failure to encode biometrics key should return BiometricDecodingError`() =
|
||||
runTest {
|
||||
val userId = MOCK_USER_STATE.activeUserId
|
||||
val biometricsKey = "asdf1234"
|
||||
val error = GeneralSecurityException()
|
||||
val cipher = mockk<Cipher> {
|
||||
every { doFinal(any()) } throws error
|
||||
}
|
||||
fakeAuthDiskSource.userState = MOCK_USER_STATE
|
||||
fakeAuthDiskSource.storeUserBiometricUnlockKey(
|
||||
userId = userId,
|
||||
biometricsKey = biometricsKey,
|
||||
)
|
||||
|
||||
val result = vaultRepository.unlockVaultWithBiometrics(cipher = cipher)
|
||||
|
||||
assertEquals(
|
||||
VaultUnlockResult.BiometricDecodingError(error = error),
|
||||
result,
|
||||
)
|
||||
coVerify(exactly = 0) {
|
||||
vaultSdkSource.derivePinProtectedUserKey(any(), any())
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `unlockVaultWithBiometrics with an IV and VaultLockManager Success should store the updated key and IV and unlock for the current user and return Success`() =
|
||||
|
||||
Reference in New Issue
Block a user