1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-17 16:53:26 +00:00

[PM-2713] use new crypto service api in auth service

This commit is contained in:
Jacob Fink
2023-07-19 11:30:07 -04:00
parent c9a7c29190
commit 0ff314f076
3 changed files with 35 additions and 211 deletions

View File

@@ -9,6 +9,7 @@ namespace Bit.Core.Abstractions
{ {
public interface ICryptoService public interface ICryptoService
{ {
void ClearCache();
Task ToggleKeysAsync(); Task ToggleKeysAsync();
Task SetUserKeyAsync(UserKey userKey, string userId = null); Task SetUserKeyAsync(UserKey userKey, string userId = null);
Task<UserKey> GetUserKeyAsync(string userId = null); Task<UserKey> GetUserKeyAsync(string userId = null);
@@ -57,21 +58,5 @@ namespace Bit.Core.Abstractions
Task<EncString> EncryptAsync(string plainValue, SymmetricCryptoKey key = null); Task<EncString> EncryptAsync(string plainValue, SymmetricCryptoKey key = null);
Task<EncByteArray> EncryptToBytesAsync(byte[] plainValue, SymmetricCryptoKey key = null); Task<EncByteArray> EncryptToBytesAsync(byte[] plainValue, SymmetricCryptoKey key = null);
Task<UserKey> DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey); Task<UserKey> DecryptAndMigrateOldPinKeyAsync(bool masterPasswordOnRestart, string pin, string email, KdfConfig kdfConfig, EncString oldPinKey);
void ClearCache();
Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null);
Task<SymmetricCryptoKey> GetKeyAsync(string userId = null);
Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key);
Task SetEncKeyAsync(string encKey);
Task SetKeyAsync(SymmetricCryptoKey key);
} }
} }

View File

