diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs index a33d71ccb..0bf62e075 100644 --- a/src/Core/Services/AuthService.cs +++ b/src/Core/Services/AuthService.cs @@ -470,10 +470,6 @@ namespace Bit.Core.Services _messagingService.Send("accountAdded"); if (_setCryptoKeys) { - if (masterKey != null) - { - await _cryptoService.SetMasterKeyAsync(masterKey); - } if (localHashedPassword != null) { @@ -489,6 +485,13 @@ namespace Bit.Core.Services await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key); + if (masterKey != null) + { + await _cryptoService.SetMasterKeyAsync(masterKey); + var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey); + await _cryptoService.SetUserKeyAsync(userKey); + } + // User doesn't have a key pair yet (old account), let's generate one for them. if (tokenResponse.PrivateKey == null) { diff --git a/src/Core/Services/CryptoService.cs b/src/Core/Services/CryptoService.cs index 142be900b..2a314c119 100644 --- a/src/Core/Services/CryptoService.cs +++ b/src/Core/Services/CryptoService.cs @@ -110,14 +110,6 @@ namespace Bit.Core.Services public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null) { - var option = await _stateService.GetVaultTimeoutAsync(); - var biometric = await _stateService.GetBiometricUnlockAsync(); - if (option.HasValue && !biometric.GetValueOrDefault()) - { - // we only store the encrypted user key if the user has a vault timeout set - // with no biometric. Otherwise, we need it for auto unlock or biometric unlock - return; - } await _stateService.SetUserKeyMasterKeyAsync(value, userId); } @@ -133,16 +125,18 @@ namespace Bit.Core.Services if (masterKey == null) { // Migration support - var encMasterKey = await _stateService.GetKeyEncryptedAsync(userId); - masterKey = new MasterKey(Convert.FromBase64String(encMasterKey)); - await this.SetMasterKeyAsync(masterKey, userId); + masterKey = await _stateService.GetKeyDecryptedAsync(userId) as MasterKey; + if (masterKey != null) + { + await SetMasterKeyAsync(masterKey, userId); + } } return masterKey; } public async Task MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig) { - return await MakeKeyAsync(password, email, kdfConfig) as MasterKey; + return await MakeKeyAsync(password, email, kdfConfig, keyBytes => new MasterKey(keyBytes)); } public async Task ClearMasterKeyAsync(string userId = null) @@ -431,7 +425,7 @@ namespace Bit.Core.Services public async Task MakePinKeyAsync(string pin, string salt, KdfConfig config) { - var pinKey = await MakeKeyAsync(pin, salt, config); + var pinKey = await MakeKeyAsync(pin, salt, config, keyBytes => new PinKey(keyBytes)); return await StretchKeyAsync(pinKey) as PinKey; } @@ -881,7 +875,9 @@ namespace Bit.Core.Services return new Tuple(new SymmetricCryptoKey(encKey) as T, encKeyEnc); } - private async Task MakeKeyAsync(string password, string salt, KdfConfig kdfConfig) + // TODO: This intantiator needs to be moved into each key type in order to get rid of the keyCreator hack + private async Task MakeKeyAsync(string password, string salt, KdfConfig kdfConfig, Func keyCreator) + where TKey : SymmetricCryptoKey { byte[] key = null; if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256) @@ -926,7 +922,7 @@ namespace Bit.Core.Services { throw new Exception("Unknown kdf."); } - return new SymmetricCryptoKey(key); + return keyCreator(key); } private class EncryptedObject diff --git a/src/Core/Services/StateService.cs b/src/Core/Services/StateService.cs index 076ffd8e6..163f29d2a 100644 --- a/src/Core/Services/StateService.cs +++ b/src/Core/Services/StateService.cs @@ -395,16 +395,15 @@ namespace Bit.Core.Services await SetValueAsync(Constants.ProtectedPinKey(reconciledOptions.UserId), value, reconciledOptions); } - // TODO(Jake): Does this need to be secure storage? public async Task GetUserKeyPinAsync(string userId = null) { - return new EncString(await _storageMediatorService.GetAsync(Constants.UserKeyPinKey(userId), false)); + var key = await _storageMediatorService.GetAsync(Constants.UserKeyPinKey(userId), false); + return key != null ? new EncString(key) : null; } - // TODO(Jake): Does this need to be secure storage? public async Task SetUserKeyPinAsync(EncString value, string userId = null) { - await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value.EncryptedString, false); + await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value?.EncryptedString, false); } public async Task GetUserKeyPinEphemeralAsync(string userId = null)