From 15d3da607bb6196741e9e8adb21e6bd5538ce91a Mon Sep 17 00:00:00 2001 From: Jacob Fink Date: Thu, 6 Jul 2023 15:40:46 -0400 Subject: [PATCH] [PM-2713] add new state for new keys and obsolete old ones - UserKey - MasterKey - UserKeyMasterKey (enc UserKey from User Table) --- src/Core/Abstractions/IStateService.cs | 24 +++-- src/Core/Constants.cs | 11 +- src/Core/Models/Domain/Account.cs | 9 +- src/Core/Services/StateService.cs | 134 +++++++++++++++++-------- 4 files changed, 125 insertions(+), 53 deletions(-) diff --git a/src/Core/Abstractions/IStateService.cs b/src/Core/Abstractions/IStateService.cs index 355acd093..777a3dea8 100644 --- a/src/Core/Abstractions/IStateService.cs +++ b/src/Core/Abstractions/IStateService.cs @@ -13,6 +13,12 @@ namespace Bit.Core.Abstractions public interface IStateService { List AccountViews { get; } + Task GetUserKeyAsync(string userId = null); + 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 GetActiveUserIdAsync(); Task GetActiveUserEmailAsync(); Task GetActiveUserCustomDataAsync(Func dataMapper); @@ -44,14 +50,8 @@ namespace Bit.Core.Abstractions Task GetPinProtectedKeyAsync(string userId = null); Task SetPinProtectedKeyAsync(EncString value, string userId = null); Task SetKdfConfigurationAsync(KdfConfig config, string userId = null); - Task GetKeyEncryptedAsync(string userId = null); - Task SetKeyEncryptedAsync(string value, string userId = null); - Task GetKeyDecryptedAsync(string userId = null); - Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null); Task GetKeyHashAsync(string userId = null); Task SetKeyHashAsync(string value, string userId = null); - Task GetEncKeyEncryptedAsync(string userId = null); - Task SetEncKeyEncryptedAsync(string value, string userId = null); Task> GetOrgKeysEncryptedAsync(string userId = null); Task SetOrgKeysEncryptedAsync(Dictionary value, string userId = null); Task GetPrivateKeyEncryptedAsync(string userId = null); @@ -176,5 +176,17 @@ namespace Bit.Core.Abstractions void SetLocale(string locale); ConfigResponse GetConfigs(); void SetConfigs(ConfigResponse value); + [Obsolete("Use GetUserKeyMasterKey instead")] + Task GetEncKeyEncryptedAsync(string userId = null); + [Obsolete("Use SetUserKeyMasterKey instead")] + Task SetEncKeyEncryptedAsync(string value, string userId = null); + [Obsolete] + Task GetKeyEncryptedAsync(string userId = null); + [Obsolete] + Task SetKeyEncryptedAsync(string value, string userId = null); + [Obsolete("Use GetMasterKey instead")] + Task GetKeyDecryptedAsync(string userId = null); + [Obsolete("Use GetMasterKey instead")] + Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null); } } diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 73863f580..98dffb5c5 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -1,4 +1,6 @@ -namespace Bit.Core +using System; + +namespace Bit.Core { public static class Constants { @@ -79,6 +81,7 @@ 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 CiphersKey(string userId) => $"ciphers_{userId}"; public static string FoldersKey(string userId) => $"folders_{userId}"; public static string CollectionsKey(string userId) => $"collections_{userId}"; @@ -87,10 +90,8 @@ public static string NeverDomainsKey(string userId) => $"neverDomains_{userId}"; public static string SendsKey(string userId) => $"sends_{userId}"; public static string PoliciesKey(string userId) => $"policies_{userId}"; - public static string KeyKey(string userId) => $"key_{userId}"; public static string EncOrgKeysKey(string userId) => $"encOrgKeys_{userId}"; public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}"; - public static string EncKeyKey(string userId) => $"encKey_{userId}"; public static string KeyHashKey(string userId) => $"keyHash_{userId}"; public static string PinProtectedKey(string userId) => $"pinProtectedKey_{userId}"; public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}"; @@ -121,5 +122,9 @@ public static string PushCurrentTokenKey(string userId) => $"pushCurrentToken_{userId}"; public static string ShouldConnectToWatchKey(string userId) => $"shouldConnectToWatch_{userId}"; public static string ScreenCaptureAllowedKey(string userId) => $"screenCaptureAllowed_{userId}"; + [Obsolete] + public static string KeyKey(string userId) => $"key_{userId}"; + [Obsolete] + public static string EncKeyKey(string userId) => $"encKey_{userId}"; } } diff --git a/src/Core/Models/Domain/Account.cs b/src/Core/Models/Domain/Account.cs index 6267d5815..b6fc42f58 100644 --- a/src/Core/Models/Domain/Account.cs +++ b/src/Core/Models/Domain/Account.cs @@ -117,9 +117,14 @@ namespace Bit.Core.Models.Domain public class AccountVolatileData { - public SymmetricCryptoKey Key; - public EncString PinProtectedKey; + public UserKey UserKey; + public MasterKey MasterKey; + public EncString UserKeyPinEphemeral; public bool? BiometricLocked; + [Obsolete("Jul 6 2023: Key has been deprecated. We will use the User Key in the future. It remains here for migration during app upgrade.")] + public SymmetricCryptoKey Key; + [Obsolete("Jul 6 2023: PinProtectedKey has been deprecated in favor of UserKeyPinEphemeral. It remains here for migration during app upgrade.")] + public EncString PinProtectedKey; } } } diff --git a/src/Core/Services/StateService.cs b/src/Core/Services/StateService.cs index ae2d62d8e..494ae0956 100644 --- a/src/Core/Services/StateService.cs +++ b/src/Core/Services/StateService.cs @@ -302,6 +302,48 @@ namespace Bit.Core.Services true, reconciledOptions); } + public async Task GetUserKeyAsync(string userId = null) + { + return (await GetAccountAsync( + ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) + ))?.VolatileData?.UserKey; + } + + public async Task SetUserKeyAsync(UserKey value, string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultInMemoryOptionsAsync()); + var account = await GetAccountAsync(reconciledOptions); + account.VolatileData.UserKey = value; + await SaveAccountAsync(account, reconciledOptions); + } + + public async Task GetMasterKeyAsync(string userId = null) + { + return (await GetAccountAsync( + ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) + ))?.VolatileData?.MasterKey; + } + + public async Task SetMasterKeyAsync(MasterKey value, string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultInMemoryOptionsAsync()); + var account = await GetAccountAsync(reconciledOptions); + account.VolatileData.MasterKey = value; + await SaveAccountAsync(account, reconciledOptions); + } + + public async Task GetUserKeyMasterKeyAsync(string userId = null) + { + return await _storageMediatorService.GetAsync(Constants.UserKeyKey(userId), false); + } + + public async Task SetUserKeyMasterKeyAsync(string value, string userId = null) + { + await _storageMediatorService.SaveAsync(Constants.UserKeyKey(userId), value, false); + } + public async Task CanAccessPremiumAsync(string userId = null) { if (userId == null) @@ -395,35 +437,6 @@ namespace Bit.Core.Services await SaveAccountAsync(account, reconciledOptions); } - public async Task GetKeyEncryptedAsync(string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultSecureStorageOptionsAsync()); - return await GetValueAsync(Constants.KeyKey(reconciledOptions.UserId), reconciledOptions); - } - - public async Task SetKeyEncryptedAsync(string value, string userId) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultSecureStorageOptionsAsync()); - await SetValueAsync(Constants.KeyKey(reconciledOptions.UserId), value, reconciledOptions); - } - - public async Task GetKeyDecryptedAsync(string userId = null) - { - return (await GetAccountAsync( - ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) - ))?.VolatileData?.Key; - } - - 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); - } public async Task GetKeyHashAsync(string userId = null) { @@ -439,19 +452,6 @@ namespace Bit.Core.Services await SetValueAsync(Constants.KeyHashKey(reconciledOptions.UserId), value, reconciledOptions); } - public async Task GetEncKeyEncryptedAsync(string userId = null) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - return await GetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), reconciledOptions); - } - - public async Task SetEncKeyEncryptedAsync(string value, string userId) - { - var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, - await GetDefaultStorageOptionsAsync()); - await SetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), value, reconciledOptions); - } public async Task> GetOrgKeysEncryptedAsync(string userId = null) { @@ -1656,5 +1656,55 @@ namespace Bit.Core.Services await SetValueAsync(Constants.LastUserShouldConnectToWatchKey, shouldConnect ?? await GetShouldConnectToWatchAsync(), await GetDefaultStorageOptionsAsync()); } + + [Obsolete] + public async Task GetEncKeyEncryptedAsync(string userId = null) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultStorageOptionsAsync()); + return await GetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), reconciledOptions); + } + + [Obsolete] + public async Task SetEncKeyEncryptedAsync(string value, string userId) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultStorageOptionsAsync()); + 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] + public async Task SetKeyEncryptedAsync(string value, string userId) + { + var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, + await GetDefaultSecureStorageOptionsAsync()); + await SetValueAsync(Constants.KeyKey(reconciledOptions.UserId), value, reconciledOptions); + } + + [Obsolete] + 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); + } } }