diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs index 0cd7db03d..26530d9a8 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs @@ -491,7 +491,7 @@ namespace Bit.App.Pages await _stateService.SetBiometricUnlockAsync(null); } await _stateService.SetBiometricLockedAsync(false); - await _cryptoService.ToggleKeyAsync(); + await _cryptoService.ToggleKeysAsync(); BuildList(); } diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index f20034cd7..72f34867a 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -9,6 +9,7 @@ namespace Bit.Core.Abstractions { public interface ICryptoService { + Task ToggleKeysAsync(); Task SetUserKeyAsync(UserKey userKey, string userId = null); Task GetUserKeyAsync(string userId = null); Task HasUserKeyAsync(string userId = null); @@ -25,7 +26,7 @@ namespace Bit.Core.Abstractions Task SetPasswordHashAsync(string keyHash); Task GetPasswordHashAsync(); Task ClearPasswordHashAsync(string userId = null); - Task CompareAndUpdatePasswordHashAsync(string masterPassword, SymmetricCryptoKey key); + Task CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key); Task SetOrgKeysAsync(IEnumerable orgs); Task GetOrgKeyAsync(string orgId); Task> GetOrgKeysAsync(); @@ -75,6 +76,5 @@ namespace Bit.Core.Abstractions Task> RemakeEncKeyAsync(SymmetricCryptoKey key); Task SetEncKeyAsync(string encKey); Task SetKeyAsync(SymmetricCryptoKey key); - Task ToggleKeyAsync(); } } diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index 42fe83c32..8d30afeb0 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -36,6 +36,17 @@ namespace Bit.Core.Services _cryptoFunctionService = cryptoFunctionService; } + public async Task ToggleKeysAsync() + { + // refresh or clear the pin key + await SetUserKeyAsync(await GetUserKeyAsync()); + + // refresh or clear the encrypted user key + var encUserKey = await _stateService.GetUserKeyMasterKeyAsync(); + await _stateService.SetUserKeyMasterKeyAsync(null); + await _stateService.SetUserKeyMasterKeyAsync(encUserKey); + } + public async Task SetUserKeyAsync(UserKey userKey, string userId = null) { await _stateService.SetUserKeyAsync(userKey, userId); @@ -45,6 +56,11 @@ namespace Bit.Core.Services { await StorePinKey(userKey, userId); } + else + { + await _stateService.SetUserKeyPinAsync(null, userId); + await _stateService.SetUserKeyPinEphemeralAsync(null, userId); + } } public async Task GetUserKeyAsync(string userId = null) @@ -69,12 +85,21 @@ namespace Bit.Core.Services public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) { + var option = await _stateService.GetVaultTimeoutAsync(); + var biometric = await _stateService.GetBiometricUnlockAsync(); + if (option.HasValue && !biometric.GetValueOrDefault()) + { + // we only store the encrypted user key if the user has a vault timeout set + // with no biometric. Otherwise, we need it for auto unlock or biometric unlock + return; + } await _stateService.SetUserKeyMasterKeyAsync(value, userId); } public async Task SetMasterKeyAsync(MasterKey masterKey, string userId = null) { await _stateService.SetMasterKeyAsync(masterKey, userId); + } public async Task GetMasterKeyAsync(string userId = null) @@ -211,7 +236,7 @@ namespace Bit.Core.Services } // TODO(Jake): Uses Master Key - public async Task CompareAndUpdatePasswordHashAsync(string masterPassword, SymmetricCryptoKey key) + public async Task CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key) { var storedPasswordHash = await GetPasswordHashAsync(); if (masterPassword != null && storedPasswordHash != null) @@ -385,6 +410,14 @@ namespace Bit.Core.Services return await StretchKeyAsync(pinKey) as PinKey; } + public async Task ClearPinKeys(string userId = null) + { + await _stateService.SetUserKeyPinAsync(null, userId); + await _stateService.SetUserKeyPinEphemeralAsync(null, userId); + await _stateService.SetProtectedPinAsync(null, userId); + await clearDeprecatedPinKeysAsync(userId); + } + // public async Task DecryptUserKeyWithPin(string pin, string salt, KdfConfig kdfConfig, EncString pinProtectedUserKey = null) // { // pinProtectedUserKey ??= await _stateService.GetUserKeyPinAsync(); @@ -614,7 +647,7 @@ namespace Bit.Core.Services return new EncByteArray(encBytes); } - // Helpers + // --HELPER METHODS-- private async Task StorePinKey(UserKey userKey, string userId = null) { @@ -899,6 +932,15 @@ namespace Bit.Core.Services public SymmetricCryptoKey Key { get; set; } } + // --LEGACY METHODS-- + // We previously used the master key for additional keys, but now we use the user key. + // These methods support migrating the old keys to the new ones. + + public async Task clearDeprecatedPinKeysAsync(string userId = null) + { + await _stateService.SetPinProtectedAsync(null); + await _stateService.SetPinProtectedKeyAsync(null); + } @@ -1083,21 +1125,6 @@ namespace Bit.Core.Services } - public async Task ToggleKeyAsync() - { - var key = await GetKeyAsync(); - var option = await _stateService.GetVaultTimeoutAsync(); - var biometric = await _stateService.GetBiometricUnlockAsync(); - if (!biometric.GetValueOrDefault() && (option != null || option == 0)) - { - await ClearKeyAsync(); - await _stateService.SetKeyDecryptedAsync(key); - return; - } - await SetKeyAsync(key); - } - - public async Task MakeKeyFromPinAsync(string pin, string salt, KdfConfig config, EncString protectedKeyCs = null) { diff --git a/src/Core/Services/VaultTimeoutService.cs b/src/Core/Services/VaultTimeoutService.cs index f5bd7d4bd..917664917 100644 --- a/src/Core/Services/VaultTimeoutService.cs +++ b/src/Core/Services/VaultTimeoutService.cs @@ -214,7 +214,7 @@ namespace Bit.Core.Services { await _stateService.SetVaultTimeoutAsync(timeout); await _stateService.SetVaultTimeoutActionAsync(action); - await _cryptoService.ToggleKeyAsync(); + await _cryptoService.ToggleKeysAsync(); await _tokenService.ToggleTokensAsync(); }