diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 1a084b4a3..3a388172a 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -9,6 +9,7 @@ namespace Bit.Core.Abstractions { public interface ICryptoService { + void ClearCache(); Task ToggleKeysAsync(); Task SetUserKeyAsync(UserKey userKey, string userId = null); Task GetUserKeyAsync(string userId = null); @@ -57,21 +58,5 @@ namespace Bit.Core.Abstractions Task EncryptAsync(string plainValue, SymmetricCryptoKey key = null); Task EncryptToBytesAsync(byte[] plainValue, SymmetricCryptoKey key = null); Task DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey); - - - - - - - - - - void ClearCache(); - - Task GetEncKeyAsync(SymmetricCryptoKey key = null); - Task GetKeyAsync(string userId = null); - Task> MakeEncKeyAsync(SymmetricCryptoKey key); - Task SetEncKeyAsync(string encKey); - Task SetKeyAsync(SymmetricCryptoKey key); } } diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index 9ff525c40..a33d71ccb 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -30,7 +30,7 @@ namespace Bit.Core.Services private readonly bool _setCryptoKeys; private readonly LazyResolve _watchDeviceService = new LazyResolve(); - private SymmetricCryptoKey _key; + private MasterKey _masterKey; private string _authedUserId; private MasterPasswordPolicyOptions _masterPasswordPolicy; @@ -199,7 +199,7 @@ namespace Bit.Core.Services { var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey); var decPasswordHash = await _cryptoService.RsaDecryptAsync(localHashedPasswordCiphered, decryptionKey); - return await LogInHelperAsync(email, accessCode, Encoding.UTF8.GetString(decPasswordHash), null, null, null, new SymmetricCryptoKey(decKey), null, null, + return await LogInHelperAsync(email, accessCode, Encoding.UTF8.GetString(decPasswordHash), null, null, null, new MasterKey(decKey), null, null, null, null, authRequestId: authRequestId); } @@ -216,7 +216,7 @@ namespace Bit.Core.Services { CaptchaToken = captchaToken; } - var result = await LogInHelperAsync(Email, MasterPasswordHash, LocalMasterPasswordHash, Code, CodeVerifier, SsoRedirectUrl, _key, + var result = await LogInHelperAsync(Email, MasterPasswordHash, LocalMasterPasswordHash, Code, CodeVerifier, SsoRedirectUrl, _masterKey, twoFactorProvider, twoFactorToken, remember, CaptchaToken, authRequestId: AuthRequestId); // If we successfully authenticated and we have a saved _2faForcePasswordResetReason reason from LogInAsync() @@ -337,7 +337,7 @@ namespace Bit.Core.Services // Helpers - private async Task MakePreloginKeyAsync(string masterPassword, string email) + private async Task MakePreloginKeyAsync(string masterPassword, string email) { email = email.Trim().ToLower(); KdfConfig kdfConfig = KdfConfig.Default; @@ -360,7 +360,7 @@ namespace Bit.Core.Services } private async Task LogInHelperAsync(string email, string hashedPassword, string localHashedPassword, - string code, string codeVerifier, string redirectUrl, SymmetricCryptoKey key, + string code, string codeVerifier, string redirectUrl, MasterKey masterKey, TwoFactorProviderType? twoFactorProvider = null, string twoFactorToken = null, bool? remember = null, string captchaToken = null, string orgId = null, string authRequestId = null) { @@ -426,7 +426,7 @@ namespace Bit.Core.Services Code = code; CodeVerifier = codeVerifier; SsoRedirectUrl = redirectUrl; - _key = _setCryptoKeys ? key : null; + _masterKey = _setCryptoKeys ? masterKey : null; TwoFactorProvidersData = response.TwoFactorResponse.TwoFactorProviders2; result.TwoFactorProviders = response.TwoFactorResponse.TwoFactorProviders2; CaptchaToken = response.TwoFactorResponse.CaptchaToken; @@ -470,9 +470,9 @@ namespace Bit.Core.Services _messagingService.Send("accountAdded"); if (_setCryptoKeys) { - if (key != null) + if (masterKey != null) { - await _cryptoService.SetKeyAsync(key); + await _cryptoService.SetMasterKeyAsync(masterKey); } if (localHashedPassword != null) @@ -487,7 +487,7 @@ namespace Bit.Core.Services await _keyConnectorService.GetAndSetKey(tokenResponse.KeyConnectorUrl); } - await _cryptoService.SetEncKeyAsync(tokenResponse.Key); + await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key); // User doesn't have a key pair yet (old account), let's generate one for them. if (tokenResponse.PrivateKey == null) @@ -511,13 +511,16 @@ namespace Bit.Core.Services { // SSO Key Connector Onboarding var password = await _cryptoFunctionService.RandomBytesAsync(64); - var masterKey = await _cryptoService.MakeMasterKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig); - var keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.EncKeyB64); - await _cryptoService.SetKeyAsync(masterKey); + var newMasterKey = await _cryptoService.MakeMasterKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig); + var keyConnectorRequest = new KeyConnectorUserKeyRequest(newMasterKey.EncKeyB64); + await _cryptoService.SetMasterKeyAsync(newMasterKey); - var encKey = await _cryptoService.MakeEncKeyAsync(masterKey); - await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); - var keyPair = await _cryptoService.MakeKeyPairAsync(); + var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync( + newMasterKey, + await _cryptoService.MakeUserKeyAsync()); + + await _cryptoService.SetUserKeyAsync(newUserKey); + var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(); try { @@ -530,11 +533,11 @@ namespace Bit.Core.Services var keys = new KeysRequest { - PublicKey = keyPair.Item1, - EncryptedPrivateKey = keyPair.Item2.EncryptedString + PublicKey = newPublicKey, + EncryptedPrivateKey = newProtectedPrivateKey.EncryptedString }; var setPasswordRequest = new SetKeyConnectorKeyRequest( - encKey.Item2.EncryptedString, keys, tokenResponse.KdfConfig, orgId + newProtectedPrivateKey.EncryptedString, keys, tokenResponse.KdfConfig, orgId ); await _apiService.PostSetKeyConnectorKey(setPasswordRequest); } @@ -549,7 +552,7 @@ namespace Bit.Core.Services private void ClearState() { - _key = null; + _masterKey = null; Email = null; CaptchaToken = null; MasterPasswordHash = null; @@ -590,7 +593,7 @@ namespace Bit.Core.Services public async Task PasswordlessLoginAsync(string id, string pubKey, bool requestApproved) { var publicKey = CoreHelpers.Base64UrlDecode(pubKey); - var masterKey = await _cryptoService.GetKeyAsync(); + var masterKey = await _cryptoService.GetMasterKeyAsync(); var encryptedKey = await _cryptoService.RsaEncryptAsync(masterKey.EncKey, publicKey); var encryptedMasterPassword = await _cryptoService.RsaEncryptAsync(Encoding.UTF8.GetBytes(await _stateService.GetKeyHashAsync()), publicKey); var deviceId = await _appIdService.GetAppIdAsync(); diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index 4b31303f4..db785de01 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -36,6 +36,16 @@ namespace Bit.Core.Services _cryptoFunctionService = cryptoFunctionService; } + public void ClearCache() + { + _encKey = null; + _legacyEtmKey = null; + _passwordHash = null; + _publicKey = null; + _privateKey = null; + _orgKeys = null; + } + public async Task ToggleKeysAsync() { // refresh or clear the pin key @@ -216,7 +226,7 @@ namespace Bit.Core.Services { if (key == null) { - key = await GetKeyAsync(); + key = await GetMasterKeyAsync(); } if (password == null || key == null) { @@ -806,20 +816,6 @@ namespace Bit.Core.Services } - private async Task GetKeyForEncryptionAsync(SymmetricCryptoKey key = null) - { - if (key != null) - { - return key; - } - var encKey = await GetEncKeyAsync(); - if (encKey != null) - { - return encKey; - } - return await GetKeyAsync(); - } - private SymmetricCryptoKey ResolveLegacyKey(EncryptionType encKey, SymmetricCryptoKey key) { if (encKey == EncryptionType.AesCbc128_HmacSha256_B64 && key.EncType == EncryptionType.AesCbc256_B64) @@ -995,165 +991,5 @@ namespace Bit.Core.Services await _stateService.SetPinProtectedAsync(null); await _stateService.SetPinProtectedKeyAsync(null); } - - - - - - - - - - - - - - - - - - - - - - - - - - - - public async Task SetKeyAsync(SymmetricCryptoKey key) - { - await _stateService.SetKeyDecryptedAsync(key); - var option = await _stateService.GetVaultTimeoutAsync(); - var biometric = await _stateService.GetBiometricUnlockAsync(); - if (option.HasValue && !biometric.GetValueOrDefault()) - { - // If we have a lock option set, we do not store the key - return; - } - await _stateService.SetKeyEncryptedAsync(key?.KeyB64); - } - - - public async Task SetEncKeyAsync(string encKey) - { - if (encKey == null) - { - return; - } - await _stateService.SetEncKeyEncryptedAsync(encKey); - _encKey = null; - } - - - - public async Task GetKeyAsync(string userId = null) - { - var inMemoryKey = await _stateService.GetKeyDecryptedAsync(userId); - if (inMemoryKey != null) - { - return inMemoryKey; - } - var key = await _stateService.GetKeyEncryptedAsync(userId); - if (key != null) - { - inMemoryKey = new SymmetricCryptoKey(Convert.FromBase64String(key)); - await _stateService.SetKeyDecryptedAsync(inMemoryKey, userId); - } - return inMemoryKey; - } - - - public Task GetEncKeyAsync(SymmetricCryptoKey key = null) - { - if (_encKey != null) - { - return Task.FromResult(_encKey); - } - if (_getEncKeysTask != null && !_getEncKeysTask.IsCompleted && !_getEncKeysTask.IsFaulted) - { - return _getEncKeysTask; - } - async Task doTask() - { - try - { - var encKey = await _stateService.GetEncKeyEncryptedAsync(); - if (encKey == null) - { - return null; - } - - if (key == null) - { - key = await GetKeyAsync(); - } - if (key == null) - { - return null; - } - - byte[] decEncKey = null; - var encKeyCipher = new EncString(encKey); - if (encKeyCipher.EncryptionType == EncryptionType.AesCbc256_B64) - { - decEncKey = await DecryptToBytesAsync(encKeyCipher, key); - } - else if (encKeyCipher.EncryptionType == EncryptionType.AesCbc256_HmacSha256_B64) - { - var newKey = await StretchKeyAsync(key); - decEncKey = await DecryptToBytesAsync(encKeyCipher, newKey); - } - else - { - throw new Exception("Unsupported encKey type."); - } - - if (decEncKey == null) - { - return null; - } - _encKey = new SymmetricCryptoKey(decEncKey); - return _encKey; - } - finally - { - _getEncKeysTask = null; - } - } - _getEncKeysTask = doTask(); - return _getEncKeysTask; - } - - - - - - - - - - - public void ClearCache() - { - _encKey = null; - _legacyEtmKey = null; - _passwordHash = null; - _publicKey = null; - _privateKey = null; - _orgKeys = null; - } - - - - - public async Task> MakeEncKeyAsync(SymmetricCryptoKey key) - { - var theKey = await GetKeyForEncryptionAsync(key); - var encKey = await _cryptoFunctionService.RandomBytesAsync(64); - return await BuildProtectedSymmetricKey(theKey, encKey); - } - } }