diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index c56968933..3360232ec 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -296,13 +296,13 @@ namespace Bit.App.Pages else { var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig); - var storedKeyHash = await _cryptoService.GetKeyHashAsync(); + var storedKeyHash = await _cryptoService.GetPasswordHashAsync(); var passwordValid = false; MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null; if (storedKeyHash != null) { - passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key); + passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, key); } else { @@ -317,7 +317,7 @@ namespace Bit.App.Pages enforcedMasterPasswordOptions = response.MasterPasswordPolicy; passwordValid = true; var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization); - await _cryptoService.SetKeyHashAsync(localKeyHash); + await _cryptoService.SetPasswordHashAsync(localKeyHash); } catch (Exception e) { diff --git a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs index 51d468275..4e0bfd04f 100644 --- a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs @@ -205,7 +205,7 @@ namespace Bit.App.Pages await _apiService.SetPasswordAsync(request); await _stateService.SetKdfConfigurationAsync(kdfConfig); await _cryptoService.SetKeyAsync(key); - await _cryptoService.SetKeyHashAsync(localMasterPasswordHash); + await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash); await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); await _cryptoService.SetEncPrivateKeyAsync(keys.Item2.EncryptedString); diff --git a/src/App/Services/MobilePasswordRepromptService.cs b/src/App/Services/MobilePasswordRepromptService.cs index 28a8e5a86..460e9df58 100644 --- a/src/App/Services/MobilePasswordRepromptService.cs +++ b/src/App/Services/MobilePasswordRepromptService.cs @@ -38,7 +38,7 @@ namespace Bit.App.Services return false; }; - return await _cryptoService.CompareAndUpdateKeyHashAsync(password, null); + return await _cryptoService.CompareAndUpdatePasswordHashAsync(password, null); } public async Task Enabled() diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 060cd9887..217e1be55 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -9,9 +9,21 @@ namespace Bit.Core.Abstractions { public interface ICryptoService { + Task SetUserKeyAsync(UserKey userKey); + Task GetUserKeyAsync(string userId = null); + Task HasUserKeyAsync(string userId = null); + Task ClearUserKeyAsync(string userId = null); + Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null); + Task SetMasterKeyAsync(MasterKey masterKey, string userId = null); + Task GetMasterKeyAsync(string userId = null); + Task ClearMasterKeyAsync(string userId = null); + Task SetPasswordHashAsync(string keyHash); + Task GetPasswordHashAsync(); + Task ClearPasswordHashAsync(string userId = null); + Task CompareAndUpdatePasswordHashAsync(string masterPassword, SymmetricCryptoKey key); + Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null); Task ClearKeyAsync(string userId = null); - Task ClearKeyHashAsync(string userId = null); Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null); Task ClearKeysAsync(string userId = null); Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null); @@ -26,12 +38,10 @@ namespace Bit.Core.Abstractions Task GetEncKeyAsync(SymmetricCryptoKey key = null); Task> GetFingerprintAsync(string userId, byte[] publicKey = null); Task GetKeyAsync(string userId = null); - Task GetKeyHashAsync(); Task GetOrgKeyAsync(string orgId); Task> GetOrgKeysAsync(); Task GetPrivateKeyAsync(); Task GetPublicKeyAsync(); - Task CompareAndUpdateKeyHashAsync(string masterPassword, SymmetricCryptoKey key); Task HasEncKeyAsync(); Task HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization); Task HasKeyAsync(string userId = null); @@ -50,7 +60,6 @@ namespace Bit.Core.Abstractions Task SetEncKeyAsync(string encKey); Task SetEncPrivateKeyAsync(string encPrivateKey); Task SetKeyAsync(SymmetricCryptoKey key); - Task SetKeyHashAsync(string keyHash); Task SetOrgKeysAsync(IEnumerable orgs); Task ToggleKeyAsync(); } diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index 92cbadd3b..a06ed8498 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -477,7 +477,7 @@ namespace Bit.Core.Services if (localHashedPassword != null) { - await _cryptoService.SetKeyHashAsync(localHashedPassword); + await _cryptoService.SetPasswordHashAsync(localHashedPassword); } if (code == null || tokenResponse.Key != null) diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index afd57c308..6b86895d6 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -21,7 +21,7 @@ namespace Bit.Core.Services private SymmetricCryptoKey _encKey; private SymmetricCryptoKey _legacyEtmKey; - private string _keyHash; + private string _passwordHash; private byte[] _publicKey; private byte[] _privateKey; private Dictionary _orgKeys; @@ -36,22 +36,37 @@ namespace Bit.Core.Services _cryptoFunctionService = cryptoFunctionService; } - public async Task SetUserKeyAsync(UserKey key) + public async Task SetUserKeyAsync(UserKey userKey) { - await _stateService.SetUserKeyAsync(key); + await _stateService.SetUserKeyAsync(userKey); } - public async Task GetUserKey(string userId = null) + public async Task GetUserKeyAsync(string userId = null) { return await _stateService.GetUserKeyAsync(userId); } - public async Task SetMasterKey(MasterKey masterKey, string userId = null) + public async Task HasUserKeyAsync(string userId = null) + { + return await GetUserKeyAsync(userId) != null; + } + + public async Task ClearUserKeyAsync(string userId = null) + { + await _stateService.SetUserKeyAsync(null, userId); + } + + public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) + { + await _stateService.SetUserKeyMasterKeyAsync(value, userId); + } + + public async Task SetMasterKeyAsync(MasterKey masterKey, string userId = null) { await _stateService.SetMasterKeyAsync(masterKey, userId); } - public async Task GetMasterKey(string userId = null) + public async Task GetMasterKeyAsync(string userId = null) { var masterKey = await _stateService.GetMasterKeyAsync(userId); if (masterKey == null) @@ -59,12 +74,63 @@ namespace Bit.Core.Services // Migration support var encMasterKey = await _stateService.GetKeyEncryptedAsync(userId); masterKey = new MasterKey(Convert.FromBase64String(encMasterKey)); - await this.SetMasterKey(masterKey, userId); + await this.SetMasterKeyAsync(masterKey, userId); } return masterKey; } + public async Task ClearMasterKeyAsync(string userId = null) + { + await _stateService.SetMasterKeyAsync(null, userId); + } + public async Task SetPasswordHashAsync(string keyHash) + { + _passwordHash = keyHash; + await _stateService.SetKeyHashAsync(keyHash); + } + + public async Task GetPasswordHashAsync() + { + if (_passwordHash != null) + { + return _passwordHash; + } + var passwordHash = await _stateService.GetKeyHashAsync(); + if (passwordHash != null) + { + _passwordHash = passwordHash; + } + return _passwordHash; + } + + public async Task ClearPasswordHashAsync(string userId = null) + { + _passwordHash = null; + await _stateService.SetKeyHashAsync(null, userId); + } + + public async Task CompareAndUpdatePasswordHashAsync(string masterPassword, SymmetricCryptoKey key) + { + var storedPasswordHash = await GetPasswordHashAsync(); + if (masterPassword != null && storedPasswordHash != null) + { + var localPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); + if (localPasswordHash != null && storedPasswordHash == localPasswordHash) + { + return true; + } + + var serverPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.ServerAuthorization); + if (serverPasswordHash != null & storedPasswordHash == serverPasswordHash) + { + await SetPasswordHashAsync(localPasswordHash); + return true; + } + } + + return false; + } public async Task SetKeyAsync(SymmetricCryptoKey key) @@ -80,11 +146,6 @@ namespace Bit.Core.Services await _stateService.SetKeyEncryptedAsync(key?.KeyB64); } - public async Task SetPasswordHashAsync(string keyHash) - { - _keyHash = keyHash; - await _stateService.SetKeyHashAsync(keyHash); - } public async Task SetEncKeyAsync(string encKey) { @@ -129,19 +190,6 @@ namespace Bit.Core.Services return inMemoryKey; } - public async Task GetKeyHashAsync() - { - if (_keyHash != null) - { - return _keyHash; - } - var keyHash = await _stateService.GetKeyHashAsync(); - if (keyHash != null) - { - _keyHash = keyHash; - } - return _keyHash; - } public Task GetEncKeyAsync(SymmetricCryptoKey key = null) { @@ -306,27 +354,6 @@ namespace Bit.Core.Services return orgKeys[orgId]; } - public async Task CompareAndUpdateKeyHashAsync(string masterPassword, SymmetricCryptoKey key) - { - var storedKeyHash = await GetKeyHashAsync(); - if (masterPassword != null && storedKeyHash != null) - { - var localKeyHash = await HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); - if (localKeyHash != null && storedKeyHash == localKeyHash) - { - return true; - } - - var serverKeyHash = await HashPasswordAsync(masterPassword, key, HashPurpose.ServerAuthorization); - if (serverKeyHash != null & storedKeyHash == serverKeyHash) - { - await SetPasswordHashAsync(localKeyHash); - return true; - } - } - - return false; - } public async Task HasKeyAsync(string userId = null) { @@ -347,11 +374,6 @@ namespace Bit.Core.Services await _stateService.SetKeyEncryptedAsync(null, userId); } - public async Task ClearKeyHashAsync(string userId = null) - { - _keyHash = null; - await _stateService.SetKeyHashAsync(null, userId); - } public async Task ClearEncKeyAsync(bool memoryOnly = false, string userId = null) { @@ -389,7 +411,7 @@ namespace Bit.Core.Services { _encKey = null; _legacyEtmKey = null; - _keyHash = null; + _passwordHash = null; _publicKey = null; _privateKey = null; _orgKeys = null; @@ -400,7 +422,7 @@ namespace Bit.Core.Services await Task.WhenAll(new Task[] { ClearKeyAsync(userId), - ClearKeyHashAsync(userId), + ClearPasswordHashAsync(userId), ClearOrgKeysAsync(false, userId), ClearEncKeyAsync(false, userId), ClearKeyPairAsync(false, userId), @@ -853,7 +875,7 @@ namespace Bit.Core.Services private async Task GetUserKeyWithLegacySupport(string userId = null) { - var userKey = await GetUserKey(); + var userKey = await GetUserKeyAsync(); if (userKey != null) { return userKey; @@ -861,7 +883,7 @@ namespace Bit.Core.Services // Legacy support: encryption used to be done with the master key (derived from master password). // Users who have not migrated will have a null user key and must use the master key instead. - return (SymmetricCryptoKey)await GetMasterKey() as UserKey; + return (SymmetricCryptoKey)await GetMasterKeyAsync() as UserKey; } private async Task GetKeyForEncryptionAsync(SymmetricCryptoKey key = null) diff --git a/src/Core/Services/UserVerificationService.cs b/src/Core/Services/UserVerificationService.cs index 74031b55c..554c0d49a 100644 --- a/src/Core/Services/UserVerificationService.cs +++ b/src/Core/Services/UserVerificationService.cs @@ -44,7 +44,7 @@ namespace Bit.Core.Services } else { - var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, null); + var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(secret, null); if (!passwordValid) { await InvalidSecretErrorAsync(verificationType);