@@ -30,7 +30,7 @@ namespace Bit.Core.Services
private readonly bool _setCryptoKeys; private readonly bool _setCryptoKeys;
private readonly LazyResolve<IWatchDeviceService> _watchDeviceService = new LazyResolve<IWatchDeviceService>(); private readonly LazyResolve<IWatchDeviceService> _watchDeviceService = new LazyResolve<IWatchDeviceService>();
private SymmetricCryptoKey _key; private MasterKey _masterKey;
private string _authedUserId; private string _authedUserId;
private MasterPasswordPolicyOptions _masterPasswordPolicy; private MasterPasswordPolicyOptions _masterPasswordPolicy;
@@ -199,7 +199,7 @@ namespace Bit.Core.Services
{ {
var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey); var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey);
var decPasswordHash = await _cryptoService.RsaDecryptAsync(localHashedPasswordCiphered, decryptionKey); var decPasswordHash = await _cryptoService.RsaDecryptAsync(localHashedPasswordCiphered, decryptionKey);
return await LogInHelperAsync(email, accessCode, Encoding.UTF8.GetString(decPasswordHash), null, null, null, new SymmetricCryptoKey(decKey), null, null, return await LogInHelperAsync(email, accessCode, Encoding.UTF8.GetString(decPasswordHash), null, null, null, new MasterKey(decKey), null, null,
null, null, authRequestId: authRequestId); null, null, authRequestId: authRequestId);
} }
@@ -216,7 +216,7 @@ namespace Bit.Core.Services
{ {
CaptchaToken = captchaToken; CaptchaToken = captchaToken;
} }
var result = await LogInHelperAsync(Email, MasterPasswordHash, LocalMasterPasswordHash, Code, CodeVerifier, SsoRedirectUrl, _key, var result = await LogInHelperAsync(Email, MasterPasswordHash, LocalMasterPasswordHash, Code, CodeVerifier, SsoRedirectUrl, _masterKey,
twoFactorProvider, twoFactorToken, remember, CaptchaToken, authRequestId: AuthRequestId); twoFactorProvider, twoFactorToken, remember, CaptchaToken, authRequestId: AuthRequestId);
// If we successfully authenticated and we have a saved _2faForcePasswordResetReason reason from LogInAsync() // If we successfully authenticated and we have a saved _2faForcePasswordResetReason reason from LogInAsync()
@@ -337,7 +337,7 @@ namespace Bit.Core.Services
// Helpers // Helpers
private async Task<SymmetricCryptoKey> MakePreloginKeyAsync(string masterPassword, string email) private async Task<MasterKey> MakePreloginKeyAsync(string masterPassword, string email)
{ {
email = email.Trim().ToLower(); email = email.Trim().ToLower();
KdfConfig kdfConfig = KdfConfig.Default; KdfConfig kdfConfig = KdfConfig.Default;
@@ -360,7 +360,7 @@ namespace Bit.Core.Services
} }
private async Task<AuthResult> LogInHelperAsync(string email, string hashedPassword, string localHashedPassword, private async Task<AuthResult> LogInHelperAsync(string email, string hashedPassword, string localHashedPassword,
string code, string codeVerifier, string redirectUrl, SymmetricCryptoKey key, string code, string codeVerifier, string redirectUrl, MasterKey masterKey,
TwoFactorProviderType? twoFactorProvider = null, string twoFactorToken = null, bool? remember = null, TwoFactorProviderType? twoFactorProvider = null, string twoFactorToken = null, bool? remember = null,
string captchaToken = null, string orgId = null, string authRequestId = null) string captchaToken = null, string orgId = null, string authRequestId = null)
{ {
@@ -426,7 +426,7 @@ namespace Bit.Core.Services
Code = code; Code = code;
CodeVerifier = codeVerifier; CodeVerifier = codeVerifier;
SsoRedirectUrl = redirectUrl; SsoRedirectUrl = redirectUrl;
_key = _setCryptoKeys ? key : null; _masterKey = _setCryptoKeys ? masterKey : null;
TwoFactorProvidersData = response.TwoFactorResponse.TwoFactorProviders2; TwoFactorProvidersData = response.TwoFactorResponse.TwoFactorProviders2;
result.TwoFactorProviders = response.TwoFactorResponse.TwoFactorProviders2; result.TwoFactorProviders = response.TwoFactorResponse.TwoFactorProviders2;
CaptchaToken = response.TwoFactorResponse.CaptchaToken; CaptchaToken = response.TwoFactorResponse.CaptchaToken;
@@ -470,9 +470,9 @@ namespace Bit.Core.Services
_messagingService.Send("accountAdded"); _messagingService.Send("accountAdded");
if (_setCryptoKeys) if (_setCryptoKeys)
{ {
if (key != null) if (masterKey != null)
{ {
await _cryptoService.SetKeyAsync(key); await _cryptoService.SetMasterKeyAsync(masterKey);
} }
if (localHashedPassword != null) if (localHashedPassword != null)
@@ -487,7 +487,7 @@ namespace Bit.Core.Services
await _keyConnectorService.GetAndSetKey(tokenResponse.KeyConnectorUrl); await _keyConnectorService.GetAndSetKey(tokenResponse.KeyConnectorUrl);
} }
await _cryptoService.SetEncKeyAsync(tokenResponse.Key); await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key);
// User doesn't have a key pair yet (old account), let's generate one for them. // User doesn't have a key pair yet (old account), let's generate one for them.
if (tokenResponse.PrivateKey == null) if (tokenResponse.PrivateKey == null)
@@ -511,13 +511,16 @@ namespace Bit.Core.Services
{ {
// SSO Key Connector Onboarding // SSO Key Connector Onboarding
var password = await _cryptoFunctionService.RandomBytesAsync(64); var password = await _cryptoFunctionService.RandomBytesAsync(64);
var masterKey = await _cryptoService.MakeMasterKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig); var newMasterKey = await _cryptoService.MakeMasterKeyAsync(Convert.ToBase64String(password), _tokenService.GetEmail(), tokenResponse.KdfConfig);
var keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.EncKeyB64); var keyConnectorRequest = new KeyConnectorUserKeyRequest(newMasterKey.EncKeyB64);
await _cryptoService.SetKeyAsync(masterKey); await _cryptoService.SetMasterKeyAsync(newMasterKey);
var encKey = await _cryptoService.MakeEncKeyAsync(masterKey); var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(
await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString); newMasterKey,
var keyPair = await _cryptoService.MakeKeyPairAsync(); await _cryptoService.MakeUserKeyAsync());
await _cryptoService.SetUserKeyAsync(newUserKey);
var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync();
try try
{ {
@@ -530,11 +533,11 @@ namespace Bit.Core.Services
var keys = new KeysRequest var keys = new KeysRequest
{ {
PublicKey = keyPair.Item1, PublicKey = newPublicKey,
EncryptedPrivateKey = keyPair.Item2.EncryptedString EncryptedPrivateKey = newProtectedPrivateKey.EncryptedString
}; };
var setPasswordRequest = new SetKeyConnectorKeyRequest( var setPasswordRequest = new SetKeyConnectorKeyRequest(
encKey.Item2.EncryptedString, keys, tokenResponse.KdfConfig, orgId newProtectedPrivateKey.EncryptedString, keys, tokenResponse.KdfConfig, orgId
); );
await _apiService.PostSetKeyConnectorKey(setPasswordRequest); await _apiService.PostSetKeyConnectorKey(setPasswordRequest);
} }
@@ -549,7 +552,7 @@ namespace Bit.Core.Services
private void ClearState() private void ClearState()
{ {
_key = null; _masterKey = null;
Email = null; Email = null;
CaptchaToken = null; CaptchaToken = null;
MasterPasswordHash = null; MasterPasswordHash = null;
@@ -590,7 +593,7 @@ namespace Bit.Core.Services
public async Task<PasswordlessLoginResponse> PasswordlessLoginAsync(string id, string pubKey, bool requestApproved) public async Task<PasswordlessLoginResponse> PasswordlessLoginAsync(string id, string pubKey, bool requestApproved)
{ {
var publicKey = CoreHelpers.Base64UrlDecode(pubKey); var publicKey = CoreHelpers.Base64UrlDecode(pubKey);
var masterKey = await _cryptoService.GetKeyAsync(); var masterKey = await _cryptoService.GetMasterKeyAsync();
var encryptedKey = await _cryptoService.RsaEncryptAsync(masterKey.EncKey, publicKey); var encryptedKey = await _cryptoService.RsaEncryptAsync(masterKey.EncKey, publicKey);
var encryptedMasterPassword = await _cryptoService.RsaEncryptAsync(Encoding.UTF8.GetBytes(await _stateService.GetKeyHashAsync()), publicKey); var encryptedMasterPassword = await _cryptoService.RsaEncryptAsync(Encoding.UTF8.GetBytes(await _stateService.GetKeyHashAsync()), publicKey);
var deviceId = await _appIdService.GetAppIdAsync(); var deviceId = await _appIdService.GetAppIdAsync();

View File

@@ -36,6 +36,16 @@ namespace Bit.Core.Services
_cryptoFunctionService = cryptoFunctionService; _cryptoFunctionService = cryptoFunctionService;
} }
public void ClearCache()
{
_encKey = null;
_legacyEtmKey = null;
_passwordHash = null;
_publicKey = null;
_privateKey = null;
_orgKeys = null;
}
public async Task ToggleKeysAsync() public async Task ToggleKeysAsync()
{ {
// refresh or clear the pin key // refresh or clear the pin key
@@ -216,7 +226,7 @@ namespace Bit.Core.Services
{ {
if (key == null) if (key == null)
{ {
key = await GetKeyAsync(); key = await GetMasterKeyAsync();
} }
if (password == null || key == null) if (password == null || key == null)
{ {
@@ -806,20 +816,6 @@ namespace Bit.Core.Services
} }
private async Task<SymmetricCryptoKey> GetKeyForEncryptionAsync(SymmetricCryptoKey key = null)
{
if (key != null)
{
return key;
}
var encKey = await GetEncKeyAsync();
if (encKey != null)
{
return encKey;
}
return await GetKeyAsync();
}
private SymmetricCryptoKey ResolveLegacyKey(EncryptionType encKey, SymmetricCryptoKey key) private SymmetricCryptoKey ResolveLegacyKey(EncryptionType encKey, SymmetricCryptoKey key)
{ {
if (encKey == EncryptionType.AesCbc128_HmacSha256_B64 && key.EncType == EncryptionType.AesCbc256_B64) if (encKey == EncryptionType.AesCbc128_HmacSha256_B64 && key.EncType == EncryptionType.AesCbc256_B64)
@@ -995,165 +991,5 @@ namespace Bit.Core.Services
await _stateService.SetPinProtectedAsync(null); await _stateService.SetPinProtectedAsync(null);
await _stateService.SetPinProtectedKeyAsync(null); await _stateService.SetPinProtectedKeyAsync(null);
} }
public async Task SetKeyAsync(SymmetricCryptoKey key)
{
await _stateService.SetKeyDecryptedAsync(key);
var option = await _stateService.GetVaultTimeoutAsync();
var biometric = await _stateService.GetBiometricUnlockAsync();
if (option.HasValue && !biometric.GetValueOrDefault())
{
// If we have a lock option set, we do not store the key
return;
}
await _stateService.SetKeyEncryptedAsync(key?.KeyB64);
}
public async Task SetEncKeyAsync(string encKey)
{
if (encKey == null)
{
return;
}
await _stateService.SetEncKeyEncryptedAsync(encKey);
_encKey = null;
}
public async Task<SymmetricCryptoKey> GetKeyAsync(string userId = null)
{
var inMemoryKey = await _stateService.GetKeyDecryptedAsync(userId);
if (inMemoryKey != null)
{
return inMemoryKey;
}
var key = await _stateService.GetKeyEncryptedAsync(userId);
if (key != null)
{
inMemoryKey = new SymmetricCryptoKey(Convert.FromBase64String(key));
await _stateService.SetKeyDecryptedAsync(inMemoryKey, userId);
}
return inMemoryKey;
}
public Task<SymmetricCryptoKey> GetEncKeyAsync(SymmetricCryptoKey key = null)
{
if (_encKey != null)
{
return Task.FromResult(_encKey);
}
if (_getEncKeysTask != null && !_getEncKeysTask.IsCompleted && !_getEncKeysTask.IsFaulted)
{
return _getEncKeysTask;
}
async Task<SymmetricCryptoKey> doTask()
{
try
{
var encKey = await _stateService.GetEncKeyEncryptedAsync();
if (encKey == null)
{
return null;
}
if (key == null)
{
key = await GetKeyAsync();
}
if (key == null)
{
return null;
}
byte[] decEncKey = null;
var encKeyCipher = new EncString(encKey);
if (encKeyCipher.EncryptionType == EncryptionType.AesCbc256_B64)
{
decEncKey = await DecryptToBytesAsync(encKeyCipher, key);
}
else if (encKeyCipher.EncryptionType == EncryptionType.AesCbc256_HmacSha256_B64)
{
var newKey = await StretchKeyAsync(key);
decEncKey = await DecryptToBytesAsync(encKeyCipher, newKey);
}
else
{
throw new Exception("Unsupported encKey type.");
}
if (decEncKey == null)
{
return null;
}
_encKey = new SymmetricCryptoKey(decEncKey);
return _encKey;
}
finally
{
_getEncKeysTask = null;
}
}
_getEncKeysTask = doTask();
return _getEncKeysTask;
}
public void ClearCache()
{
_encKey = null;
_legacyEtmKey = null;
_passwordHash = null;
_publicKey = null;
_privateKey = null;
_orgKeys = null;
}
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeEncKeyAsync(SymmetricCryptoKey key)
{
var theKey = await GetKeyForEncryptionAsync(key);
var encKey = await _cryptoFunctionService.RandomBytesAsync(64);
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(theKey, encKey);
}
} }
} }