1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-22 11:13:49 +00:00

[PM-2713] refresh pin key when setting user key

This commit is contained in:
Jacob Fink
2023-07-18 13:03:30 -04:00
parent 5ba3fac0c0
commit d58f0b281b
4 changed files with 45 additions and 20 deletions

View File

@@ -9,7 +9,7 @@ namespace Bit.Core.Abstractions
{ {
public interface ICryptoService public interface ICryptoService
{ {
Task SetUserKeyAsync(UserKey userKey); Task SetUserKeyAsync(UserKey userKey, string userId = null);
Task<UserKey> GetUserKeyAsync(string userId = null); Task<UserKey> GetUserKeyAsync(string userId = null);
Task<bool> HasUserKeyAsync(string userId = null); Task<bool> HasUserKeyAsync(string userId = null);
Task<UserKey> MakeUserKeyAsync(); Task<UserKey> MakeUserKeyAsync();

View File

@@ -44,18 +44,18 @@ namespace Bit.Core.Abstractions
Task<bool> CanAccessPremiumAsync(string userId = null); Task<bool> CanAccessPremiumAsync(string userId = null);
Task<string> GetProtectedPinAsync(string userId = null); Task<string> GetProtectedPinAsync(string userId = null);
Task SetPersonalPremiumAsync(bool value, string userId = null); Task SetPersonalPremiumAsync(bool value, string userId = null);
Task<string> GetUserKeyPin(string userId = null); Task<string> GetUserKeyPinAsync(string userId = null);
Task SetUserKeyPin(string value, string userId = null); Task SetUserKeyPinAsync(EncString value, string userId = null);
Task<EncString> GetUserKeyPinEphemeral(string userId = null); Task<EncString> GetUserKeyPinEphemeralAsync(string userId = null);
Task SetUserKeyPinEphemeral(EncString value, string userId = null); Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null);
Task SetProtectedPinAsync(string value, string userId = null); Task SetProtectedPinAsync(string value, string userId = null);
[Obsolete("Use GetUserKeyPin instead, left for migration purposes")] [Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")]
Task<string> GetPinProtectedAsync(string userId = null); Task<string> GetPinProtectedAsync(string userId = null);
[Obsolete("Use SetUserKeyPin instead")] [Obsolete("Use SetUserKeyPinAsync instead")]
Task SetPinProtectedAsync(string value, string userId = null); Task SetPinProtectedAsync(string value, string userId = null);
[Obsolete("Use GetUserKeyPinEphemeral instead, left for migration purposes")] [Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")]
Task<EncString> GetPinProtectedKeyAsync(string userId = null); Task<EncString> GetPinProtectedKeyAsync(string userId = null);
[Obsolete("Use SetUserKeyPinEphemeral instead")] [Obsolete("Use SetUserKeyPinEphemeralAsync instead")]
Task SetPinProtectedKeyAsync(EncString value, string userId = null); Task SetPinProtectedKeyAsync(EncString value, string userId = null);
Task SetKdfConfigurationAsync(KdfConfig config, string userId = null); Task SetKdfConfigurationAsync(KdfConfig config, string userId = null);
Task<string> GetKeyHashAsync(string userId = null); Task<string> GetKeyHashAsync(string userId = null);

View File

@@ -36,9 +36,15 @@ namespace Bit.Core.Services
_cryptoFunctionService = cryptoFunctionService; _cryptoFunctionService = cryptoFunctionService;
} }
public async Task SetUserKeyAsync(UserKey userKey) public async Task SetUserKeyAsync(UserKey userKey, string userId = null)
{ {
await _stateService.SetUserKeyAsync(userKey); 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);
}
} }
public async Task<UserKey> GetUserKeyAsync(string userId = null) public async Task<UserKey> GetUserKeyAsync(string userId = null)
@@ -610,6 +616,25 @@ namespace Bit.Core.Services
// Helpers // Helpers
private async Task StorePinKey(UserKey userKey, string userId = null)
{
var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId)));
var pinKey = await MakePinKeyAsync(
pin,
await _stateService.GetEmailAsync(userId),
await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile))
);
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)
{
await _stateService.SetUserKeyPinAsync(encPin, userId);
return;
}
await _stateService.SetUserKeyPinEphemeralAsync(encPin, userId);
}
private async Task<EncryptedObject> AesEncryptAsync(byte[] data, SymmetricCryptoKey key) private async Task<EncryptedObject> AesEncryptAsync(byte[] data, SymmetricCryptoKey key)
{ {
var obj = new EncryptedObject var obj = new EncryptedObject

View File

@@ -396,25 +396,25 @@ namespace Bit.Core.Services
} }
// TODO(Jake): Does this need to be secure storage? // TODO(Jake): Does this need to be secure storage?
public async Task<string> GetUserKeyPin(string userId = null) public async Task<string> GetUserKeyPinAsync(string userId = null)
{ {
return await _storageMediatorService.GetAsync<string>(Constants.UserKeyPinKey(userId), false); return await _storageMediatorService.GetAsync<string>(Constants.UserKeyPinKey(userId), false);
} }
// TODO(Jake): Does this need to be secure storage? // TODO(Jake): Does this need to be secure storage?
public async Task SetUserKeyPin(string value, string userId = null) public async Task SetUserKeyPinAsync(EncString value, string userId = null)
{ {
await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value, false); await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value.EncryptedString, false);
} }
public async Task<EncString> GetUserKeyPinEphemeral(string userId = null) public async Task<EncString> GetUserKeyPinEphemeralAsync(string userId = null)
{ {
return (await GetAccountAsync( return (await GetAccountAsync(
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync()) ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
))?.VolatileData?.UserKeyPinEphemeral; ))?.VolatileData?.UserKeyPinEphemeral;
} }
public async Task SetUserKeyPinEphemeral(EncString value, string userId = null) public async Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null)
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
await GetDefaultInMemoryOptionsAsync()); await GetDefaultInMemoryOptionsAsync());
@@ -423,7 +423,7 @@ namespace Bit.Core.Services
await SaveAccountAsync(account, reconciledOptions); await SaveAccountAsync(account, reconciledOptions);
} }
[Obsolete("Use GetUserKeyPin instead, left for migration purposes")] [Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")]
public async Task<string> GetPinProtectedAsync(string userId = null) public async Task<string> GetPinProtectedAsync(string userId = null)
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
@@ -431,7 +431,7 @@ namespace Bit.Core.Services
return await GetValueAsync<string>(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions); return await GetValueAsync<string>(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions);
} }
[Obsolete("Use SetUserKeyPin instead")] [Obsolete("Use SetUserKeyPinAsync instead")]
public async Task SetPinProtectedAsync(string value, string userId = null) public async Task SetPinProtectedAsync(string value, string userId = null)
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
@@ -439,7 +439,7 @@ namespace Bit.Core.Services
await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions); await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions);
} }
[Obsolete("Use GetUserKeyPinEphemeral instead, left for migration purposes")] [Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")]
public async Task<EncString> GetPinProtectedKeyAsync(string userId = null) public async Task<EncString> GetPinProtectedKeyAsync(string userId = null)
{ {
return (await GetAccountAsync( return (await GetAccountAsync(
@@ -447,7 +447,7 @@ namespace Bit.Core.Services
))?.VolatileData?.PinProtectedKey; ))?.VolatileData?.PinProtectedKey;
} }
[Obsolete("Use SetUserKeyPinEphemeral instead")] [Obsolete("Use SetUserKeyPinEphemeralAsync instead")]
public async Task SetPinProtectedKeyAsync(EncString value, string userId = null) public async Task SetPinProtectedKeyAsync(EncString value, string userId = null)
{ {
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId }, var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },