mirror of
https://github.com/bitwarden/mobile
synced 2025-12-18 09:13:15 +00:00
[PM-2713] use new crypto service api in auth service
This commit is contained in:
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user