diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index 458d25c4f..81a696984 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -295,19 +295,19 @@ namespace Bit.App.Pages } else { - var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig); + var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig); var storedKeyHash = await _cryptoService.GetPasswordHashAsync(); var passwordValid = false; MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null; if (storedKeyHash != null) { - passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, key); + passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, masterKey); } else { await _deviceActionService.ShowLoadingAsync(AppResources.Loading); - var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization); + var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization); var request = new PasswordVerificationRequest(); request.MasterPasswordHash = keyHash; @@ -316,7 +316,7 @@ namespace Bit.App.Pages var response = await _apiService.PostAccountVerifyPasswordAsync(request); enforcedMasterPasswordOptions = response.MasterPasswordPolicy; passwordValid = true; - var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization); + var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization); await _cryptoService.SetPasswordHashAsync(localKeyHash); } catch (Exception e) @@ -327,13 +327,14 @@ namespace Bit.App.Pages } if (passwordValid) { + // TODO(Jake): Update this to use new PinKeyEphemeral if (_isPinProtected) { var protectedPin = await _stateService.GetProtectedPinAsync(); - var encKey = await _cryptoService.GetEncKeyAsync(key); + var encKey = await _cryptoService.GetEncKeyAsync(masterKey); var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey); var pinKey = await _cryptoService.MakePinKeyAsync(decPin, _email, kdfConfig); - await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey)); + await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(masterKey.Key, pinKey)); } if (await RequirePasswordChangeAsync(enforcedMasterPasswordOptions)) @@ -345,7 +346,7 @@ namespace Bit.App.Pages MasterPassword = string.Empty; await AppHelpers.ResetInvalidUnlockAttemptsAsync(); - await SetKeyAndContinueAsync(key); + await SetKeyAndContinueAsync(masterKey); // Re-enable biometrics if (BiometricLock & !BiometricIntegrityValid) @@ -447,6 +448,7 @@ namespace Bit.App.Pages } } + // TODO(Jake): Update to store UserKey private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key) { var hasKey = await _cryptoService.HasKeyAsync(); diff --git a/src/App/Pages/Accounts/RegisterPageViewModel.cs b/src/App/Pages/Accounts/RegisterPageViewModel.cs index ebfc522c1..d7df5e75f 100644 --- a/src/App/Pages/Accounts/RegisterPageViewModel.cs +++ b/src/App/Pages/Accounts/RegisterPageViewModel.cs @@ -177,9 +177,9 @@ namespace Bit.App.Pages Name = string.IsNullOrWhiteSpace(Name) ? null : Name; Email = Email.Trim().ToLower(); var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null); - var key = await _cryptoService.MakeKeyAsync(MasterPassword, Email, kdfConfig); - var encKey = await _cryptoService.MakeEncKeyAsync(key); - var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, key); + var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, Email, kdfConfig); + var encKey = await _cryptoService.MakeEncKeyAsync(masterKey); + var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey); var keys = await _cryptoService.MakeKeyPairAsync(encKey.Item1); var request = new RegisterRequest { diff --git a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs index f2d217a5d..67c69344a 100644 --- a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs @@ -165,19 +165,19 @@ namespace Bit.App.Pages var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null); var email = await _stateService.GetEmailAsync(); - var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdfConfig); - var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization); - var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization); + var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); + var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization); + var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization); Tuple encKey; var existingEncKey = await _cryptoService.GetEncKeyAsync(); if (existingEncKey == null) { - encKey = await _cryptoService.MakeEncKeyAsync(key); + encKey = await _cryptoService.MakeEncKeyAsync(masterKey); } else { - encKey = await _cryptoService.RemakeEncKeyAsync(key); + encKey = await _cryptoService.RemakeEncKeyAsync(masterKey); } var keys = await _cryptoService.MakeKeyPairAsync(encKey.Item1); @@ -204,7 +204,7 @@ namespace Bit.App.Pages // Set Password and relevant information await _apiService.SetPasswordAsync(request); await _stateService.SetKdfConfigurationAsync(kdfConfig); - await _cryptoService.SetKeyAsync(key); + await _cryptoService.SetKeyAsync(masterKey); await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash); await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString); diff --git a/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs b/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs index daf4b2dbe..a6de632ca 100644 --- a/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs @@ -93,12 +93,12 @@ namespace Bit.App.Pages var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile)); var email = await _stateService.GetEmailAsync(); - // Create new key and hash new password - var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdfConfig); - var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key); + // Create new master key and hash new password + var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); + var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey); // Create new encKey for the User - var newEncKey = await _cryptoService.RemakeEncKeyAsync(key); + var newEncKey = await _cryptoService.RemakeEncKeyAsync(masterKey); // Initiate API action try diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 99e11a629..f20034cd7 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -69,7 +69,6 @@ namespace Bit.Core.Abstractions Task HasEncKeyAsync(); Task HasKeyAsync(string userId = null); Task> MakeEncKeyAsync(SymmetricCryptoKey key); - Task MakeKeyAsync(string password, string salt, KdfConfig config); Task MakeKeyFromPinAsync(string pin, string salt, KdfConfig config, EncString protectedKeyEs = null); // TODO(Jake): This isn't used, delete Task> MakeShareKeyAsync(); diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index f66a93f21..9ff525c40 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -356,7 +356,7 @@ namespace Bit.Core.Services throw; } } - return await _cryptoService.MakeKeyAsync(masterPassword, email, kdfConfig); + return await _cryptoService.MakeMasterKeyAsync(masterPassword, email, kdfConfig); } private async Task LogInHelperAsync(string email, string hashedPassword, string localHashedPassword, @@ -511,11 +511,11 @@ namespace Bit.Core.Services { // SSO Key Connector Onboarding var password = await _cryptoFunctionService.RandomBytesAsync(64); - var k = await _cryptoService.MakeKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig); - var keyConnectorRequest = new KeyConnectorUserKeyRequest(k.EncKeyB64); - await _cryptoService.SetKeyAsync(k); + var masterKey = await _cryptoService.MakeMasterKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig); + var keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.EncKeyB64); + await _cryptoService.SetKeyAsync(masterKey); - var encKey = await _cryptoService.MakeEncKeyAsync(k); + var encKey = await _cryptoService.MakeEncKeyAsync(masterKey); await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); var keyPair = await _cryptoService.MakeKeyPairAsync(); diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index f2da0299e..42fe83c32 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -843,6 +843,54 @@ namespace Bit.Core.Services return new Tuple(new SymmetricCryptoKey(encKey) as T, encKeyEnc); } + private async Task MakeKeyAsync(string password, string salt, KdfConfig kdfConfig) + { + byte[] key = null; + if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256) + { + var iterations = kdfConfig.Iterations.GetValueOrDefault(5000); + if (iterations < 5000) + { + throw new Exception("PBKDF2 iteration minimum is 5000."); + } + key = await _cryptoFunctionService.Pbkdf2Async(password, salt, + CryptoHashAlgorithm.Sha256, iterations); + } + else if (kdfConfig.Type == KdfType.Argon2id) + { + var iterations = kdfConfig.Iterations.GetValueOrDefault(Constants.Argon2Iterations); + var memory = kdfConfig.Memory.GetValueOrDefault(Constants.Argon2MemoryInMB) * 1024; + var parallelism = kdfConfig.Parallelism.GetValueOrDefault(Constants.Argon2Parallelism); + + if (kdfConfig.Iterations < 2) + { + throw new Exception("Argon2 iterations minimum is 2"); + } + + if (kdfConfig.Memory < 16) + { + throw new Exception("Argon2 memory minimum is 16 MB"); + } + else if (kdfConfig.Memory > 1024) + { + throw new Exception("Argon2 memory maximum is 1024 MB"); + } + + if (kdfConfig.Parallelism < 1) + { + throw new Exception("Argon2 parallelism minimum is 1"); + } + + var saltHash = await _cryptoFunctionService.HashAsync(salt, CryptoHashAlgorithm.Sha256); + key = await _cryptoFunctionService.Argon2Async(password, saltHash, iterations, memory, parallelism); + } + else + { + throw new Exception("Unknown kdf."); + } + return new SymmetricCryptoKey(key); + } + private class EncryptedObject { public byte[] Iv { get; set; } @@ -1049,53 +1097,6 @@ namespace Bit.Core.Services await SetKeyAsync(key); } - public async Task MakeKeyAsync(string password, string salt, KdfConfig kdfConfig) - { - byte[] key = null; - if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256) - { - var iterations = kdfConfig.Iterations.GetValueOrDefault(5000); - if (iterations < 5000) - { - throw new Exception("PBKDF2 iteration minimum is 5000."); - } - key = await _cryptoFunctionService.Pbkdf2Async(password, salt, - CryptoHashAlgorithm.Sha256, iterations); - } - else if (kdfConfig.Type == KdfType.Argon2id) - { - var iterations = kdfConfig.Iterations.GetValueOrDefault(Constants.Argon2Iterations); - var memory = kdfConfig.Memory.GetValueOrDefault(Constants.Argon2MemoryInMB) * 1024; - var parallelism = kdfConfig.Parallelism.GetValueOrDefault(Constants.Argon2Parallelism); - - if (kdfConfig.Iterations < 2) - { - throw new Exception("Argon2 iterations minimum is 2"); - } - - if (kdfConfig.Memory < 16) - { - throw new Exception("Argon2 memory minimum is 16 MB"); - } - else if (kdfConfig.Memory > 1024) - { - throw new Exception("Argon2 memory maximum is 1024 MB"); - } - - if (kdfConfig.Parallelism < 1) - { - throw new Exception("Argon2 parallelism minimum is 1"); - } - - var saltHash = await _cryptoFunctionService.HashAsync(salt, CryptoHashAlgorithm.Sha256); - key = await _cryptoFunctionService.Argon2Async(password, saltHash, iterations, memory, parallelism); - } - else - { - throw new Exception("Unknown kdf."); - } - return new SymmetricCryptoKey(key); - } public async Task MakeKeyFromPinAsync(string pin, string salt, KdfConfig config, EncString protectedKeyCs = null)