Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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

/**
Expand Down Expand Up @@ -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) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -326,7 +327,12 @@ class VaultRepositoryImpl(
)
authDiskSource.storeUserBiometricInitVector(userId = userId, iv = cipher.iv)
}
deriveTemporaryPinProtectedUserKeyIfNecessary(userId = userId)
deriveTemporaryPinProtectedUserKeyIfNecessary(
userId = userId,
initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey(
decryptedUserKey = decryptedUserKey,
),
)
}
}
}
Expand All @@ -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,
),
)
}
}
}
Expand Down Expand Up @@ -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,
Expand All @@ -544,6 +565,7 @@ class VaultRepositoryImpl(
pinProtectedUserKey = null,
inMemoryOnly = true,
)
Timber.d("[Auth] Set PIN-protected user key in memory")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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"
}
Loading