diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/KdfManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/KdfManagerImpl.kt index e91dad119f..4cdfbf44b4 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/KdfManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/manager/KdfManagerImpl.kt @@ -16,6 +16,7 @@ import com.x8bit.bitwarden.data.auth.repository.util.toUserStateJsonKdfUpdatedMi import com.x8bit.bitwarden.data.auth.util.KdfParamsConstants.DEFAULT_PBKDF2_ITERATIONS import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource +import timber.log.Timber import kotlin.collections.get /** @@ -71,6 +72,7 @@ class KdfManagerImpl( onSuccess = { authDiskSource.userState = authDiskSource.userState ?.toUserStateJsonKdfUpdatedMinimums() + Timber.d("[Auth] Upgraded user's KDF to minimums") UpdateKdfMinimumsResult.Success }, onFailure = { UpdateKdfMinimumsResult.Error(error = it) }, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt index 13b4e62e56..e49e491724 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt @@ -39,6 +39,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResul import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.logTag import com.x8bit.bitwarden.data.vault.repository.util.statusFor import com.x8bit.bitwarden.data.vault.repository.util.toVaultUnlockResult import com.x8bit.bitwarden.data.vault.repository.util.update @@ -239,7 +240,10 @@ class VaultLockManagerImpl( trustedDeviceManager .trustThisDeviceIfNecessary(userId = userId) updateKdfIfNeeded(initUserCryptoMethod) - migratePinProtectedUserKeyIfNeeded(userId = userId) + migratePinProtectedUserKeyIfNeeded( + userId = userId, + initUserCryptoMethod = initUserCryptoMethod, + ) setVaultToUnlocked(userId = userId) } else { incrementInvalidUnlockCount(userId = userId) @@ -284,12 +288,19 @@ class VaultLockManagerImpl( * Optionally marks the envelope as in-memory only if the PIN-protected user key is not present. * * @param userId The ID of the user for whom to migrate the PIN-protected user key. + * @param initUserCryptoMethod The method used to initialize the user's crypto. */ - private suspend fun migratePinProtectedUserKeyIfNeeded(userId: String) { + private suspend fun migratePinProtectedUserKeyIfNeeded( + userId: String, + initUserCryptoMethod: InitUserCryptoMethod, + ) { val encryptedPin = authDiskSource.getEncryptedPin(userId) ?: return if (authDiskSource.getPinProtectedUserKeyEnvelope(userId) != null) return val inMemoryOnly = authDiskSource.getPinProtectedUserKey(userId) == null + + Timber.d("[Auth] Vault unlocked, method: ${initUserCryptoMethod.logTag}") + vaultSdkSource.enrollPinWithEncryptedPin(userId, encryptedPin) .onSuccess { enrollPinResponse -> authDiskSource.storeEncryptedPin( @@ -306,6 +317,11 @@ class VaultLockManagerImpl( pinProtectedUserKey = null, inMemoryOnly = inMemoryOnly, ) + if (inMemoryOnly) { + Timber.d("[Auth] Set PIN-protected user key in memory") + } else { + Timber.d("[Auth] Migrated from legacy PIN to PIN-protected user key envelope") + } } } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index db5bc2977e..d0c80195e8 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -40,6 +40,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult import com.x8bit.bitwarden.data.vault.repository.model.ImportCredentialsResult import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.logTag import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkFolder import com.x8bit.bitwarden.data.vault.repository.util.toSdkAccount @@ -326,7 +327,12 @@ class VaultRepositoryImpl( ) authDiskSource.storeUserBiometricInitVector(userId = userId, iv = cipher.iv) } - deriveTemporaryPinProtectedUserKeyIfNecessary(userId = userId) + deriveTemporaryPinProtectedUserKeyIfNecessary( + userId = userId, + initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( + decryptedUserKey = decryptedUserKey, + ), + ) } } } @@ -350,7 +356,13 @@ class VaultRepositoryImpl( ) .also { if (it is VaultUnlockResult.Success) { - deriveTemporaryPinProtectedUserKeyIfNecessary(userId = userId) + deriveTemporaryPinProtectedUserKeyIfNecessary( + userId = userId, + initUserCryptoMethod = InitUserCryptoMethod.Password( + password = masterPassword, + userKey = userKey, + ), + ) } } } @@ -516,14 +528,23 @@ class VaultRepositoryImpl( * unlocks during this current app session. * * If the user's vault has not yet been unlocked, this call will do nothing. + * + * @param userId The ID of the user to check. + * @param initUserCryptoMethod The method used to initialize the user's crypto. */ - private suspend fun deriveTemporaryPinProtectedUserKeyIfNecessary(userId: String) { + private suspend fun deriveTemporaryPinProtectedUserKeyIfNecessary( + userId: String, + initUserCryptoMethod: InitUserCryptoMethod, + ) { val encryptedPin = authDiskSource.getEncryptedPin(userId = userId) ?: return val existingPinProtectedUserKeyEnvelope = authDiskSource .getPinProtectedUserKeyEnvelope( userId = userId, ) if (existingPinProtectedUserKeyEnvelope != null) return + + Timber.d("[Auth] Vault unlocked, method: ${initUserCryptoMethod.logTag}") + vaultSdkSource .enrollPinWithEncryptedPin( userId = userId, @@ -544,6 +565,7 @@ class VaultRepositoryImpl( pinProtectedUserKey = null, inMemoryOnly = true, ) + Timber.d("[Auth] Set PIN-protected user key in memory") } } diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt new file mode 100644 index 0000000000..b497bcc62d --- /dev/null +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/InitUserCryptoMethodExtensions.kt @@ -0,0 +1,19 @@ +package com.x8bit.bitwarden.data.vault.repository.util + +import com.bitwarden.core.InitUserCryptoMethod + +/** + * Returns the label for the given [InitUserCryptoMethod]. + * This will be only used for logging purposes, therefore it is not localized. + */ +val InitUserCryptoMethod.logTag: String + get() = when (this) { + is InitUserCryptoMethod.AuthRequest -> "Auth Request" + is InitUserCryptoMethod.DecryptedKey -> "Decrypted Key (Never Lock/Biometrics)" + is InitUserCryptoMethod.DeviceKey -> "Device Key" + is InitUserCryptoMethod.KeyConnector -> "Key Connector" + is InitUserCryptoMethod.Password -> "Password" + is InitUserCryptoMethod.Pin -> "Pin" + is InitUserCryptoMethod.PinEnvelope -> "Pin Envelope" + is InitUserCryptoMethod.MasterPasswordUnlock -> "Master Password Unlock" + }