diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs index 09d81e10a..6b9137322 100644 --- a/src/App/Pages/Accounts/LockPageViewModel.cs +++ b/src/App/Pages/Accounts/LockPageViewModel.cs @@ -39,7 +39,7 @@ namespace Bit.App.Pages private string _masterPassword; private string _pin; private bool _showPassword; - private PinLockEnum _pinStatus; + private PinLockType _pinStatus; private bool _pinEnabled; private bool _biometricEnabled; private bool _biometricIntegrityValid = true; @@ -171,12 +171,12 @@ namespace Bit.App.Pages return; } - _pinStatus = await _vaultTimeoutService.IsPinLockSetAsync(); + _pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync(); - var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync() + var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync() ?? await _stateService.GetPinProtectedKeyAsync(); - PinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) || - _pinStatus == PinLockEnum.Persistent; + PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) || + _pinStatus == PinLockType.Persistent; BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync(); @@ -278,15 +278,15 @@ namespace Bit.App.Pages { EncString userKeyPin = null; EncString oldPinProtected = null; - if (_pinStatus == PinLockEnum.Persistent) + if (_pinStatus == PinLockType.Persistent) { - userKeyPin = await _stateService.GetUserKeyPinAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync(); var oldEncryptedKey = await _stateService.GetPinProtectedAsync(); oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null; } - else if (_pinStatus == PinLockEnum.Transient) + else if (_pinStatus == PinLockType.Transient) { - userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync(); oldPinProtected = await _stateService.GetPinProtectedKeyAsync(); } @@ -294,7 +294,7 @@ namespace Bit.App.Pages if (oldPinProtected != null) { userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync( - _pinStatus == PinLockEnum.Transient, + _pinStatus == PinLockType.Transient, Pin, _email, kdfConfig, @@ -340,20 +340,20 @@ namespace Bit.App.Pages else { var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig); - var storedKeyHash = await _cryptoService.GetPasswordHashAsync(); + var storedKeyHash = await _cryptoService.GetMasterKeyHashAsync(); var passwordValid = false; MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null; if (storedKeyHash != null) { // Offline unlock possible - passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, masterKey); + passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, masterKey); } else { // Online unlock required await _deviceActionService.ShowLoadingAsync(AppResources.Loading); - var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization); + var keyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization); var request = new PasswordVerificationRequest(); request.MasterPasswordHash = keyHash; @@ -362,8 +362,8 @@ namespace Bit.App.Pages var response = await _apiService.PostAccountVerifyPasswordAsync(request); enforcedMasterPasswordOptions = response.MasterPasswordPolicy; passwordValid = true; - var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization); - await _cryptoService.SetPasswordHashAsync(localKeyHash); + var localKeyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization); + await _cryptoService.SetMasterKeyHashAsync(localKeyHash); } catch (Exception e) { diff --git a/src/App/Pages/Accounts/RegisterPageViewModel.cs b/src/App/Pages/Accounts/RegisterPageViewModel.cs index b742a65ba..f69453bad 100644 --- a/src/App/Pages/Accounts/RegisterPageViewModel.cs +++ b/src/App/Pages/Accounts/RegisterPageViewModel.cs @@ -178,11 +178,8 @@ namespace Bit.App.Pages Email = Email.Trim().ToLower(); var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null); var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, Email, kdfConfig); - var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync( - newMasterKey, - await _cryptoService.MakeUserKeyAsync() - ); - var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey); + var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey); + var hashedPassword = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey); var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey); var request = new RegisterRequest { diff --git a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs index 57ffaac79..2f0966786 100644 --- a/src/App/Pages/Accounts/SetPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/SetPasswordPageViewModel.cs @@ -166,13 +166,12 @@ namespace Bit.App.Pages var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null); var email = await _stateService.GetEmailAsync(); var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); - var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization); - var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization); + var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization); + var localMasterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization); - var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey, - await _cryptoService.GetUserKeyAsync() ?? await _cryptoService.MakeUserKeyAsync()); + var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey); - var keys = await _cryptoService.MakeKeyPairAsync(newUserKey); + var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey); var request = new SetPasswordRequest { MasterPasswordHash = masterPasswordHash, @@ -185,8 +184,8 @@ namespace Bit.App.Pages OrgIdentifier = OrgIdentifier, Keys = new KeysRequest { - PublicKey = keys.Item1, - EncryptedPrivateKey = keys.Item2.EncryptedString + PublicKey = newPublicKey, + EncryptedPrivateKey = newProtectedPrivateKey.EncryptedString } }; @@ -196,10 +195,11 @@ namespace Bit.App.Pages // Set Password and relevant information await _apiService.SetPasswordAsync(request); await _stateService.SetKdfConfigurationAsync(kdfConfig); + await _cryptoService.SetUserKeyAsync(newUserKey); await _cryptoService.SetMasterKeyAsync(newMasterKey); - await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash); + await _cryptoService.SetMasterKeyHashAsync(localMasterPasswordHash); await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(newProtectedUserKey.EncryptedString); - await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString); + await _cryptoService.SetUserPrivateKeyAsync(newProtectedPrivateKey.EncryptedString); if (ResetPasswordAutoEnroll) { diff --git a/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs b/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs index 7d8ec85f0..941736f08 100644 --- a/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs +++ b/src/App/Pages/Accounts/UpdateTempPasswordPageViewModel.cs @@ -95,7 +95,7 @@ namespace Bit.App.Pages // Create new master key and hash new password var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig); - var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey); + var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey); // Encrypt user key with new master key var (userKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(masterKey); @@ -155,7 +155,7 @@ namespace Bit.App.Pages private async Task UpdatePasswordAsync(string newMasterPasswordHash, string newEncKey) { - var currentPasswordHash = await _cryptoService.HashPasswordAsync(CurrentMasterPassword, null); + var currentPasswordHash = await _cryptoService.HashMasterKeyAsync(CurrentMasterPassword, null); var request = new PasswordRequest { diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs index c0cd8cc27..5a2f1c827 100644 --- a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs +++ b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs @@ -150,8 +150,8 @@ namespace Bit.App.Pages t.Value != null).ToList(); } - var pinSet = await _vaultTimeoutService.IsPinLockSetAsync(); - _pin = pinSet != PinLockEnum.Disabled; + var pinSet = await _vaultTimeoutService.GetPinLockTypeAsync(); + _pin = pinSet != PinLockType.Disabled; _biometric = await _vaultTimeoutService.IsBiometricLockSetAsync(); _screenCaptureAllowed = await _stateService.GetScreenCaptureAllowedAsync(); @@ -335,6 +335,7 @@ namespace Bit.App.Pages } if (oldTimeout != newTimeout) { + await _cryptoService.RefreshKeysAsync(); await Device.InvokeOnMainThreadAsync(BuildList); } } @@ -454,18 +455,18 @@ namespace Bit.App.Pages var email = await _stateService.GetEmailAsync(); var pinKey = await _cryptoService.MakePinKeyAsync(pin, email, kdfConfig); var userKey = await _cryptoService.GetUserKeyAsync(); - var pinProtectedKey = await _cryptoService.EncryptAsync(userKey.Key, pinKey); + var protectedPinKey = await _cryptoService.EncryptAsync(userKey.Key, pinKey); var encPin = await _cryptoService.EncryptAsync(pin); await _stateService.SetProtectedPinAsync(encPin.EncryptedString); if (masterPassOnRestart) { - await _stateService.SetUserKeyPinEphemeralAsync(pinProtectedKey); + await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(protectedPinKey); } else { - await _stateService.SetUserKeyPinAsync(pinProtectedKey); + await _stateService.SetPinKeyEncryptedUserKeyAsync(protectedPinKey); } } else @@ -507,7 +508,7 @@ namespace Bit.App.Pages await UpdateVaultTimeoutActionIfNeededAsync(); } await _stateService.SetBiometricLockedAsync(false); - await _cryptoService.ToggleKeysAsync(); + await _cryptoService.RefreshKeysAsync(); BuildList(); } diff --git a/src/App/Services/MobilePasswordRepromptService.cs b/src/App/Services/MobilePasswordRepromptService.cs index 460e9df58..28a8e5a86 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.CompareAndUpdatePasswordHashAsync(password, null); + return await _cryptoService.CompareAndUpdateKeyHashAsync(password, null); } public async Task Enabled() diff --git a/src/App/Utilities/AccountManagement/AccountsManager.cs b/src/App/Utilities/AccountManagement/AccountsManager.cs index 919070359..6fffba58c 100644 --- a/src/App/Utilities/AccountManagement/AccountsManager.cs +++ b/src/App/Utilities/AccountManagement/AccountsManager.cs @@ -206,6 +206,7 @@ namespace Bit.App.Utilities.AccountManagement private async Task AddAccountAsync() { + await AppHelpers.ClearServiceCacheAsync(); await Device.InvokeOnMainThreadAsync(() => { Options.HideAccountSwitcher = false; diff --git a/src/App/Utilities/VerificationActionsFlowHelper.cs b/src/App/Utilities/VerificationActionsFlowHelper.cs index eaf3376e9..febaf798d 100644 --- a/src/App/Utilities/VerificationActionsFlowHelper.cs +++ b/src/App/Utilities/VerificationActionsFlowHelper.cs @@ -121,7 +121,7 @@ namespace Bit.App.Utilities } var parameters = GetParameters(); - parameters.Secret = await _cryptoService.HashPasswordAsync(password, null); + parameters.Secret = await _cryptoService.HashMasterKeyAsync(password, null); parameters.VerificationType = VerificationType.MasterPassword; await ExecuteAsync(parameters); break; diff --git a/src/Core/Abstractions/ICryptoService.cs b/src/Core/Abstractions/ICryptoService.cs index 3a388172a..b7d03df2d 100644 --- a/src/Core/Abstractions/ICryptoService.cs +++ b/src/Core/Abstractions/ICryptoService.cs @@ -10,7 +10,7 @@ namespace Bit.Core.Abstractions public interface ICryptoService { void ClearCache(); - Task ToggleKeysAsync(); + Task RefreshKeysAsync(); Task SetUserKeyAsync(UserKey userKey, string userId = null); Task GetUserKeyAsync(string userId = null); Task GetUserKeyWithLegacySupportAsync(string userId = null); @@ -19,26 +19,27 @@ namespace Bit.Core.Abstractions Task MakeUserKeyAsync(); Task ClearUserKeyAsync(string userId = null); Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null); + Task GetAutoUnlockKeyAsync(string userId = null); + Task HasAutoUnlockKeyAsync(string userId = null); Task SetMasterKeyAsync(MasterKey masterKey, string userId = null); Task GetMasterKeyAsync(string userId = null); Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig); Task ClearMasterKeyAsync(string userId = null); - Task> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null); + Task> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey); Task DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null); - Task> MakeDataEncKeyAsync(UserKey key); - Task> MakeDataEncKeyAsync(OrgKey key); - Task HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization); - Task SetPasswordHashAsync(string keyHash); - Task GetPasswordHashAsync(); - Task ClearPasswordHashAsync(string userId = null); - Task CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key); + Task> MakeDataEncKeyAsync(SymmetricCryptoKey key); + Task HashMasterKeyAsync(string password, MasterKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization); + Task SetMasterKeyHashAsync(string keyHash); + Task GetMasterKeyHashAsync(); + Task ClearMasterKeyHashAsync(string userId = null); + Task CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key); Task SetOrgKeysAsync(IEnumerable orgs); Task GetOrgKeyAsync(string orgId); Task> GetOrgKeysAsync(); Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null); - Task GetPublicKeyAsync(); - Task SetPrivateKeyAsync(string encPrivateKey); - Task GetPrivateKeyAsync(); + Task GetUserPublicKeyAsync(); + Task SetUserPrivateKeyAsync(string encPrivateKey); + Task GetUserPrivateKeyAsync(); Task> GetFingerprintAsync(string userId, byte[] publicKey = null); Task> MakeKeyPairAsync(SymmetricCryptoKey key = null); Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null); diff --git a/src/Core/Abstractions/IStateService.cs b/src/Core/Abstractions/IStateService.cs index 12a2f80d3..5815a883f 100644 --- a/src/Core/Abstractions/IStateService.cs +++ b/src/Core/Abstractions/IStateService.cs @@ -17,8 +17,10 @@ namespace Bit.Core.Abstractions Task SetUserKeyAsync(UserKey value, string userId = null); Task GetMasterKeyAsync(string userId = null); Task SetMasterKeyAsync(MasterKey value, string userId = null); - Task GetUserKeyMasterKeyAsync(string userId = null); - Task SetUserKeyMasterKeyAsync(string value, string userId = null); + Task GetMasterKeyEncryptedUserKeyAsync(string userId = null); + Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null); + Task GetUserKeyAutoUnlockAsync(string userId = null); + Task SetUserKeyAutoUnlockAsync(string value, string userId = null); Task GetActiveUserIdAsync(); Task GetActiveUserEmailAsync(); Task GetActiveUserCustomDataAsync(Func dataMapper); @@ -44,19 +46,11 @@ namespace Bit.Core.Abstractions Task CanAccessPremiumAsync(string userId = null); Task GetProtectedPinAsync(string userId = null); Task SetPersonalPremiumAsync(bool value, string userId = null); - Task GetUserKeyPinAsync(string userId = null); - Task SetUserKeyPinAsync(EncString value, string userId = null); - Task GetUserKeyPinEphemeralAsync(string userId = null); - Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null); + Task GetPinKeyEncryptedUserKeyAsync(string userId = null); + Task SetPinKeyEncryptedUserKeyAsync(EncString value, string userId = null); + Task GetPinKeyEncryptedUserKeyEphemeralAsync(string userId = null); + Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null); Task SetProtectedPinAsync(string value, string userId = null); - [Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")] - Task GetPinProtectedAsync(string userId = null); - [Obsolete("Use SetUserKeyPinAsync instead")] - Task SetPinProtectedAsync(string value, string userId = null); - [Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")] - Task GetPinProtectedKeyAsync(string userId = null); - [Obsolete("Use SetUserKeyPinEphemeralAsync instead")] - Task SetPinProtectedKeyAsync(EncString value, string userId = null); Task SetKdfConfigurationAsync(KdfConfig config, string userId = null); Task GetKeyHashAsync(string userId = null); Task SetKeyHashAsync(string value, string userId = null); @@ -191,17 +185,24 @@ namespace Bit.Core.Abstractions void SetConfigs(ConfigResponse value); Task GetShouldTrustDeviceAsync(); Task SetShouldTrustDeviceAsync(bool value); - [Obsolete("Use GetUserKeyMasterKey instead")] + [Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")] + Task GetPinProtectedAsync(string userId = null); + [Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")] + Task SetPinProtectedAsync(string value, string userId = null); + [Obsolete("Use GetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")] + Task GetPinProtectedKeyAsync(string userId = null); + [Obsolete("Use SetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")] + Task SetPinProtectedKeyAsync(EncString value, string userId = null); + [Obsolete("Use GetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")] Task GetEncKeyEncryptedAsync(string userId = null); - [Obsolete("Use SetUserKeyMasterKey instead")] + [Obsolete("Use SetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")] Task SetEncKeyEncryptedAsync(string value, string userId = null); - [Obsolete] - Task GetKeyEncryptedAsync(string userId = null); - [Obsolete] + [Obsolete("Left for migration purposes")] Task SetKeyEncryptedAsync(string value, string userId = null); - [Obsolete("Use GetMasterKey instead")] + + [Obsolete("Use GetUserKeyAutoUnlock instead, left for migration purposes")] + Task GetKeyEncryptedAsync(string userId = null); + [Obsolete("Use GetMasterKeyAsync instead, left for migration purposes")] Task GetKeyDecryptedAsync(string userId = null); - [Obsolete("Use GetMasterKey instead")] - Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null); } } diff --git a/src/Core/Abstractions/IVaultTimeoutService.cs b/src/Core/Abstractions/IVaultTimeoutService.cs index 529806983..2c1f9598d 100644 --- a/src/Core/Abstractions/IVaultTimeoutService.cs +++ b/src/Core/Abstractions/IVaultTimeoutService.cs @@ -17,7 +17,7 @@ namespace Bit.Core.Abstractions Task ShouldLockAsync(string userId = null); Task IsLoggedOutByTimeoutAsync(string userId = null); Task ShouldLogOutByTimeoutAsync(string userId = null); - Task IsPinLockSetAsync(string userId = null); + Task GetPinLockTypeAsync(string userId = null); Task IsBiometricLockSetAsync(string userId = null); Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null); Task LogOutAsync(bool userInitiated = true, string userId = null); diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index e8bf08ed1..3c0b4fceb 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -85,7 +85,8 @@ namespace Bit.Core public static string VaultTimeoutKey(string userId) => $"vaultTimeout_{userId}"; public static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}"; - public static string UserKeyKey(string userId) => $"userKey_{userId}"; + public static string MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}"; + public static string UserKeyAutoUnlockKey(string userId) => $"autoUnlock_{userId}"; public static string CiphersKey(string userId) => $"ciphers_{userId}"; public static string FoldersKey(string userId) => $"folders_{userId}"; public static string CollectionsKey(string userId) => $"collections_{userId}"; @@ -98,7 +99,7 @@ namespace Bit.Core public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}"; public static string DeviceKeyKey(string userId) => $"deviceKey_{userId}"; public static string KeyHashKey(string userId) => $"keyHash_{userId}"; - public static string UserKeyPinKey(string userId) => $"userKeyPin_{userId}"; + public static string PinKeyEncryptedUserKeyKey(string userId) => $"pinKeyEncryptedUserKey_{userId}"; public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}"; public static string PassGenHistoryKey(string userId) => $"generatedPasswordHistory_{userId}"; public static string TwoFactorTokenKey(string email) => $"twoFactorToken_{email}"; diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index 8e3ffb08a..5e1248702 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -151,8 +151,8 @@ namespace Bit.Core.Services SelectedTwoFactorProviderType = null; _2faForcePasswordResetReason = null; var key = await MakePreloginKeyAsync(masterPassword, email); - var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key); - var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); + var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key); + var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization); var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken); if (await RequirePasswordChangeAsync(email, masterPassword)) @@ -265,8 +265,8 @@ namespace Bit.Core.Services { SelectedTwoFactorProviderType = null; var key = await MakePreloginKeyAsync(masterPassword, email); - var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key); - var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); + var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key); + var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization); return await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, twoFactorProvider, twoFactorToken, remember); } @@ -502,7 +502,7 @@ namespace Bit.Core.Services { if (localHashedPassword != null) { - await _cryptoService.SetPasswordHashAsync(localHashedPassword); + await _cryptoService.SetMasterKeyHashAsync(localHashedPassword); await _cryptoService.SetMasterKeyAsync(masterKey); var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey); await _cryptoService.SetUserKeyAsync(userKey); @@ -558,7 +558,7 @@ namespace Bit.Core.Services catch { } } - await _cryptoService.SetPrivateKeyAsync(tokenResponse.PrivateKey); + await _cryptoService.SetUserPrivateKeyAsync(tokenResponse.PrivateKey); } else if (tokenResponse.KeyConnectorUrl != null) { diff --git a/src/Core/Services/CipherService.cs b/src/Core/Services/CipherService.cs index 76820f424..b03ab1d17 100644 --- a/src/Core/Services/CipherService.cs +++ b/src/Core/Services/CipherService.cs @@ -250,8 +250,7 @@ namespace Bit.Core.Services { try { - var hashKey = await _cryptoService.HasUserKeyAsync(); - if (!hashKey) + if (!await _cryptoService.HasUserKeyAsync()) { throw new Exception("No key."); } @@ -591,20 +590,9 @@ namespace Bit.Core.Services public async Task SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data) { - SymmetricCryptoKey attachmentKey; - EncString protectedAttachmentKey; - var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId); - if (orgKey != null) - { - (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey); - } - else - { - var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync(); - (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey); - } + var (attachmentKey, protectedAttachmentKey, encKey) = await MakeAttachmentKeyAsync(cipher.OrganizationId); - var encFileName = await _cryptoService.EncryptAsync(filename, orgKey); + var encFileName = await _cryptoService.EncryptAsync(filename, encKey); var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey); CipherResponse response; @@ -841,6 +829,14 @@ namespace Bit.Core.Services // Helpers + private async Task> MakeAttachmentKeyAsync(string organizationId) + { + var encryptionKey = await _cryptoService.GetOrgKeyAsync(organizationId) + ?? (SymmetricCryptoKey)await _cryptoService.GetUserKeyWithLegacySupportAsync(); + var (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(encryptionKey); + return new Tuple(attachmentKey, protectedAttachmentKey, encryptionKey); + } + private async Task ShareAttachmentWithServerAsync(AttachmentView attachmentView, string cipherId, string organizationId) { @@ -853,20 +849,9 @@ namespace Bit.Core.Services var bytes = await attachmentResponse.Content.ReadAsByteArrayAsync(); var decBytes = await _cryptoService.DecryptFromBytesAsync(bytes, null); - SymmetricCryptoKey attachmentKey; - EncString protectedAttachmentKey; - var orgKey = await _cryptoService.GetOrgKeyAsync(organizationId); - if (orgKey != null) - { - (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey); - } - else - { - var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync(); - (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey); - } + var (attachmentKey, protectedAttachmentKey, encKey) = await MakeAttachmentKeyAsync(organizationId); - var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, orgKey); + var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, encKey); var encFileData = await _cryptoService.EncryptToBytesAsync(decBytes, attachmentKey); var boundary = string.Concat("--BWMobileFormBoundary", DateTime.UtcNow.Ticks); diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index 2a314c119..e0eaa8e8f 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -20,7 +20,7 @@ namespace Bit.Core.Services private readonly ICryptoFunctionService _cryptoFunctionService; private SymmetricCryptoKey _legacyEtmKey; - private string _passwordHash; + private string _masterKeyHash; private byte[] _publicKey; private byte[] _privateKey; private Dictionary _orgKeys; @@ -37,42 +37,28 @@ namespace Bit.Core.Services public void ClearCache() { _legacyEtmKey = null; - _passwordHash = null; + _masterKeyHash = null; _publicKey = null; _privateKey = null; _orgKeys = null; } - public async Task ToggleKeysAsync() + public async Task RefreshKeysAsync() { - // refresh or clear the pin key + // Refresh or clear additional keys such as + // pin and auto unlock keys 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); - - // Refresh the Pin Key if the user has a Pin set - if (await _stateService.GetProtectedPinAsync(userId) != null) - { - await StorePinKey(userKey, userId); - } - else - { - await _stateService.SetUserKeyPinAsync(null, userId); - await _stateService.SetUserKeyPinEphemeralAsync(null, userId); - } + await StoreAdditionalKeysAsync(userKey, userId); } - public async Task GetUserKeyAsync(string userId = null) + public Task GetUserKeyAsync(string userId = null) { - return await _stateService.GetUserKeyAsync(userId); + return _stateService.GetUserKeyAsync(userId); } public async Task GetUserKeyWithLegacySupportAsync(string userId = null) @@ -85,7 +71,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 GetMasterKeyAsync() as UserKey; + return new UserKey((await GetMasterKeyAsync()).Key); } public async Task HasUserKeyAsync(string userId = null) @@ -95,7 +81,7 @@ namespace Bit.Core.Services public async Task HasEncryptedUserKeyAsync(string userId = null) { - return await _stateService.GetUserKeyMasterKeyAsync(userId) != null; + return await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId) != null; } public async Task MakeUserKeyAsync() @@ -103,20 +89,30 @@ namespace Bit.Core.Services return new UserKey(await _cryptoFunctionService.RandomBytesAsync(64)); } - public async Task ClearUserKeyAsync(string userId = null) + public Task ClearUserKeyAsync(string userId = null) { - await _stateService.SetUserKeyAsync(null, userId); + return _stateService.SetUserKeyAsync(null, userId); } - public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) + public Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) { - await _stateService.SetUserKeyMasterKeyAsync(value, userId); + return _stateService.SetMasterKeyEncryptedUserKeyAsync(value, userId); } - public async Task SetMasterKeyAsync(MasterKey masterKey, string userId = null) + public async Task GetAutoUnlockKeyAsync(string userId = null) { - await _stateService.SetMasterKeyAsync(masterKey, userId); + await MigrateAutoUnlockKeyIfNeededAsync(userId); + return await _stateService.GetUserKeyAutoUnlockAsync(userId); + } + public async Task HasAutoUnlockKeyAsync(string userId = null) + { + return await GetAutoUnlockKeyAsync(userId) != null; + } + + public Task SetMasterKeyAsync(MasterKey masterKey, string userId = null) + { + return _stateService.SetMasterKeyAsync(masterKey, userId); } public async Task GetMasterKeyAsync(string userId = null) @@ -125,7 +121,7 @@ namespace Bit.Core.Services if (masterKey == null) { // Migration support - masterKey = await _stateService.GetKeyDecryptedAsync(userId) as MasterKey; + masterKey = new MasterKey((await _stateService.GetKeyDecryptedAsync(userId)).Key); if (masterKey != null) { await SetMasterKeyAsync(masterKey, userId); @@ -134,20 +130,20 @@ namespace Bit.Core.Services return masterKey; } - public async Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig) + public Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig) { - return await MakeKeyAsync(password, email, kdfConfig, keyBytes => new MasterKey(keyBytes)); + return MakeKeyAsync(password, email, kdfConfig, keyBytes => new MasterKey(keyBytes)); } - public async Task ClearMasterKeyAsync(string userId = null) + public Task ClearMasterKeyAsync(string userId = null) { - await _stateService.SetMasterKeyAsync(null, userId); + return _stateService.SetMasterKeyAsync(null, userId); } - public async Task> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null) + public async Task> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey) { - userKey ??= await GetUserKeyAsync(); - return await BuildProtectedSymmetricKey(masterKey, userKey.Key); + var userKey = await GetUserKeyAsync() ?? await MakeUserKeyAsync(); + return await BuildProtectedSymmetricKey(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes)); } public async Task DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null) @@ -160,7 +156,7 @@ namespace Bit.Core.Services if (encUserKey == null) { - var userKeyMasterKey = await _stateService.GetUserKeyMasterKeyAsync(userId); + var userKeyMasterKey = await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId); if (userKeyMasterKey == null) { throw new Exception("No encrypted user key found"); @@ -175,12 +171,12 @@ namespace Bit.Core.Services } else if (encUserKey.EncryptionType == EncryptionType.AesCbc256_HmacSha256_B64) { - var newKey = await StretchKeyAsync(masterKey); + var newKey = await StretchKeyAsync(masterKey, keyBytes => new MasterKey(keyBytes)); decUserKey = await DecryptToBytesAsync(encUserKey, newKey); } else { - throw new Exception("Unsupported encKey type."); + throw new Exception($"Unsupported encrypted user key type: {encUserKey.EncryptionType}"); } if (decUserKey == null) @@ -190,86 +186,82 @@ namespace Bit.Core.Services return new UserKey(decUserKey); } - public async Task> MakeDataEncKeyAsync(UserKey key) + public async Task> MakeDataEncKeyAsync(SymmetricCryptoKey key) { - if (key == null) + if (key is null) { - throw new Exception("No user key provided"); + throw new ArgumentNullException(nameof(key)); + } + if (!(key is UserKey) && !(key is OrgKey)) + { + throw new ArgumentException($"Data encryption keys must be of type UserKey or OrgKey. {key.GetType().FullName} unsupported."); } var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64); - return await BuildProtectedSymmetricKey(key, newSymKey); + return await BuildProtectedSymmetricKey(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes)); } - public async Task> MakeDataEncKeyAsync(OrgKey key) + public async Task HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization) { - if (key == null) + if (password is null) { - throw new Exception("No org key provided"); + throw new ArgumentNullException(nameof(password)); } - var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64); - return await BuildProtectedSymmetricKey(key, newSymKey); - } + if (masterKey is null) + { + masterKey = await GetMasterKeyAsync(); - // TODO(Jake): Uses Master Key - public async Task HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization) - { - if (key == null) - { - key = await GetMasterKeyAsync(); + if (masterKey is null) + { + throw new ArgumentNullException(nameof(masterKey)); + } } - if (password == null || key == null) - { - throw new Exception("Invalid parameters."); - } - var iterations = hashPurpose == HashPurpose.LocalAuthorization ? 2 : 1; - var hash = await _cryptoFunctionService.Pbkdf2Async(key.Key, password, CryptoHashAlgorithm.Sha256, iterations); + var hash = await _cryptoFunctionService.Pbkdf2Async(masterKey.Key, password, CryptoHashAlgorithm.Sha256, (int)hashPurpose); return Convert.ToBase64String(hash); } - public async Task SetPasswordHashAsync(string keyHash) + public Task SetMasterKeyHashAsync(string keyHash) { - _passwordHash = keyHash; - await _stateService.SetKeyHashAsync(keyHash); + _masterKeyHash = keyHash; + return _stateService.SetKeyHashAsync(keyHash); } - public async Task GetPasswordHashAsync() + public async Task GetMasterKeyHashAsync() { - if (_passwordHash != null) + if (_masterKeyHash != null) { - return _passwordHash; + return _masterKeyHash; } var passwordHash = await _stateService.GetKeyHashAsync(); if (passwordHash != null) { - _passwordHash = passwordHash; + _masterKeyHash = passwordHash; } - return _passwordHash; + return _masterKeyHash; } - public async Task ClearPasswordHashAsync(string userId = null) + public Task ClearMasterKeyHashAsync(string userId = null) { - _passwordHash = null; - await _stateService.SetKeyHashAsync(null, userId); + _masterKeyHash = null; + return _stateService.SetKeyHashAsync(null, userId); } - // TODO(Jake): Uses Master Key - public async Task CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key) + public async Task CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key) { - var storedPasswordHash = await GetPasswordHashAsync(); + var storedPasswordHash = await GetMasterKeyHashAsync(); if (masterPassword != null && storedPasswordHash != null) { - var localPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization); + var localPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization); if (localPasswordHash != null && storedPasswordHash == localPasswordHash) { return true; } - var serverPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.ServerAuthorization); - if (serverPasswordHash != null & storedPasswordHash == serverPasswordHash) + var serverPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.ServerAuthorization); + if (serverPasswordHash != null && storedPasswordHash == serverPasswordHash) { - await SetPasswordHashAsync(localPasswordHash); + await SetMasterKeyHashAsync(localPasswordHash); return true; } } @@ -277,11 +269,11 @@ namespace Bit.Core.Services return false; } - public async Task SetOrgKeysAsync(IEnumerable orgs) + public Task SetOrgKeysAsync(IEnumerable orgs) { var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key); _orgKeys = null; - await _stateService.SetOrgKeysEncryptedAsync(orgKeys); + return _stateService.SetOrgKeysEncryptedAsync(orgKeys); } public async Task GetOrgKeyAsync(string orgId) @@ -351,13 +343,13 @@ namespace Bit.Core.Services } } - public async Task GetPublicKeyAsync() + public async Task GetUserPublicKeyAsync() { if (_publicKey != null) { return _publicKey; } - var privateKey = await GetPrivateKeyAsync(); + var privateKey = await GetUserPrivateKeyAsync(); if (privateKey == null) { return null; @@ -366,7 +358,7 @@ namespace Bit.Core.Services return _publicKey; } - public async Task SetPrivateKeyAsync(string encPrivateKey) + public async Task SetUserPrivateKeyAsync(string encPrivateKey) { if (encPrivateKey == null) { @@ -376,7 +368,7 @@ namespace Bit.Core.Services _privateKey = null; } - public async Task GetPrivateKeyAsync() + public async Task GetUserPrivateKeyAsync() { if (_privateKey != null) { @@ -395,7 +387,7 @@ namespace Bit.Core.Services { if (publicKey == null) { - publicKey = await GetPublicKeyAsync(); + publicKey = await GetUserPublicKeyAsync(); } if (publicKey == null) { @@ -426,28 +418,29 @@ namespace Bit.Core.Services public async Task MakePinKeyAsync(string pin, string salt, KdfConfig config) { var pinKey = await MakeKeyAsync(pin, salt, config, keyBytes => new PinKey(keyBytes)); - return await StretchKeyAsync(pinKey) as PinKey; + return await StretchKeyAsync(pinKey, keyBytes => new PinKey(keyBytes)); } - public async Task ClearPinKeysAsync(string userId = null) + public Task ClearPinKeysAsync(string userId = null) { - await _stateService.SetUserKeyPinAsync(null, userId); - await _stateService.SetUserKeyPinEphemeralAsync(null, userId); - await _stateService.SetProtectedPinAsync(null, userId); - await clearDeprecatedPinKeysAsync(userId); + return Task.WhenAll( + _stateService.SetPinKeyEncryptedUserKeyAsync(null, userId), + _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId), + _stateService.SetProtectedPinAsync(null, userId), + ClearDeprecatedPinKeysAsync(userId)); } public async Task DecryptUserKeyWithPinAsync(string pin, string salt, KdfConfig kdfConfig, EncString pinProtectedUserKey = null) { - pinProtectedUserKey ??= await _stateService.GetUserKeyPinAsync(); - pinProtectedUserKey ??= await _stateService.GetUserKeyPinEphemeralAsync(); + pinProtectedUserKey ??= await _stateService.GetPinKeyEncryptedUserKeyAsync(); + pinProtectedUserKey ??= await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync(); if (pinProtectedUserKey == null) { throw new Exception("No PIN protected user key found."); } var pinKey = await MakePinKeyAsync(pin, salt, kdfConfig); - var userKey = await DecryptToBytesAsync(pinProtectedUserKey, pinKey); - return new UserKey(userKey); + var userKeyBytes = await DecryptToBytesAsync(pinProtectedUserKey, pinKey); + return new UserKey(userKeyBytes); } // Only for migration purposes @@ -481,7 +474,7 @@ namespace Bit.Core.Services { if (publicKey == null) { - publicKey = await GetPublicKeyAsync(); + publicKey = await GetUserPublicKeyAsync(); } if (publicKey == null) { @@ -521,7 +514,7 @@ namespace Bit.Core.Services if (privateKey is null) { - privateKey = await GetPrivateKeyAsync(); + privateKey = await GetUserPrivateKeyAsync(); } if (privateKey == null) @@ -618,17 +611,17 @@ namespace Bit.Core.Services return await AesDecryptToBytesAsync(encType, ctBytes, ivBytes, macBytes, key); } - public async Task DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null) + public Task DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null) { var iv = Convert.FromBase64String(encString.Iv); var data = Convert.FromBase64String(encString.Data); var mac = !string.IsNullOrWhiteSpace(encString.Mac) ? Convert.FromBase64String(encString.Mac) : null; - return await AesDecryptToBytesAsync(encString.EncryptionType, data, iv, mac, key); + return AesDecryptToBytesAsync(encString.EncryptionType, data, iv, mac, key); } - public async Task DecryptToUtf8Async(EncString encString, SymmetricCryptoKey key = null) + public Task DecryptToUtf8Async(EncString encString, SymmetricCryptoKey key = null) { - return await AesDecryptToUtf8Async(encString.EncryptionType, encString.Data, + return AesDecryptToUtf8Async(encString.EncryptionType, encString.Data, encString.Iv, encString.Mac, key); } @@ -675,7 +668,31 @@ namespace Bit.Core.Services // --HELPER METHODS-- - private async Task StorePinKey(UserKey userKey, string userId = null) + private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null) + { + // Refresh, set, or clear the pin key + if (await _stateService.GetProtectedPinAsync(userId) != null) + { + await UpdateUserKeyPinAsync(userKey, userId); + } + else + { + await _stateService.SetPinKeyEncryptedUserKeyAsync(null, userId); + await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId); + } + + // Refresh, set, or clear the auto key + if (await _stateService.GetVaultTimeoutAsync(userId) == null) + { + await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId); + } + else + { + await _stateService.SetUserKeyAutoUnlockAsync(null, userId); + } + } + + private async Task UpdateUserKeyPinAsync(UserKey userKey, string userId = null) { var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId))); var pinKey = await MakePinKeyAsync( @@ -685,13 +702,12 @@ namespace Bit.Core.Services ); var encPin = await EncryptAsync(userKey.Key, pinKey); - // TODO(Jake): Does this logic make sense? Should we save something in state to indicate the preference? - if (await _stateService.GetUserKeyPinAsync(userId) != null) + if (await _stateService.GetPinKeyEncryptedUserKeyAsync(userId) != null) { - await _stateService.SetUserKeyPinAsync(encPin, userId); + await _stateService.SetPinKeyEncryptedUserKeyAsync(encPin, userId); return; } - await _stateService.SetUserKeyPinEphemeralAsync(encPin, userId); + await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(encPin, userId); } private async Task AesEncryptAsync(byte[] data, SymmetricCryptoKey key) @@ -821,14 +837,16 @@ namespace Bit.Core.Services return key; } - private async Task StretchKeyAsync(SymmetricCryptoKey key) + // TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack + private async Task StretchKeyAsync(SymmetricCryptoKey key, Func keyCreator) + where TKey : SymmetricCryptoKey { var newKey = new byte[64]; var enc = await _cryptoFunctionService.HkdfExpandAsync(key.Key, Encoding.UTF8.GetBytes("enc"), 32, HkdfAlgorithm.Sha256); Buffer.BlockCopy(enc, 0, newKey, 0, 32); var mac = await _cryptoFunctionService.HkdfExpandAsync(key.Key, Encoding.UTF8.GetBytes("mac"), 32, HkdfAlgorithm.Sha256); Buffer.BlockCopy(mac, 0, newKey, 32, 32); - return new SymmetricCryptoKey(newKey); + return keyCreator(newKey); } private List HashPhrase(byte[] hash, int minimumEntropy = 64) @@ -855,13 +873,14 @@ namespace Bit.Core.Services return phrase; } - private async Task> BuildProtectedSymmetricKey(SymmetricCryptoKey key, - byte[] encKey) where T : SymmetricCryptoKey + // TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack + private async Task> BuildProtectedSymmetricKey(SymmetricCryptoKey key, + byte[] encKey, Func keyCreator) where TKey : SymmetricCryptoKey { EncString encKeyEnc = null; if (key.Key.Length == 32) { - var newKey = await StretchKeyAsync(key); + var newKey = await StretchKeyAsync(key, keyCreator); encKeyEnc = await EncryptAsync(encKey, newKey); } else if (key.Key.Length == 64) @@ -872,10 +891,10 @@ namespace Bit.Core.Services { throw new Exception("Invalid key size."); } - return new Tuple(new SymmetricCryptoKey(encKey) as T, encKeyEnc); + return new Tuple(keyCreator(encKey), encKeyEnc); } - // TODO: This intantiator needs to be moved into each key type in order to get rid of the keyCreator hack + // TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack private async Task MakeKeyAsync(string password, string salt, KdfConfig kdfConfig, Func keyCreator) where TKey : SymmetricCryptoKey { @@ -937,6 +956,27 @@ namespace Bit.Core.Services // 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. + private async Task MigrateAutoUnlockKeyIfNeededAsync(string userId = null) + { + var oldAutoKey = await _stateService.GetKeyEncryptedAsync(userId); + if (oldAutoKey == null) + { + return; + } + // Decrypt + var masterKey = new MasterKey(Convert.FromBase64String(oldAutoKey)); + var encryptedUserKey = await _stateService.GetEncKeyEncryptedAsync(userId); + var userKey = await DecryptUserKeyWithMasterKeyAsync( + masterKey, + new EncString(encryptedUserKey), + userId); + // Migrate + await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId); + await _stateService.SetKeyEncryptedAsync(null, userId); + // Set encrypted user key just in case the user locks without syncing + await SetMasterKeyEncryptedUserKeyAsync(encryptedUserKey); + } + public async Task DecryptAndMigrateOldPinKeyAsync( bool masterPasswordOnRestart, string pin, @@ -964,25 +1004,28 @@ namespace Bit.Core.Services if (masterPasswordOnRestart) { await _stateService.SetPinProtectedKeyAsync(null); - await _stateService.SetUserKeyPinEphemeralAsync(pinProtectedKey); + await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(pinProtectedKey); } else { await _stateService.SetPinProtectedAsync(null); - await _stateService.SetUserKeyPinAsync(pinProtectedKey); + await _stateService.SetPinKeyEncryptedUserKeyAsync(pinProtectedKey); // We previously only set the protected pin if MP on Restart was enabled // now we set it regardless var encPin = await EncryptAsync(pin, userKey); await _stateService.SetProtectedPinAsync(encPin.EncryptedString); } + // Clear old key + await _stateService.SetEncKeyEncryptedAsync(null); return userKey; } - public async Task clearDeprecatedPinKeysAsync(string userId = null) + public Task ClearDeprecatedPinKeysAsync(string userId = null) { - await _stateService.SetPinProtectedAsync(null); - await _stateService.SetPinProtectedKeyAsync(null); + return Task.WhenAll( + _stateService.SetPinProtectedAsync(null, userId), + _stateService.SetPinProtectedKeyAsync(null, userId)); } } } diff --git a/src/Core/Services/StateService.cs b/src/Core/Services/StateService.cs index 738b5346c..b57fa783e 100644 --- a/src/Core/Services/StateService.cs +++ b/src/Core/Services/StateService.cs @@ -334,18 +334,29 @@ namespace Bit.Core.Services await SaveAccountAsync(account, reconciledOptions); } - public async Task GetUserKeyMasterKeyAsync(string userId = null) + public async Task GetMasterKeyEncryptedUserKeyAsync(string userId = null) { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultInMemoryOptionsAsync()); - return await _storageMediatorService.GetAsync(Constants.UserKeyKey(reconciledOptions.UserId), false); + return await _storageMediatorService.GetAsync( + await ComposeKeyAsync(Constants.MasterKeyEncryptedUserKeyKey, userId), false); } - public async Task SetUserKeyMasterKeyAsync(string value, string userId = null) + public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultInMemoryOptionsAsync()); - await _storageMediatorService.SaveAsync(Constants.UserKeyKey(reconciledOptions.UserId), value, false); + await _storageMediatorService.SaveAsync( + await ComposeKeyAsync(Constants.MasterKeyEncryptedUserKeyKey, userId), value, false); + } + + public async Task GetUserKeyAutoUnlockAsync(string userId = null) + { + var keyB64 = await _storageMediatorService.GetAsync( + await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), true); + return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64)); + } + + public async Task SetUserKeyAutoUnlockAsync(string value, string userId = null) + { + await _storageMediatorService.SaveAsync( + await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value, true); } public async Task CanAccessPremiumAsync(string userId = null) @@ -354,6 +365,7 @@ namespace Bit.Core.Services { userId = await GetActiveUserIdAsync(); } + if (!await IsAuthenticatedAsync(userId)) { return false; @@ -399,25 +411,27 @@ namespace Bit.Core.Services await SetValueAsync(Constants.ProtectedPinKey(reconciledOptions.UserId), value, reconciledOptions); } - public async Task GetUserKeyPinAsync(string userId = null) + public async Task GetPinKeyEncryptedUserKeyAsync(string userId = null) { - var key = await _storageMediatorService.GetAsync(Constants.UserKeyPinKey(userId), false); + var key = await _storageMediatorService.GetAsync( + await ComposeKeyAsync(Constants.PinKeyEncryptedUserKeyKey, userId), false); return key != null ? new EncString(key) : null; } - public async Task SetUserKeyPinAsync(EncString value, string userId = null) + public async Task SetPinKeyEncryptedUserKeyAsync(EncString value, string userId = null) { - await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value?.EncryptedString, false); + await _storageMediatorService.SaveAsync( + await ComposeKeyAsync(Constants.PinKeyEncryptedUserKeyKey, userId), value?.EncryptedString, false); } - public async Task GetUserKeyPinEphemeralAsync(string userId = null) + public async Task GetPinKeyEncryptedUserKeyEphemeralAsync(string userId = null) { return (await GetAccountAsync( ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) ))?.VolatileData?.UserKeyPinEphemeral; } - public async Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null) + public async Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()); @@ -426,39 +440,6 @@ namespace Bit.Core.Services await SaveAccountAsync(account, reconciledOptions); } - [Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")] - public async Task GetPinProtectedAsync(string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - return await GetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions); - } - - [Obsolete("Use SetUserKeyPinAsync instead")] - public async Task SetPinProtectedAsync(string value, string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions); - } - - [Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")] - public async Task GetPinProtectedKeyAsync(string userId = null) - { - return (await GetAccountAsync( - ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) - ))?.VolatileData?.PinProtectedKey; - } - - [Obsolete("Use SetUserKeyPinEphemeralAsync instead")] - public async Task SetPinProtectedKeyAsync(EncString value, string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultInMemoryOptionsAsync()); - var account = await GetAccountAsync(reconciledOptions); - account.VolatileData.PinProtectedKey = value; - await SaveAccountAsync(account, reconciledOptions); - } public async Task SetKdfConfigurationAsync(KdfConfig config, string userId = null) { @@ -1532,28 +1513,30 @@ namespace Bit.Core.Services } // Non-state storage - await SetProtectedPinAsync(null, userId); - await SetPinProtectedAsync(null, userId); - await SetKeyEncryptedAsync(null, userId); - await SetKeyHashAsync(null, userId); - await SetEncKeyEncryptedAsync(null, userId); - await SetOrgKeysEncryptedAsync(null, userId); - await SetPrivateKeyEncryptedAsync(null, userId); - await SetLastActiveTimeAsync(null, userId); - await SetPreviousPageInfoAsync(null, userId); - await SetInvalidUnlockAttemptsAsync(null, userId); - await SetLocalDataAsync(null, userId); - await SetEncryptedCiphersAsync(null, userId); - await SetEncryptedCollectionsAsync(null, userId); - await SetLastSyncAsync(null, userId); - await SetEncryptedFoldersAsync(null, userId); - await SetEncryptedPoliciesAsync(null, userId); - await SetUsesKeyConnectorAsync(null, userId); - await SetOrganizationsAsync(null, userId); - await SetEncryptedPasswordGenerationHistoryAsync(null, userId); - await SetEncryptedSendsAsync(null, userId); - await SetSettingsAsync(null, userId); - await SetApprovePasswordlessLoginsAsync(null, userId); + await Task.WhenAll( + SetUserKeyAutoUnlockAsync(null, userId), + SetProtectedPinAsync(null, userId), + SetKeyHashAsync(null, userId), + SetOrgKeysEncryptedAsync(null, userId), + SetPrivateKeyEncryptedAsync(null, userId), + SetLastActiveTimeAsync(null, userId), + SetPreviousPageInfoAsync(null, userId), + SetInvalidUnlockAttemptsAsync(null, userId), + SetLocalDataAsync(null, userId), + SetEncryptedCiphersAsync(null, userId), + SetEncryptedCollectionsAsync(null, userId), + SetLastSyncAsync(null, userId), + SetEncryptedFoldersAsync(null, userId), + SetEncryptedPoliciesAsync(null, userId), + SetUsesKeyConnectorAsync(null, userId), + SetOrganizationsAsync(null, userId), + SetEncryptedPasswordGenerationHistoryAsync(null, userId), + SetEncryptedSendsAsync(null, userId), + SetSettingsAsync(null, userId), + SetApprovePasswordlessLoginsAsync(null, userId), + SetEncKeyEncryptedAsync(null, userId), + SetKeyEncryptedAsync(null, userId), + SetPinProtectedAsync(null, userId)); } private async Task ScaffoldNewAccountAsync(Account account) @@ -1742,7 +1725,41 @@ namespace Bit.Core.Services shouldConnect ?? await GetShouldConnectToWatchAsync(), await GetDefaultStorageOptionsAsync()); } - [Obsolete] + [Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")] + public async Task GetPinProtectedAsync(string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultStorageOptionsAsync()); + return await GetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions); + } + + [Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead")] + public async Task SetPinProtectedAsync(string value, string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultStorageOptionsAsync()); + await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions); + } + + [Obsolete("Use GetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")] + public async Task GetPinProtectedKeyAsync(string userId = null) + { + return (await GetAccountAsync( + ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) + ))?.VolatileData?.PinProtectedKey; + } + + [Obsolete("Use SetPinKeyEncryptedUserKeyEphemeralAsync instead")] + public async Task SetPinProtectedKeyAsync(EncString value, string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultInMemoryOptionsAsync()); + var account = await GetAccountAsync(reconciledOptions); + account.VolatileData.PinProtectedKey = value; + await SaveAccountAsync(account, reconciledOptions); + } + + [Obsolete("Use GetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")] public async Task GetEncKeyEncryptedAsync(string userId = null) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, @@ -1750,7 +1767,7 @@ namespace Bit.Core.Services return await GetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), reconciledOptions); } - [Obsolete] + [Obsolete("Use SetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")] public async Task SetEncKeyEncryptedAsync(string value, string userId) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, @@ -1758,15 +1775,7 @@ namespace Bit.Core.Services await SetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), value, reconciledOptions); } - [Obsolete] - public async Task GetKeyEncryptedAsync(string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultSecureStorageOptionsAsync()); - return await GetValueAsync(Constants.KeyKey(reconciledOptions.UserId), reconciledOptions); - } - - [Obsolete] + [Obsolete("Left for migration purposes")] public async Task SetKeyEncryptedAsync(string value, string userId) { var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, @@ -1774,22 +1783,20 @@ namespace Bit.Core.Services await SetValueAsync(Constants.KeyKey(reconciledOptions.UserId), value, reconciledOptions); } - [Obsolete] + [Obsolete("Use GetUserKeyAutoUnlock instead, left for migration purposes")] + public async Task GetKeyEncryptedAsync(string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultSecureStorageOptionsAsync()); + return await GetValueAsync(Constants.KeyKey(reconciledOptions.UserId), reconciledOptions); + } + + [Obsolete("Use GetMasterKeyAsync instead, left for migration purposes")] public async Task GetKeyDecryptedAsync(string userId = null) { return (await GetAccountAsync( ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) ))?.VolatileData?.Key; } - - [Obsolete] - public async Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultInMemoryOptionsAsync()); - var account = await GetAccountAsync(reconciledOptions); - account.VolatileData.Key = value; - await SaveAccountAsync(account, reconciledOptions); - } } } diff --git a/src/Core/Services/SyncService.cs b/src/Core/Services/SyncService.cs index 2763a8e0d..e4dfd6660 100644 --- a/src/Core/Services/SyncService.cs +++ b/src/Core/Services/SyncService.cs @@ -328,7 +328,7 @@ namespace Bit.Core.Services return; } await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(response.Key); - await _cryptoService.SetPrivateKeyAsync(response.PrivateKey); + await _cryptoService.SetUserPrivateKeyAsync(response.PrivateKey); await _cryptoService.SetOrgKeysAsync(response.Organizations); await _stateService.SetSecurityStampAsync(response.SecurityStamp); var organizations = response.Organizations.ToDictionary(o => o.Id, o => new OrganizationData(o)); diff --git a/src/Core/Services/UserVerificationService.cs b/src/Core/Services/UserVerificationService.cs index 554c0d49a..74031b55c 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.CompareAndUpdatePasswordHashAsync(secret, null); + var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, null); if (!passwordValid) { await InvalidSecretErrorAsync(verificationType); diff --git a/src/Core/Services/VaultTimeoutService.cs b/src/Core/Services/VaultTimeoutService.cs index f1060c2e1..28b48c258 100644 --- a/src/Core/Services/VaultTimeoutService.cs +++ b/src/Core/Services/VaultTimeoutService.cs @@ -1,13 +1,11 @@ using System; -using System.Linq; using System.Threading.Tasks; using Bit.Core.Abstractions; using Bit.Core.Enums; -using Bit.Core.Models.Domain; namespace Bit.Core.Services { - public enum PinLockEnum + public enum PinLockType { Disabled, Persistent, @@ -61,15 +59,26 @@ namespace Bit.Core.Services public async Task IsLockedAsync(string userId = null) { - var hasKey = await _cryptoService.HasUserKeyAsync(userId); - if (hasKey) + var biometricSet = await IsBiometricLockSetAsync(userId); + if (biometricSet && await _stateService.GetBiometricLockedAsync(userId)) { - var biometricSet = await IsBiometricLockSetAsync(userId); - if (biometricSet && await _stateService.GetBiometricLockedAsync(userId)) + return true; + } + + if (!await _cryptoService.HasUserKeyAsync(userId)) + { + if (await _cryptoService.HasAutoUnlockKeyAsync(userId)) + { + await _cryptoService.SetUserKeyAsync(await _cryptoService.GetAutoUnlockKeyAsync(userId)); + } + else { return true; } } + + // Check again to verify auto key was set + var hasKey = await _cryptoService.HasUserKeyAsync(userId); return !hasKey; } @@ -172,11 +181,11 @@ namespace Bit.Core.Services if (await _keyConnectorService.GetUsesKeyConnector()) { - var pinStatus = await IsPinLockSetAsync(userId); - var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync() + var pinStatus = await GetPinLockTypeAsync(userId); + var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync() ?? await _stateService.GetPinProtectedKeyAsync(); - var pinEnabled = (pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) || - pinStatus == PinLockEnum.Persistent; + var pinEnabled = (pinStatus == PinLockType.Transient && ephemeralPinSet != null) || + pinStatus == PinLockType.Persistent; if (!pinEnabled && !await IsBiometricLockSetAsync()) { @@ -198,6 +207,7 @@ namespace Bit.Core.Services await Task.WhenAll( _cryptoService.ClearUserKeyAsync(userId), _cryptoService.ClearMasterKeyAsync(userId), + _stateService.SetUserKeyAutoUnlockAsync(null, userId), _cryptoService.ClearOrgKeysAsync(true, userId), _cryptoService.ClearKeyPairAsync(true, userId)); @@ -223,30 +233,27 @@ namespace Bit.Core.Services { await _stateService.SetVaultTimeoutAsync(timeout); await _stateService.SetVaultTimeoutActionAsync(action); - await _cryptoService.ToggleKeysAsync(); + await _cryptoService.RefreshKeysAsync(); await _tokenService.ToggleTokensAsync(); } - public async Task IsPinLockSetAsync(string userId = null) + public async Task GetPinLockTypeAsync(string userId = null) { // we can't depend on only the protected pin being set because old // versions only used it for MP on Restart - var pinIsEnabled = await _stateService.GetProtectedPinAsync(userId); - var userKeyPin = await _stateService.GetUserKeyPinAsync(userId); - var oldUserKeyPin = await _stateService.GetPinProtectedAsync(userId); + var isPinEnabled = await _stateService.GetProtectedPinAsync(userId) != null; + var hasUserKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync(userId) != null; + var hasOldUserKeyPin = await _stateService.GetPinProtectedAsync(userId) != null; - if (userKeyPin != null || oldUserKeyPin != null) + if (hasUserKeyPin || hasOldUserKeyPin) { - return PinLockEnum.Persistent; + return PinLockType.Persistent; } - else if (pinIsEnabled != null && userKeyPin == null && oldUserKeyPin == null) + else if (isPinEnabled && !hasUserKeyPin && !hasOldUserKeyPin) { - return PinLockEnum.Transient; - } - else - { - return PinLockEnum.Disabled; + return PinLockType.Transient; } + return PinLockType.Disabled; } public async Task IsBiometricLockSetAsync(string userId = null) diff --git a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs index bebc7e925..db5ce6f67 100644 --- a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs +++ b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs @@ -30,7 +30,7 @@ namespace Bit.iOS.Core.Controllers private IBiometricService _biometricService; private IKeyConnectorService _keyConnectorService; private IAccountsManager _accountManager; - private PinLockEnum _pinStatus; + private PinLockType _pinStatus; private bool _pinEnabled; private bool _biometricEnabled; private bool _biometricIntegrityValid = true; @@ -104,18 +104,18 @@ namespace Bit.iOS.Core.Controllers if (autofillExtension && await _stateService.GetPasswordRepromptAutofillAsync()) { _passwordReprompt = true; - _pinStatus = PinLockEnum.Disabled; + _pinStatus = PinLockType.Disabled; _pinEnabled = false; _biometricEnabled = false; } else { - _pinStatus = await _vaultTimeoutService.IsPinLockSetAsync(); + _pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync(); - var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync() + var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync() ?? await _stateService.GetPinProtectedKeyAsync(); - _pinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) || - _pinStatus == PinLockEnum.Persistent; + _pinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) || + _pinStatus == PinLockType.Persistent; _biometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync(); @@ -257,15 +257,15 @@ namespace Bit.iOS.Core.Controllers { EncString userKeyPin = null; EncString oldPinProtected = null; - if (_pinStatus == PinLockEnum.Persistent) + if (_pinStatus == PinLockType.Persistent) { - userKeyPin = await _stateService.GetUserKeyPinAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync(); var oldEncryptedKey = await _stateService.GetPinProtectedAsync(); oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null; } - else if (_pinStatus == PinLockEnum.Transient) + else if (_pinStatus == PinLockType.Transient) { - userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync(); oldPinProtected = await _stateService.GetPinProtectedKeyAsync(); } @@ -273,7 +273,7 @@ namespace Bit.iOS.Core.Controllers if (oldPinProtected != null) { userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync( - _pinStatus == PinLockEnum.Transient, + _pinStatus == PinLockType.Transient, inputtedValue, email, kdfConfig, @@ -312,18 +312,18 @@ namespace Bit.iOS.Core.Controllers { var masterKey = await _cryptoService.MakeMasterKeyAsync(inputtedValue, email, kdfConfig); - var storedPasswordHash = await _cryptoService.GetPasswordHashAsync(); + var storedPasswordHash = await _cryptoService.GetMasterKeyHashAsync(); if (storedPasswordHash == null) { var oldKey = await _secureStorageService.GetAsync("oldKey"); if (masterKey.KeyB64 == oldKey) { - var localPasswordHash = await _cryptoService.HashPasswordAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization); + var localPasswordHash = await _cryptoService.HashMasterKeyAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization); await _secureStorageService.RemoveAsync("oldKey"); - await _cryptoService.SetPasswordHashAsync(localPasswordHash); + await _cryptoService.SetMasterKeyHashAsync(localPasswordHash); } } - var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(inputtedValue, masterKey); + var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(inputtedValue, masterKey); if (passwordValid) { await AppHelpers.ResetInvalidUnlockAttemptsAsync(); diff --git a/src/iOS.Core/Controllers/LockPasswordViewController.cs b/src/iOS.Core/Controllers/LockPasswordViewController.cs index 9d4019a47..eff86b50e 100644 --- a/src/iOS.Core/Controllers/LockPasswordViewController.cs +++ b/src/iOS.Core/Controllers/LockPasswordViewController.cs @@ -1,20 +1,20 @@ using System; -using UIKit; -using Foundation; -using Bit.iOS.Core.Views; -using Bit.App.Resources; -using Bit.iOS.Core.Utilities; -using Bit.App.Abstractions; -using Bit.Core.Abstractions; -using Bit.Core.Utilities; using System.Threading.Tasks; -using Bit.App.Utilities; -using Bit.Core.Models.Domain; -using Bit.Core.Enums; -using Bit.App.Pages; +using Bit.App.Abstractions; using Bit.App.Models; -using Xamarin.Forms; +using Bit.App.Pages; +using Bit.App.Resources; +using Bit.App.Utilities; +using Bit.Core.Abstractions; +using Bit.Core.Enums; +using Bit.Core.Models.Domain; using Bit.Core.Services; +using Bit.Core.Utilities; +using Bit.iOS.Core.Utilities; +using Bit.iOS.Core.Views; +using Foundation; +using UIKit; +using Xamarin.Forms; namespace Bit.iOS.Core.Controllers { @@ -30,7 +30,7 @@ namespace Bit.iOS.Core.Controllers private IPlatformUtilsService _platformUtilsService; private IBiometricService _biometricService; private IKeyConnectorService _keyConnectorService; - private PinLockEnum _pinStatus; + private PinLockType _pinStatus; private bool _pinEnabled; private bool _biometricEnabled; private bool _biometricIntegrityValid = true; @@ -96,18 +96,18 @@ namespace Bit.iOS.Core.Controllers if (autofillExtension && await _stateService.GetPasswordRepromptAutofillAsync()) { _passwordReprompt = true; - _pinStatus = PinLockEnum.Disabled; + _pinStatus = PinLockType.Disabled; _pinEnabled = false; _biometricEnabled = false; } else { - _pinStatus = await _vaultTimeoutService.IsPinLockSetAsync(); + _pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync(); - var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync() + var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync() ?? await _stateService.GetPinProtectedKeyAsync(); - _pinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) || - _pinStatus == PinLockEnum.Persistent; + _pinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) || + _pinStatus == PinLockType.Persistent; _biometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync(); @@ -129,7 +129,7 @@ namespace Bit.iOS.Core.Controllers { BaseNavItem.Title = AppResources.VerifyMasterPassword; } - + BaseCancelButton.Title = AppResources.Cancel; if (_biometricUnlockOnly) @@ -224,15 +224,15 @@ namespace Bit.iOS.Core.Controllers { EncString userKeyPin = null; EncString oldPinProtected = null; - if (_pinStatus == PinLockEnum.Persistent) + if (_pinStatus == PinLockType.Persistent) { - userKeyPin = await _stateService.GetUserKeyPinAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync(); var oldEncryptedKey = await _stateService.GetPinProtectedAsync(); oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null; } - else if (_pinStatus == PinLockEnum.Transient) + else if (_pinStatus == PinLockType.Transient) { - userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync(); + userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync(); oldPinProtected = await _stateService.GetPinProtectedKeyAsync(); } @@ -240,7 +240,7 @@ namespace Bit.iOS.Core.Controllers if (oldPinProtected != null) { userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync( - _pinStatus == PinLockEnum.Transient, + _pinStatus == PinLockType.Transient, inputtedValue, email, kdfConfig, @@ -284,19 +284,19 @@ namespace Bit.iOS.Core.Controllers else { var masterKey = await _cryptoService.MakeMasterKeyAsync(inputtedValue, email, kdfConfig); - - var storedPasswordHash = await _cryptoService.GetPasswordHashAsync(); + + var storedPasswordHash = await _cryptoService.GetMasterKeyHashAsync(); if (storedPasswordHash == null) { var oldKey = await _secureStorageService.GetAsync("oldKey"); if (masterKey.KeyB64 == oldKey) { - var localPasswordHash = await _cryptoService.HashPasswordAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization); + var localPasswordHash = await _cryptoService.HashMasterKeyAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization); await _secureStorageService.RemoveAsync("oldKey"); - await _cryptoService.SetPasswordHashAsync(localPasswordHash); + await _cryptoService.SetMasterKeyHashAsync(localPasswordHash); } } - var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(inputtedValue, masterKey); + var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(inputtedValue, masterKey); if (passwordValid) { await AppHelpers.ResetInvalidUnlockAttemptsAsync(); @@ -395,7 +395,7 @@ namespace Bit.iOS.Core.Controllers }); PresentViewController(alert, true, null); } - + private async Task LogOutAsync() { await AppHelpers.LogOutAsync(await _stateService.GetActiveUserIdAsync());