mirror of
https://github.com/bitwarden/mobile
synced 2025-12-15 15:53:44 +00:00
Merge branch 'auth/pm-2713/drop-master-key-dependency' into feature/pm-1029-tde-login
This commit is contained in:
@@ -39,7 +39,7 @@ namespace Bit.App.Pages
|
||||
private string _masterPassword;
|
||||
private string _pin;
|
||||
private bool _showPassword;
|
||||
private PinLockEnum _pinStatus;
|
||||
private PinLockType _pinStatus;
|
||||
private bool _pinEnabled;
|
||||
private bool _biometricEnabled;
|
||||
private bool _biometricIntegrityValid = true;
|
||||
@@ -171,12 +171,12 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
|
||||
_pinStatus = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||
_pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync();
|
||||
|
||||
var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync()
|
||||
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
||||
?? await _stateService.GetPinProtectedKeyAsync();
|
||||
PinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockEnum.Persistent;
|
||||
PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockType.Persistent;
|
||||
|
||||
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync();
|
||||
|
||||
@@ -278,15 +278,15 @@ namespace Bit.App.Pages
|
||||
{
|
||||
EncString userKeyPin = null;
|
||||
EncString oldPinProtected = null;
|
||||
if (_pinStatus == PinLockEnum.Persistent)
|
||||
if (_pinStatus == PinLockType.Persistent)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync();
|
||||
var oldEncryptedKey = await _stateService.GetPinProtectedAsync();
|
||||
oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null;
|
||||
}
|
||||
else if (_pinStatus == PinLockEnum.Transient)
|
||||
else if (_pinStatus == PinLockType.Transient)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync();
|
||||
oldPinProtected = await _stateService.GetPinProtectedKeyAsync();
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace Bit.App.Pages
|
||||
if (oldPinProtected != null)
|
||||
{
|
||||
userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync(
|
||||
_pinStatus == PinLockEnum.Transient,
|
||||
_pinStatus == PinLockType.Transient,
|
||||
Pin,
|
||||
_email,
|
||||
kdfConfig,
|
||||
@@ -340,20 +340,20 @@ namespace Bit.App.Pages
|
||||
else
|
||||
{
|
||||
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, _email, kdfConfig);
|
||||
var storedKeyHash = await _cryptoService.GetPasswordHashAsync();
|
||||
var storedKeyHash = await _cryptoService.GetMasterKeyHashAsync();
|
||||
var passwordValid = false;
|
||||
MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null;
|
||||
|
||||
if (storedKeyHash != null)
|
||||
{
|
||||
// Offline unlock possible
|
||||
passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(MasterPassword, masterKey);
|
||||
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, masterKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Online unlock required
|
||||
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
|
||||
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization);
|
||||
var keyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.ServerAuthorization);
|
||||
var request = new PasswordVerificationRequest();
|
||||
request.MasterPasswordHash = keyHash;
|
||||
|
||||
@@ -362,8 +362,8 @@ namespace Bit.App.Pages
|
||||
var response = await _apiService.PostAccountVerifyPasswordAsync(request);
|
||||
enforcedMasterPasswordOptions = response.MasterPasswordPolicy;
|
||||
passwordValid = true;
|
||||
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization);
|
||||
await _cryptoService.SetPasswordHashAsync(localKeyHash);
|
||||
var localKeyHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey, HashPurpose.LocalAuthorization);
|
||||
await _cryptoService.SetMasterKeyHashAsync(localKeyHash);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -178,11 +178,8 @@ namespace Bit.App.Pages
|
||||
Email = Email.Trim().ToLower();
|
||||
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
||||
var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, Email, kdfConfig);
|
||||
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(
|
||||
newMasterKey,
|
||||
await _cryptoService.MakeUserKeyAsync()
|
||||
);
|
||||
var hashedPassword = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey);
|
||||
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey);
|
||||
var hashedPassword = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey);
|
||||
var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey);
|
||||
var request = new RegisterRequest
|
||||
{
|
||||
|
||||
@@ -166,13 +166,12 @@ namespace Bit.App.Pages
|
||||
var kdfConfig = new KdfConfig(KdfType.PBKDF2_SHA256, Constants.Pbkdf2Iterations, null, null);
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var newMasterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig);
|
||||
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization);
|
||||
var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization);
|
||||
var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.ServerAuthorization);
|
||||
var localMasterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, newMasterKey, HashPurpose.LocalAuthorization);
|
||||
|
||||
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey,
|
||||
await _cryptoService.GetUserKeyAsync() ?? await _cryptoService.MakeUserKeyAsync());
|
||||
var (newUserKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(newMasterKey);
|
||||
|
||||
var keys = await _cryptoService.MakeKeyPairAsync(newUserKey);
|
||||
var (newPublicKey, newProtectedPrivateKey) = await _cryptoService.MakeKeyPairAsync(newUserKey);
|
||||
var request = new SetPasswordRequest
|
||||
{
|
||||
MasterPasswordHash = masterPasswordHash,
|
||||
@@ -185,8 +184,8 @@ namespace Bit.App.Pages
|
||||
OrgIdentifier = OrgIdentifier,
|
||||
Keys = new KeysRequest
|
||||
{
|
||||
PublicKey = keys.Item1,
|
||||
EncryptedPrivateKey = keys.Item2.EncryptedString
|
||||
PublicKey = newPublicKey,
|
||||
EncryptedPrivateKey = newProtectedPrivateKey.EncryptedString
|
||||
}
|
||||
};
|
||||
|
||||
@@ -196,10 +195,11 @@ namespace Bit.App.Pages
|
||||
// Set Password and relevant information
|
||||
await _apiService.SetPasswordAsync(request);
|
||||
await _stateService.SetKdfConfigurationAsync(kdfConfig);
|
||||
await _cryptoService.SetUserKeyAsync(newUserKey);
|
||||
await _cryptoService.SetMasterKeyAsync(newMasterKey);
|
||||
await _cryptoService.SetPasswordHashAsync(localMasterPasswordHash);
|
||||
await _cryptoService.SetMasterKeyHashAsync(localMasterPasswordHash);
|
||||
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(newProtectedUserKey.EncryptedString);
|
||||
await _cryptoService.SetPrivateKeyAsync(keys.Item2.EncryptedString);
|
||||
await _cryptoService.SetUserPrivateKeyAsync(newProtectedPrivateKey.EncryptedString);
|
||||
|
||||
if (ResetPasswordAutoEnroll)
|
||||
{
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Bit.App.Pages
|
||||
|
||||
// Create new master key and hash new password
|
||||
var masterKey = await _cryptoService.MakeMasterKeyAsync(MasterPassword, email, kdfConfig);
|
||||
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, masterKey);
|
||||
var masterPasswordHash = await _cryptoService.HashMasterKeyAsync(MasterPassword, masterKey);
|
||||
|
||||
// Encrypt user key with new master key
|
||||
var (userKey, newProtectedUserKey) = await _cryptoService.EncryptUserKeyWithMasterKeyAsync(masterKey);
|
||||
@@ -155,7 +155,7 @@ namespace Bit.App.Pages
|
||||
|
||||
private async Task UpdatePasswordAsync(string newMasterPasswordHash, string newEncKey)
|
||||
{
|
||||
var currentPasswordHash = await _cryptoService.HashPasswordAsync(CurrentMasterPassword, null);
|
||||
var currentPasswordHash = await _cryptoService.HashMasterKeyAsync(CurrentMasterPassword, null);
|
||||
|
||||
var request = new PasswordRequest
|
||||
{
|
||||
|
||||
@@ -150,8 +150,8 @@ namespace Bit.App.Pages
|
||||
t.Value != null).ToList();
|
||||
}
|
||||
|
||||
var pinSet = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||
_pin = pinSet != PinLockEnum.Disabled;
|
||||
var pinSet = await _vaultTimeoutService.GetPinLockTypeAsync();
|
||||
_pin = pinSet != PinLockType.Disabled;
|
||||
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
|
||||
_screenCaptureAllowed = await _stateService.GetScreenCaptureAllowedAsync();
|
||||
|
||||
@@ -335,6 +335,7 @@ namespace Bit.App.Pages
|
||||
}
|
||||
if (oldTimeout != newTimeout)
|
||||
{
|
||||
await _cryptoService.RefreshKeysAsync();
|
||||
await Device.InvokeOnMainThreadAsync(BuildList);
|
||||
}
|
||||
}
|
||||
@@ -454,18 +455,18 @@ namespace Bit.App.Pages
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
var pinKey = await _cryptoService.MakePinKeyAsync(pin, email, kdfConfig);
|
||||
var userKey = await _cryptoService.GetUserKeyAsync();
|
||||
var pinProtectedKey = await _cryptoService.EncryptAsync(userKey.Key, pinKey);
|
||||
var protectedPinKey = await _cryptoService.EncryptAsync(userKey.Key, pinKey);
|
||||
|
||||
var encPin = await _cryptoService.EncryptAsync(pin);
|
||||
await _stateService.SetProtectedPinAsync(encPin.EncryptedString);
|
||||
|
||||
if (masterPassOnRestart)
|
||||
{
|
||||
await _stateService.SetUserKeyPinEphemeralAsync(pinProtectedKey);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(protectedPinKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _stateService.SetUserKeyPinAsync(pinProtectedKey);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyAsync(protectedPinKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -507,7 +508,7 @@ namespace Bit.App.Pages
|
||||
await UpdateVaultTimeoutActionIfNeededAsync();
|
||||
}
|
||||
await _stateService.SetBiometricLockedAsync(false);
|
||||
await _cryptoService.ToggleKeysAsync();
|
||||
await _cryptoService.RefreshKeysAsync();
|
||||
BuildList();
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace Bit.App.Services
|
||||
return false;
|
||||
};
|
||||
|
||||
return await _cryptoService.CompareAndUpdatePasswordHashAsync(password, null);
|
||||
return await _cryptoService.CompareAndUpdateKeyHashAsync(password, null);
|
||||
}
|
||||
|
||||
public async Task<bool> Enabled()
|
||||
|
||||
@@ -206,6 +206,7 @@ namespace Bit.App.Utilities.AccountManagement
|
||||
|
||||
private async Task AddAccountAsync()
|
||||
{
|
||||
await AppHelpers.ClearServiceCacheAsync();
|
||||
await Device.InvokeOnMainThreadAsync(() =>
|
||||
{
|
||||
Options.HideAccountSwitcher = false;
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Bit.App.Utilities
|
||||
}
|
||||
|
||||
var parameters = GetParameters();
|
||||
parameters.Secret = await _cryptoService.HashPasswordAsync(password, null);
|
||||
parameters.Secret = await _cryptoService.HashMasterKeyAsync(password, null);
|
||||
parameters.VerificationType = VerificationType.MasterPassword;
|
||||
await ExecuteAsync(parameters);
|
||||
break;
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Bit.Core.Abstractions
|
||||
public interface ICryptoService
|
||||
{
|
||||
void ClearCache();
|
||||
Task ToggleKeysAsync();
|
||||
Task RefreshKeysAsync();
|
||||
Task SetUserKeyAsync(UserKey userKey, string userId = null);
|
||||
Task<UserKey> GetUserKeyAsync(string userId = null);
|
||||
Task<UserKey> GetUserKeyWithLegacySupportAsync(string userId = null);
|
||||
@@ -19,26 +19,27 @@ namespace Bit.Core.Abstractions
|
||||
Task<UserKey> MakeUserKeyAsync();
|
||||
Task ClearUserKeyAsync(string userId = null);
|
||||
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
||||
Task<UserKey> GetAutoUnlockKeyAsync(string userId = null);
|
||||
Task<bool> HasAutoUnlockKeyAsync(string userId = null);
|
||||
Task SetMasterKeyAsync(MasterKey masterKey, string userId = null);
|
||||
Task<MasterKey> GetMasterKeyAsync(string userId = null);
|
||||
Task<MasterKey> MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig);
|
||||
Task ClearMasterKeyAsync(string userId = null);
|
||||
Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null);
|
||||
Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey);
|
||||
Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null);
|
||||
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key);
|
||||
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key);
|
||||
Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
|
||||
Task SetPasswordHashAsync(string keyHash);
|
||||
Task<string> GetPasswordHashAsync();
|
||||
Task ClearPasswordHashAsync(string userId = null);
|
||||
Task<bool> CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key);
|
||||
Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(SymmetricCryptoKey key);
|
||||
Task<string> HashMasterKeyAsync(string password, MasterKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization);
|
||||
Task SetMasterKeyHashAsync(string keyHash);
|
||||
Task<string> GetMasterKeyHashAsync();
|
||||
Task ClearMasterKeyHashAsync(string userId = null);
|
||||
Task<bool> CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key);
|
||||
Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs);
|
||||
Task<OrgKey> GetOrgKeyAsync(string orgId);
|
||||
Task<Dictionary<string, OrgKey>> GetOrgKeysAsync();
|
||||
Task ClearOrgKeysAsync(bool memoryOnly = false, string userId = null);
|
||||
Task<byte[]> GetPublicKeyAsync();
|
||||
Task SetPrivateKeyAsync(string encPrivateKey);
|
||||
Task<byte[]> GetPrivateKeyAsync();
|
||||
Task<byte[]> GetUserPublicKeyAsync();
|
||||
Task SetUserPrivateKeyAsync(string encPrivateKey);
|
||||
Task<byte[]> GetUserPrivateKeyAsync();
|
||||
Task<List<string>> GetFingerprintAsync(string userId, byte[] publicKey = null);
|
||||
Task<Tuple<string, EncString>> MakeKeyPairAsync(SymmetricCryptoKey key = null);
|
||||
Task ClearKeyPairAsync(bool memoryOnly = false, string userId = null);
|
||||
|
||||
@@ -17,8 +17,10 @@ namespace Bit.Core.Abstractions
|
||||
Task SetUserKeyAsync(UserKey value, string userId = null);
|
||||
Task<MasterKey> GetMasterKeyAsync(string userId = null);
|
||||
Task SetMasterKeyAsync(MasterKey value, string userId = null);
|
||||
Task<string> GetUserKeyMasterKeyAsync(string userId = null);
|
||||
Task SetUserKeyMasterKeyAsync(string value, string userId = null);
|
||||
Task<string> GetMasterKeyEncryptedUserKeyAsync(string userId = null);
|
||||
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
|
||||
Task<UserKey> GetUserKeyAutoUnlockAsync(string userId = null);
|
||||
Task SetUserKeyAutoUnlockAsync(string value, string userId = null);
|
||||
Task<string> GetActiveUserIdAsync();
|
||||
Task<string> GetActiveUserEmailAsync();
|
||||
Task<T> GetActiveUserCustomDataAsync<T>(Func<Account, T> dataMapper);
|
||||
@@ -44,19 +46,11 @@ namespace Bit.Core.Abstractions
|
||||
Task<bool> CanAccessPremiumAsync(string userId = null);
|
||||
Task<string> GetProtectedPinAsync(string userId = null);
|
||||
Task SetPersonalPremiumAsync(bool value, string userId = null);
|
||||
Task<EncString> GetUserKeyPinAsync(string userId = null);
|
||||
Task SetUserKeyPinAsync(EncString value, string userId = null);
|
||||
Task<EncString> GetUserKeyPinEphemeralAsync(string userId = null);
|
||||
Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null);
|
||||
Task<EncString> GetPinKeyEncryptedUserKeyAsync(string userId = null);
|
||||
Task SetPinKeyEncryptedUserKeyAsync(EncString value, string userId = null);
|
||||
Task<EncString> GetPinKeyEncryptedUserKeyEphemeralAsync(string userId = null);
|
||||
Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null);
|
||||
Task SetProtectedPinAsync(string value, string userId = null);
|
||||
[Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")]
|
||||
Task<string> GetPinProtectedAsync(string userId = null);
|
||||
[Obsolete("Use SetUserKeyPinAsync instead")]
|
||||
Task SetPinProtectedAsync(string value, string userId = null);
|
||||
[Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")]
|
||||
Task<EncString> GetPinProtectedKeyAsync(string userId = null);
|
||||
[Obsolete("Use SetUserKeyPinEphemeralAsync instead")]
|
||||
Task SetPinProtectedKeyAsync(EncString value, string userId = null);
|
||||
Task SetKdfConfigurationAsync(KdfConfig config, string userId = null);
|
||||
Task<string> GetKeyHashAsync(string userId = null);
|
||||
Task SetKeyHashAsync(string value, string userId = null);
|
||||
@@ -191,17 +185,24 @@ namespace Bit.Core.Abstractions
|
||||
void SetConfigs(ConfigResponse value);
|
||||
Task<bool> GetShouldTrustDeviceAsync();
|
||||
Task SetShouldTrustDeviceAsync(bool value);
|
||||
[Obsolete("Use GetUserKeyMasterKey instead")]
|
||||
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
Task<string> GetPinProtectedAsync(string userId = null);
|
||||
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
Task SetPinProtectedAsync(string value, string userId = null);
|
||||
[Obsolete("Use GetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")]
|
||||
Task<EncString> GetPinProtectedKeyAsync(string userId = null);
|
||||
[Obsolete("Use SetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")]
|
||||
Task SetPinProtectedKeyAsync(EncString value, string userId = null);
|
||||
[Obsolete("Use GetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
Task<string> GetEncKeyEncryptedAsync(string userId = null);
|
||||
[Obsolete("Use SetUserKeyMasterKey instead")]
|
||||
[Obsolete("Use SetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
Task SetEncKeyEncryptedAsync(string value, string userId = null);
|
||||
[Obsolete]
|
||||
Task<string> GetKeyEncryptedAsync(string userId = null);
|
||||
[Obsolete]
|
||||
[Obsolete("Left for migration purposes")]
|
||||
Task SetKeyEncryptedAsync(string value, string userId = null);
|
||||
[Obsolete("Use GetMasterKey instead")]
|
||||
|
||||
[Obsolete("Use GetUserKeyAutoUnlock instead, left for migration purposes")]
|
||||
Task<string> GetKeyEncryptedAsync(string userId = null);
|
||||
[Obsolete("Use GetMasterKeyAsync instead, left for migration purposes")]
|
||||
Task<SymmetricCryptoKey> GetKeyDecryptedAsync(string userId = null);
|
||||
[Obsolete("Use GetMasterKey instead")]
|
||||
Task SetKeyDecryptedAsync(SymmetricCryptoKey value, string userId = null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Bit.Core.Abstractions
|
||||
Task<bool> ShouldLockAsync(string userId = null);
|
||||
Task<bool> IsLoggedOutByTimeoutAsync(string userId = null);
|
||||
Task<bool> ShouldLogOutByTimeoutAsync(string userId = null);
|
||||
Task<PinLockEnum> IsPinLockSetAsync(string userId = null);
|
||||
Task<PinLockType> GetPinLockTypeAsync(string userId = null);
|
||||
Task<bool> IsBiometricLockSetAsync(string userId = null);
|
||||
Task LockAsync(bool allowSoftLock = false, bool userInitiated = false, string userId = null);
|
||||
Task LogOutAsync(bool userInitiated = true, string userId = null);
|
||||
|
||||
@@ -85,7 +85,8 @@ namespace Bit.Core
|
||||
|
||||
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 MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}";
|
||||
public static string UserKeyAutoUnlockKey(string userId) => $"autoUnlock_{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}";
|
||||
@@ -98,7 +99,7 @@ namespace Bit.Core
|
||||
public static string EncPrivateKeyKey(string userId) => $"encPrivateKey_{userId}";
|
||||
public static string DeviceKeyKey(string userId) => $"deviceKey_{userId}";
|
||||
public static string KeyHashKey(string userId) => $"keyHash_{userId}";
|
||||
public static string UserKeyPinKey(string userId) => $"userKeyPin_{userId}";
|
||||
public static string PinKeyEncryptedUserKeyKey(string userId) => $"pinKeyEncryptedUserKey_{userId}";
|
||||
public static string PassGenOptionsKey(string userId) => $"passwordGenerationOptions_{userId}";
|
||||
public static string PassGenHistoryKey(string userId) => $"generatedPasswordHistory_{userId}";
|
||||
public static string TwoFactorTokenKey(string email) => $"twoFactorToken_{email}";
|
||||
|
||||
@@ -151,8 +151,8 @@ namespace Bit.Core.Services
|
||||
SelectedTwoFactorProviderType = null;
|
||||
_2faForcePasswordResetReason = null;
|
||||
var key = await MakePreloginKeyAsync(masterPassword, email);
|
||||
var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key);
|
||||
var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key);
|
||||
var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken);
|
||||
|
||||
if (await RequirePasswordChangeAsync(email, masterPassword))
|
||||
@@ -265,8 +265,8 @@ namespace Bit.Core.Services
|
||||
{
|
||||
SelectedTwoFactorProviderType = null;
|
||||
var key = await MakePreloginKeyAsync(masterPassword, email);
|
||||
var hashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key);
|
||||
var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
var hashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key);
|
||||
var localHashedPassword = await _cryptoService.HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
return await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, twoFactorProvider,
|
||||
twoFactorToken, remember);
|
||||
}
|
||||
@@ -502,7 +502,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
if (localHashedPassword != null)
|
||||
{
|
||||
await _cryptoService.SetPasswordHashAsync(localHashedPassword);
|
||||
await _cryptoService.SetMasterKeyHashAsync(localHashedPassword);
|
||||
await _cryptoService.SetMasterKeyAsync(masterKey);
|
||||
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
|
||||
await _cryptoService.SetUserKeyAsync(userKey);
|
||||
@@ -558,7 +558,7 @@ namespace Bit.Core.Services
|
||||
catch { }
|
||||
}
|
||||
|
||||
await _cryptoService.SetPrivateKeyAsync(tokenResponse.PrivateKey);
|
||||
await _cryptoService.SetUserPrivateKeyAsync(tokenResponse.PrivateKey);
|
||||
}
|
||||
else if (tokenResponse.KeyConnectorUrl != null)
|
||||
{
|
||||
|
||||
@@ -250,8 +250,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
var hashKey = await _cryptoService.HasUserKeyAsync();
|
||||
if (!hashKey)
|
||||
if (!await _cryptoService.HasUserKeyAsync())
|
||||
{
|
||||
throw new Exception("No key.");
|
||||
}
|
||||
@@ -591,20 +590,9 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task<Cipher> SaveAttachmentRawWithServerAsync(Cipher cipher, string filename, byte[] data)
|
||||
{
|
||||
SymmetricCryptoKey attachmentKey;
|
||||
EncString protectedAttachmentKey;
|
||||
var orgKey = await _cryptoService.GetOrgKeyAsync(cipher.OrganizationId);
|
||||
if (orgKey != null)
|
||||
{
|
||||
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync();
|
||||
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey);
|
||||
}
|
||||
var (attachmentKey, protectedAttachmentKey, encKey) = await MakeAttachmentKeyAsync(cipher.OrganizationId);
|
||||
|
||||
var encFileName = await _cryptoService.EncryptAsync(filename, orgKey);
|
||||
var encFileName = await _cryptoService.EncryptAsync(filename, encKey);
|
||||
var encFileData = await _cryptoService.EncryptToBytesAsync(data, attachmentKey);
|
||||
|
||||
CipherResponse response;
|
||||
@@ -841,6 +829,14 @@ namespace Bit.Core.Services
|
||||
|
||||
// Helpers
|
||||
|
||||
private async Task<Tuple<SymmetricCryptoKey, EncString, SymmetricCryptoKey>> MakeAttachmentKeyAsync(string organizationId)
|
||||
{
|
||||
var encryptionKey = await _cryptoService.GetOrgKeyAsync(organizationId)
|
||||
?? (SymmetricCryptoKey)await _cryptoService.GetUserKeyWithLegacySupportAsync();
|
||||
var (attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(encryptionKey);
|
||||
return new Tuple<SymmetricCryptoKey, EncString, SymmetricCryptoKey>(attachmentKey, protectedAttachmentKey, encryptionKey);
|
||||
}
|
||||
|
||||
private async Task ShareAttachmentWithServerAsync(AttachmentView attachmentView, string cipherId,
|
||||
string organizationId)
|
||||
{
|
||||
@@ -853,20 +849,9 @@ namespace Bit.Core.Services
|
||||
var bytes = await attachmentResponse.Content.ReadAsByteArrayAsync();
|
||||
var decBytes = await _cryptoService.DecryptFromBytesAsync(bytes, null);
|
||||
|
||||
SymmetricCryptoKey attachmentKey;
|
||||
EncString protectedAttachmentKey;
|
||||
var orgKey = await _cryptoService.GetOrgKeyAsync(organizationId);
|
||||
if (orgKey != null)
|
||||
{
|
||||
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(orgKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
var userKey = await _cryptoService.GetUserKeyWithLegacySupportAsync();
|
||||
(attachmentKey, protectedAttachmentKey) = await _cryptoService.MakeDataEncKeyAsync(userKey);
|
||||
}
|
||||
var (attachmentKey, protectedAttachmentKey, encKey) = await MakeAttachmentKeyAsync(organizationId);
|
||||
|
||||
var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, orgKey);
|
||||
var encFileName = await _cryptoService.EncryptAsync(attachmentView.FileName, encKey);
|
||||
var encFileData = await _cryptoService.EncryptToBytesAsync(decBytes, attachmentKey);
|
||||
|
||||
var boundary = string.Concat("--BWMobileFormBoundary", DateTime.UtcNow.Ticks);
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Bit.Core.Services
|
||||
private readonly ICryptoFunctionService _cryptoFunctionService;
|
||||
|
||||
private SymmetricCryptoKey _legacyEtmKey;
|
||||
private string _passwordHash;
|
||||
private string _masterKeyHash;
|
||||
private byte[] _publicKey;
|
||||
private byte[] _privateKey;
|
||||
private Dictionary<string, OrgKey> _orgKeys;
|
||||
@@ -37,42 +37,28 @@ namespace Bit.Core.Services
|
||||
public void ClearCache()
|
||||
{
|
||||
_legacyEtmKey = null;
|
||||
_passwordHash = null;
|
||||
_masterKeyHash = null;
|
||||
_publicKey = null;
|
||||
_privateKey = null;
|
||||
_orgKeys = null;
|
||||
}
|
||||
|
||||
public async Task ToggleKeysAsync()
|
||||
public async Task RefreshKeysAsync()
|
||||
{
|
||||
// refresh or clear the pin key
|
||||
// Refresh or clear additional keys such as
|
||||
// pin and auto unlock keys
|
||||
await SetUserKeyAsync(await GetUserKeyAsync());
|
||||
|
||||
// refresh or clear the encrypted user key
|
||||
var encUserKey = await _stateService.GetUserKeyMasterKeyAsync();
|
||||
await _stateService.SetUserKeyMasterKeyAsync(null);
|
||||
await _stateService.SetUserKeyMasterKeyAsync(encUserKey);
|
||||
}
|
||||
|
||||
public async Task SetUserKeyAsync(UserKey userKey, string userId = null)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _stateService.SetUserKeyPinAsync(null, userId);
|
||||
await _stateService.SetUserKeyPinEphemeralAsync(null, userId);
|
||||
}
|
||||
await StoreAdditionalKeysAsync(userKey, userId);
|
||||
}
|
||||
|
||||
public async Task<UserKey> GetUserKeyAsync(string userId = null)
|
||||
public Task<UserKey> GetUserKeyAsync(string userId = null)
|
||||
{
|
||||
return await _stateService.GetUserKeyAsync(userId);
|
||||
return _stateService.GetUserKeyAsync(userId);
|
||||
}
|
||||
|
||||
public async Task<UserKey> GetUserKeyWithLegacySupportAsync(string userId = null)
|
||||
@@ -85,7 +71,7 @@ namespace Bit.Core.Services
|
||||
|
||||
// Legacy support: encryption used to be done with the master key (derived from master password).
|
||||
// Users who have not migrated will have a null user key and must use the master key instead.
|
||||
return (SymmetricCryptoKey)await GetMasterKeyAsync() as UserKey;
|
||||
return new UserKey((await GetMasterKeyAsync()).Key);
|
||||
}
|
||||
|
||||
public async Task<bool> HasUserKeyAsync(string userId = null)
|
||||
@@ -95,7 +81,7 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task<bool> HasEncryptedUserKeyAsync(string userId = null)
|
||||
{
|
||||
return await _stateService.GetUserKeyMasterKeyAsync(userId) != null;
|
||||
return await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId) != null;
|
||||
}
|
||||
|
||||
public async Task<UserKey> MakeUserKeyAsync()
|
||||
@@ -103,20 +89,30 @@ namespace Bit.Core.Services
|
||||
return new UserKey(await _cryptoFunctionService.RandomBytesAsync(64));
|
||||
}
|
||||
|
||||
public async Task ClearUserKeyAsync(string userId = null)
|
||||
public Task ClearUserKeyAsync(string userId = null)
|
||||
{
|
||||
await _stateService.SetUserKeyAsync(null, userId);
|
||||
return _stateService.SetUserKeyAsync(null, userId);
|
||||
}
|
||||
|
||||
public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null)
|
||||
public Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null)
|
||||
{
|
||||
await _stateService.SetUserKeyMasterKeyAsync(value, userId);
|
||||
return _stateService.SetMasterKeyEncryptedUserKeyAsync(value, userId);
|
||||
}
|
||||
|
||||
public async Task SetMasterKeyAsync(MasterKey masterKey, string userId = null)
|
||||
public async Task<UserKey> GetAutoUnlockKeyAsync(string userId = null)
|
||||
{
|
||||
await _stateService.SetMasterKeyAsync(masterKey, userId);
|
||||
await MigrateAutoUnlockKeyIfNeededAsync(userId);
|
||||
return await _stateService.GetUserKeyAutoUnlockAsync(userId);
|
||||
}
|
||||
|
||||
public async Task<bool> HasAutoUnlockKeyAsync(string userId = null)
|
||||
{
|
||||
return await GetAutoUnlockKeyAsync(userId) != null;
|
||||
}
|
||||
|
||||
public Task SetMasterKeyAsync(MasterKey masterKey, string userId = null)
|
||||
{
|
||||
return _stateService.SetMasterKeyAsync(masterKey, userId);
|
||||
}
|
||||
|
||||
public async Task<MasterKey> GetMasterKeyAsync(string userId = null)
|
||||
@@ -125,7 +121,7 @@ namespace Bit.Core.Services
|
||||
if (masterKey == null)
|
||||
{
|
||||
// Migration support
|
||||
masterKey = await _stateService.GetKeyDecryptedAsync(userId) as MasterKey;
|
||||
masterKey = new MasterKey((await _stateService.GetKeyDecryptedAsync(userId)).Key);
|
||||
if (masterKey != null)
|
||||
{
|
||||
await SetMasterKeyAsync(masterKey, userId);
|
||||
@@ -134,20 +130,20 @@ namespace Bit.Core.Services
|
||||
return masterKey;
|
||||
}
|
||||
|
||||
public async Task<MasterKey> MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig)
|
||||
public Task<MasterKey> MakeMasterKeyAsync(string password, string email, KdfConfig kdfConfig)
|
||||
{
|
||||
return await MakeKeyAsync(password, email, kdfConfig, keyBytes => new MasterKey(keyBytes));
|
||||
return MakeKeyAsync(password, email, kdfConfig, keyBytes => new MasterKey(keyBytes));
|
||||
}
|
||||
|
||||
public async Task ClearMasterKeyAsync(string userId = null)
|
||||
public Task ClearMasterKeyAsync(string userId = null)
|
||||
{
|
||||
await _stateService.SetMasterKeyAsync(null, userId);
|
||||
return _stateService.SetMasterKeyAsync(null, userId);
|
||||
}
|
||||
|
||||
public async Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey, UserKey userKey = null)
|
||||
public async Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey)
|
||||
{
|
||||
userKey ??= await GetUserKeyAsync();
|
||||
return await BuildProtectedSymmetricKey<UserKey>(masterKey, userKey.Key);
|
||||
var userKey = await GetUserKeyAsync() ?? await MakeUserKeyAsync();
|
||||
return await BuildProtectedSymmetricKey(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes));
|
||||
}
|
||||
|
||||
public async Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null)
|
||||
@@ -160,7 +156,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (encUserKey == null)
|
||||
{
|
||||
var userKeyMasterKey = await _stateService.GetUserKeyMasterKeyAsync(userId);
|
||||
var userKeyMasterKey = await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId);
|
||||
if (userKeyMasterKey == null)
|
||||
{
|
||||
throw new Exception("No encrypted user key found");
|
||||
@@ -175,12 +171,12 @@ namespace Bit.Core.Services
|
||||
}
|
||||
else if (encUserKey.EncryptionType == EncryptionType.AesCbc256_HmacSha256_B64)
|
||||
{
|
||||
var newKey = await StretchKeyAsync(masterKey);
|
||||
var newKey = await StretchKeyAsync(masterKey, keyBytes => new MasterKey(keyBytes));
|
||||
decUserKey = await DecryptToBytesAsync(encUserKey, newKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Unsupported encKey type.");
|
||||
throw new Exception($"Unsupported encrypted user key type: {encUserKey.EncryptionType}");
|
||||
}
|
||||
|
||||
if (decUserKey == null)
|
||||
@@ -190,86 +186,82 @@ namespace Bit.Core.Services
|
||||
return new UserKey(decUserKey);
|
||||
}
|
||||
|
||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(UserKey key)
|
||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(SymmetricCryptoKey key)
|
||||
{
|
||||
if (key == null)
|
||||
if (key is null)
|
||||
{
|
||||
throw new Exception("No user key provided");
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
if (!(key is UserKey) && !(key is OrgKey))
|
||||
{
|
||||
throw new ArgumentException($"Data encryption keys must be of type UserKey or OrgKey. {key.GetType().FullName} unsupported.");
|
||||
}
|
||||
|
||||
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey);
|
||||
return await BuildProtectedSymmetricKey(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes));
|
||||
}
|
||||
|
||||
public async Task<Tuple<SymmetricCryptoKey, EncString>> MakeDataEncKeyAsync(OrgKey key)
|
||||
public async Task<string> HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
|
||||
{
|
||||
if (key == null)
|
||||
if (password is null)
|
||||
{
|
||||
throw new Exception("No org key provided");
|
||||
throw new ArgumentNullException(nameof(password));
|
||||
}
|
||||
|
||||
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
|
||||
return await BuildProtectedSymmetricKey<SymmetricCryptoKey>(key, newSymKey);
|
||||
}
|
||||
if (masterKey is null)
|
||||
{
|
||||
masterKey = await GetMasterKeyAsync();
|
||||
|
||||
// TODO(Jake): Uses Master Key
|
||||
public async Task<string> HashPasswordAsync(string password, SymmetricCryptoKey key, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
key = await GetMasterKeyAsync();
|
||||
if (masterKey is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(masterKey));
|
||||
}
|
||||
}
|
||||
if (password == null || key == null)
|
||||
{
|
||||
throw new Exception("Invalid parameters.");
|
||||
}
|
||||
var iterations = hashPurpose == HashPurpose.LocalAuthorization ? 2 : 1;
|
||||
var hash = await _cryptoFunctionService.Pbkdf2Async(key.Key, password, CryptoHashAlgorithm.Sha256, iterations);
|
||||
var hash = await _cryptoFunctionService.Pbkdf2Async(masterKey.Key, password, CryptoHashAlgorithm.Sha256, (int)hashPurpose);
|
||||
return Convert.ToBase64String(hash);
|
||||
}
|
||||
|
||||
public async Task SetPasswordHashAsync(string keyHash)
|
||||
public Task SetMasterKeyHashAsync(string keyHash)
|
||||
{
|
||||
_passwordHash = keyHash;
|
||||
await _stateService.SetKeyHashAsync(keyHash);
|
||||
_masterKeyHash = keyHash;
|
||||
return _stateService.SetKeyHashAsync(keyHash);
|
||||
}
|
||||
|
||||
public async Task<string> GetPasswordHashAsync()
|
||||
public async Task<string> GetMasterKeyHashAsync()
|
||||
{
|
||||
if (_passwordHash != null)
|
||||
if (_masterKeyHash != null)
|
||||
{
|
||||
return _passwordHash;
|
||||
return _masterKeyHash;
|
||||
}
|
||||
var passwordHash = await _stateService.GetKeyHashAsync();
|
||||
if (passwordHash != null)
|
||||
{
|
||||
_passwordHash = passwordHash;
|
||||
_masterKeyHash = passwordHash;
|
||||
}
|
||||
return _passwordHash;
|
||||
return _masterKeyHash;
|
||||
}
|
||||
|
||||
public async Task ClearPasswordHashAsync(string userId = null)
|
||||
public Task ClearMasterKeyHashAsync(string userId = null)
|
||||
{
|
||||
_passwordHash = null;
|
||||
await _stateService.SetKeyHashAsync(null, userId);
|
||||
_masterKeyHash = null;
|
||||
return _stateService.SetKeyHashAsync(null, userId);
|
||||
}
|
||||
|
||||
// TODO(Jake): Uses Master Key
|
||||
public async Task<bool> CompareAndUpdatePasswordHashAsync(string masterPassword, MasterKey key)
|
||||
public async Task<bool> CompareAndUpdateKeyHashAsync(string masterPassword, MasterKey key)
|
||||
{
|
||||
var storedPasswordHash = await GetPasswordHashAsync();
|
||||
var storedPasswordHash = await GetMasterKeyHashAsync();
|
||||
if (masterPassword != null && storedPasswordHash != null)
|
||||
{
|
||||
var localPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
var localPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.LocalAuthorization);
|
||||
if (localPasswordHash != null && storedPasswordHash == localPasswordHash)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var serverPasswordHash = await HashPasswordAsync(masterPassword, key, HashPurpose.ServerAuthorization);
|
||||
if (serverPasswordHash != null & storedPasswordHash == serverPasswordHash)
|
||||
var serverPasswordHash = await HashMasterKeyAsync(masterPassword, key, HashPurpose.ServerAuthorization);
|
||||
if (serverPasswordHash != null && storedPasswordHash == serverPasswordHash)
|
||||
{
|
||||
await SetPasswordHashAsync(localPasswordHash);
|
||||
await SetMasterKeyHashAsync(localPasswordHash);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -277,11 +269,11 @@ namespace Bit.Core.Services
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs)
|
||||
public Task SetOrgKeysAsync(IEnumerable<ProfileOrganizationResponse> orgs)
|
||||
{
|
||||
var orgKeys = orgs.ToDictionary(org => org.Id, org => org.Key);
|
||||
_orgKeys = null;
|
||||
await _stateService.SetOrgKeysEncryptedAsync(orgKeys);
|
||||
return _stateService.SetOrgKeysEncryptedAsync(orgKeys);
|
||||
}
|
||||
|
||||
public async Task<OrgKey> GetOrgKeyAsync(string orgId)
|
||||
@@ -351,13 +343,13 @@ namespace Bit.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetPublicKeyAsync()
|
||||
public async Task<byte[]> GetUserPublicKeyAsync()
|
||||
{
|
||||
if (_publicKey != null)
|
||||
{
|
||||
return _publicKey;
|
||||
}
|
||||
var privateKey = await GetPrivateKeyAsync();
|
||||
var privateKey = await GetUserPrivateKeyAsync();
|
||||
if (privateKey == null)
|
||||
{
|
||||
return null;
|
||||
@@ -366,7 +358,7 @@ namespace Bit.Core.Services
|
||||
return _publicKey;
|
||||
}
|
||||
|
||||
public async Task SetPrivateKeyAsync(string encPrivateKey)
|
||||
public async Task SetUserPrivateKeyAsync(string encPrivateKey)
|
||||
{
|
||||
if (encPrivateKey == null)
|
||||
{
|
||||
@@ -376,7 +368,7 @@ namespace Bit.Core.Services
|
||||
_privateKey = null;
|
||||
}
|
||||
|
||||
public async Task<byte[]> GetPrivateKeyAsync()
|
||||
public async Task<byte[]> GetUserPrivateKeyAsync()
|
||||
{
|
||||
if (_privateKey != null)
|
||||
{
|
||||
@@ -395,7 +387,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
if (publicKey == null)
|
||||
{
|
||||
publicKey = await GetPublicKeyAsync();
|
||||
publicKey = await GetUserPublicKeyAsync();
|
||||
}
|
||||
if (publicKey == null)
|
||||
{
|
||||
@@ -426,28 +418,29 @@ namespace Bit.Core.Services
|
||||
public async Task<PinKey> MakePinKeyAsync(string pin, string salt, KdfConfig config)
|
||||
{
|
||||
var pinKey = await MakeKeyAsync(pin, salt, config, keyBytes => new PinKey(keyBytes));
|
||||
return await StretchKeyAsync(pinKey) as PinKey;
|
||||
return await StretchKeyAsync(pinKey, keyBytes => new PinKey(keyBytes));
|
||||
}
|
||||
|
||||
public async Task ClearPinKeysAsync(string userId = null)
|
||||
public Task ClearPinKeysAsync(string userId = null)
|
||||
{
|
||||
await _stateService.SetUserKeyPinAsync(null, userId);
|
||||
await _stateService.SetUserKeyPinEphemeralAsync(null, userId);
|
||||
await _stateService.SetProtectedPinAsync(null, userId);
|
||||
await clearDeprecatedPinKeysAsync(userId);
|
||||
return Task.WhenAll(
|
||||
_stateService.SetPinKeyEncryptedUserKeyAsync(null, userId),
|
||||
_stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId),
|
||||
_stateService.SetProtectedPinAsync(null, userId),
|
||||
ClearDeprecatedPinKeysAsync(userId));
|
||||
}
|
||||
|
||||
public async Task<UserKey> DecryptUserKeyWithPinAsync(string pin, string salt, KdfConfig kdfConfig, EncString pinProtectedUserKey = null)
|
||||
{
|
||||
pinProtectedUserKey ??= await _stateService.GetUserKeyPinAsync();
|
||||
pinProtectedUserKey ??= await _stateService.GetUserKeyPinEphemeralAsync();
|
||||
pinProtectedUserKey ??= await _stateService.GetPinKeyEncryptedUserKeyAsync();
|
||||
pinProtectedUserKey ??= await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync();
|
||||
if (pinProtectedUserKey == null)
|
||||
{
|
||||
throw new Exception("No PIN protected user key found.");
|
||||
}
|
||||
var pinKey = await MakePinKeyAsync(pin, salt, kdfConfig);
|
||||
var userKey = await DecryptToBytesAsync(pinProtectedUserKey, pinKey);
|
||||
return new UserKey(userKey);
|
||||
var userKeyBytes = await DecryptToBytesAsync(pinProtectedUserKey, pinKey);
|
||||
return new UserKey(userKeyBytes);
|
||||
}
|
||||
|
||||
// Only for migration purposes
|
||||
@@ -481,7 +474,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
if (publicKey == null)
|
||||
{
|
||||
publicKey = await GetPublicKeyAsync();
|
||||
publicKey = await GetUserPublicKeyAsync();
|
||||
}
|
||||
if (publicKey == null)
|
||||
{
|
||||
@@ -521,7 +514,7 @@ namespace Bit.Core.Services
|
||||
|
||||
if (privateKey is null)
|
||||
{
|
||||
privateKey = await GetPrivateKeyAsync();
|
||||
privateKey = await GetUserPrivateKeyAsync();
|
||||
}
|
||||
|
||||
if (privateKey == null)
|
||||
@@ -618,17 +611,17 @@ namespace Bit.Core.Services
|
||||
return await AesDecryptToBytesAsync(encType, ctBytes, ivBytes, macBytes, key);
|
||||
}
|
||||
|
||||
public async Task<byte[]> DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null)
|
||||
public Task<byte[]> DecryptToBytesAsync(EncString encString, SymmetricCryptoKey key = null)
|
||||
{
|
||||
var iv = Convert.FromBase64String(encString.Iv);
|
||||
var data = Convert.FromBase64String(encString.Data);
|
||||
var mac = !string.IsNullOrWhiteSpace(encString.Mac) ? Convert.FromBase64String(encString.Mac) : null;
|
||||
return await AesDecryptToBytesAsync(encString.EncryptionType, data, iv, mac, key);
|
||||
return AesDecryptToBytesAsync(encString.EncryptionType, data, iv, mac, key);
|
||||
}
|
||||
|
||||
public async Task<string> DecryptToUtf8Async(EncString encString, SymmetricCryptoKey key = null)
|
||||
public Task<string> DecryptToUtf8Async(EncString encString, SymmetricCryptoKey key = null)
|
||||
{
|
||||
return await AesDecryptToUtf8Async(encString.EncryptionType, encString.Data,
|
||||
return AesDecryptToUtf8Async(encString.EncryptionType, encString.Data,
|
||||
encString.Iv, encString.Mac, key);
|
||||
}
|
||||
|
||||
@@ -675,7 +668,31 @@ namespace Bit.Core.Services
|
||||
|
||||
// --HELPER METHODS--
|
||||
|
||||
private async Task StorePinKey(UserKey userKey, string userId = null)
|
||||
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
|
||||
{
|
||||
// Refresh, set, or clear the pin key
|
||||
if (await _stateService.GetProtectedPinAsync(userId) != null)
|
||||
{
|
||||
await UpdateUserKeyPinAsync(userKey, userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _stateService.SetPinKeyEncryptedUserKeyAsync(null, userId);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId);
|
||||
}
|
||||
|
||||
// Refresh, set, or clear the auto key
|
||||
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
|
||||
{
|
||||
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _stateService.SetUserKeyAutoUnlockAsync(null, userId);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateUserKeyPinAsync(UserKey userKey, string userId = null)
|
||||
{
|
||||
var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId)));
|
||||
var pinKey = await MakePinKeyAsync(
|
||||
@@ -685,13 +702,12 @@ namespace Bit.Core.Services
|
||||
);
|
||||
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)
|
||||
if (await _stateService.GetPinKeyEncryptedUserKeyAsync(userId) != null)
|
||||
{
|
||||
await _stateService.SetUserKeyPinAsync(encPin, userId);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyAsync(encPin, userId);
|
||||
return;
|
||||
}
|
||||
await _stateService.SetUserKeyPinEphemeralAsync(encPin, userId);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(encPin, userId);
|
||||
}
|
||||
|
||||
private async Task<EncryptedObject> AesEncryptAsync(byte[] data, SymmetricCryptoKey key)
|
||||
@@ -821,14 +837,16 @@ namespace Bit.Core.Services
|
||||
return key;
|
||||
}
|
||||
|
||||
private async Task<SymmetricCryptoKey> StretchKeyAsync(SymmetricCryptoKey key)
|
||||
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
|
||||
private async Task<TKey> StretchKeyAsync<TKey>(SymmetricCryptoKey key, Func<byte[], TKey> keyCreator)
|
||||
where TKey : SymmetricCryptoKey
|
||||
{
|
||||
var newKey = new byte[64];
|
||||
var enc = await _cryptoFunctionService.HkdfExpandAsync(key.Key, Encoding.UTF8.GetBytes("enc"), 32, HkdfAlgorithm.Sha256);
|
||||
Buffer.BlockCopy(enc, 0, newKey, 0, 32);
|
||||
var mac = await _cryptoFunctionService.HkdfExpandAsync(key.Key, Encoding.UTF8.GetBytes("mac"), 32, HkdfAlgorithm.Sha256);
|
||||
Buffer.BlockCopy(mac, 0, newKey, 32, 32);
|
||||
return new SymmetricCryptoKey(newKey);
|
||||
return keyCreator(newKey);
|
||||
}
|
||||
|
||||
private List<string> HashPhrase(byte[] hash, int minimumEntropy = 64)
|
||||
@@ -855,13 +873,14 @@ namespace Bit.Core.Services
|
||||
return phrase;
|
||||
}
|
||||
|
||||
private async Task<Tuple<T, EncString>> BuildProtectedSymmetricKey<T>(SymmetricCryptoKey key,
|
||||
byte[] encKey) where T : SymmetricCryptoKey
|
||||
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
|
||||
private async Task<Tuple<TKey, EncString>> BuildProtectedSymmetricKey<TKey>(SymmetricCryptoKey key,
|
||||
byte[] encKey, Func<byte[], TKey> keyCreator) where TKey : SymmetricCryptoKey
|
||||
{
|
||||
EncString encKeyEnc = null;
|
||||
if (key.Key.Length == 32)
|
||||
{
|
||||
var newKey = await StretchKeyAsync(key);
|
||||
var newKey = await StretchKeyAsync(key, keyCreator);
|
||||
encKeyEnc = await EncryptAsync(encKey, newKey);
|
||||
}
|
||||
else if (key.Key.Length == 64)
|
||||
@@ -872,10 +891,10 @@ namespace Bit.Core.Services
|
||||
{
|
||||
throw new Exception("Invalid key size.");
|
||||
}
|
||||
return new Tuple<T, EncString>(new SymmetricCryptoKey(encKey) as T, encKeyEnc);
|
||||
return new Tuple<TKey, EncString>(keyCreator(encKey), encKeyEnc);
|
||||
}
|
||||
|
||||
// TODO: This intantiator needs to be moved into each key type in order to get rid of the keyCreator hack
|
||||
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
|
||||
private async Task<TKey> MakeKeyAsync<TKey>(string password, string salt, KdfConfig kdfConfig, Func<byte[], TKey> keyCreator)
|
||||
where TKey : SymmetricCryptoKey
|
||||
{
|
||||
@@ -937,6 +956,27 @@ namespace Bit.Core.Services
|
||||
// We previously used the master key for additional keys, but now we use the user key.
|
||||
// These methods support migrating the old keys to the new ones.
|
||||
|
||||
private async Task MigrateAutoUnlockKeyIfNeededAsync(string userId = null)
|
||||
{
|
||||
var oldAutoKey = await _stateService.GetKeyEncryptedAsync(userId);
|
||||
if (oldAutoKey == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Decrypt
|
||||
var masterKey = new MasterKey(Convert.FromBase64String(oldAutoKey));
|
||||
var encryptedUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
|
||||
var userKey = await DecryptUserKeyWithMasterKeyAsync(
|
||||
masterKey,
|
||||
new EncString(encryptedUserKey),
|
||||
userId);
|
||||
// Migrate
|
||||
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
|
||||
await _stateService.SetKeyEncryptedAsync(null, userId);
|
||||
// Set encrypted user key just in case the user locks without syncing
|
||||
await SetMasterKeyEncryptedUserKeyAsync(encryptedUserKey);
|
||||
}
|
||||
|
||||
public async Task<UserKey> DecryptAndMigrateOldPinKeyAsync(
|
||||
bool masterPasswordOnRestart,
|
||||
string pin,
|
||||
@@ -964,25 +1004,28 @@ namespace Bit.Core.Services
|
||||
if (masterPasswordOnRestart)
|
||||
{
|
||||
await _stateService.SetPinProtectedKeyAsync(null);
|
||||
await _stateService.SetUserKeyPinEphemeralAsync(pinProtectedKey);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(pinProtectedKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _stateService.SetPinProtectedAsync(null);
|
||||
await _stateService.SetUserKeyPinAsync(pinProtectedKey);
|
||||
await _stateService.SetPinKeyEncryptedUserKeyAsync(pinProtectedKey);
|
||||
|
||||
// We previously only set the protected pin if MP on Restart was enabled
|
||||
// now we set it regardless
|
||||
var encPin = await EncryptAsync(pin, userKey);
|
||||
await _stateService.SetProtectedPinAsync(encPin.EncryptedString);
|
||||
}
|
||||
// Clear old key
|
||||
await _stateService.SetEncKeyEncryptedAsync(null);
|
||||
return userKey;
|
||||
}
|
||||
|
||||
public async Task clearDeprecatedPinKeysAsync(string userId = null)
|
||||
public Task ClearDeprecatedPinKeysAsync(string userId = null)
|
||||
{
|
||||
await _stateService.SetPinProtectedAsync(null);
|
||||
await _stateService.SetPinProtectedKeyAsync(null);
|
||||
return Task.WhenAll(
|
||||
_stateService.SetPinProtectedAsync(null, userId),
|
||||
_stateService.SetPinProtectedKeyAsync(null, userId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,18 +334,29 @@ namespace Bit.Core.Services
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
public async Task<string> GetUserKeyMasterKeyAsync(string userId = null)
|
||||
public async Task<string> GetMasterKeyEncryptedUserKeyAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultInMemoryOptionsAsync());
|
||||
return await _storageMediatorService.GetAsync<string>(Constants.UserKeyKey(reconciledOptions.UserId), false);
|
||||
return await _storageMediatorService.GetAsync<string>(
|
||||
await ComposeKeyAsync(Constants.MasterKeyEncryptedUserKeyKey, userId), false);
|
||||
}
|
||||
|
||||
public async Task SetUserKeyMasterKeyAsync(string value, string userId = null)
|
||||
public async Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultInMemoryOptionsAsync());
|
||||
await _storageMediatorService.SaveAsync(Constants.UserKeyKey(reconciledOptions.UserId), value, false);
|
||||
await _storageMediatorService.SaveAsync(
|
||||
await ComposeKeyAsync(Constants.MasterKeyEncryptedUserKeyKey, userId), value, false);
|
||||
}
|
||||
|
||||
public async Task<UserKey> GetUserKeyAutoUnlockAsync(string userId = null)
|
||||
{
|
||||
var keyB64 = await _storageMediatorService.GetAsync<string>(
|
||||
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), true);
|
||||
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
|
||||
}
|
||||
|
||||
public async Task SetUserKeyAutoUnlockAsync(string value, string userId = null)
|
||||
{
|
||||
await _storageMediatorService.SaveAsync(
|
||||
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value, true);
|
||||
}
|
||||
|
||||
public async Task<bool> CanAccessPremiumAsync(string userId = null)
|
||||
@@ -354,6 +365,7 @@ namespace Bit.Core.Services
|
||||
{
|
||||
userId = await GetActiveUserIdAsync();
|
||||
}
|
||||
|
||||
if (!await IsAuthenticatedAsync(userId))
|
||||
{
|
||||
return false;
|
||||
@@ -399,25 +411,27 @@ namespace Bit.Core.Services
|
||||
await SetValueAsync(Constants.ProtectedPinKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||
}
|
||||
|
||||
public async Task<EncString> GetUserKeyPinAsync(string userId = null)
|
||||
public async Task<EncString> GetPinKeyEncryptedUserKeyAsync(string userId = null)
|
||||
{
|
||||
var key = await _storageMediatorService.GetAsync<string>(Constants.UserKeyPinKey(userId), false);
|
||||
var key = await _storageMediatorService.GetAsync<string>(
|
||||
await ComposeKeyAsync(Constants.PinKeyEncryptedUserKeyKey, userId), false);
|
||||
return key != null ? new EncString(key) : null;
|
||||
}
|
||||
|
||||
public async Task SetUserKeyPinAsync(EncString value, string userId = null)
|
||||
public async Task SetPinKeyEncryptedUserKeyAsync(EncString value, string userId = null)
|
||||
{
|
||||
await _storageMediatorService.SaveAsync(Constants.UserKeyPinKey(userId), value?.EncryptedString, false);
|
||||
await _storageMediatorService.SaveAsync(
|
||||
await ComposeKeyAsync(Constants.PinKeyEncryptedUserKeyKey, userId), value?.EncryptedString, false);
|
||||
}
|
||||
|
||||
public async Task<EncString> GetUserKeyPinEphemeralAsync(string userId = null)
|
||||
public async Task<EncString> GetPinKeyEncryptedUserKeyEphemeralAsync(string userId = null)
|
||||
{
|
||||
return (await GetAccountAsync(
|
||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
||||
))?.VolatileData?.UserKeyPinEphemeral;
|
||||
}
|
||||
|
||||
public async Task SetUserKeyPinEphemeralAsync(EncString value, string userId = null)
|
||||
public async Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultInMemoryOptionsAsync());
|
||||
@@ -426,39 +440,6 @@ namespace Bit.Core.Services
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetUserKeyPinAsync instead, left for migration purposes")]
|
||||
public async Task<string> GetPinProtectedAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
return await GetValueAsync<string>(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use SetUserKeyPinAsync instead")]
|
||||
public async Task SetPinProtectedAsync(string value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetUserKeyPinEphemeralAsync instead, left for migration purposes")]
|
||||
public async Task<EncString> GetPinProtectedKeyAsync(string userId = null)
|
||||
{
|
||||
return (await GetAccountAsync(
|
||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
||||
))?.VolatileData?.PinProtectedKey;
|
||||
}
|
||||
|
||||
[Obsolete("Use SetUserKeyPinEphemeralAsync instead")]
|
||||
public async Task SetPinProtectedKeyAsync(EncString value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultInMemoryOptionsAsync());
|
||||
var account = await GetAccountAsync(reconciledOptions);
|
||||
account.VolatileData.PinProtectedKey = value;
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
public async Task SetKdfConfigurationAsync(KdfConfig config, string userId = null)
|
||||
{
|
||||
@@ -1532,28 +1513,30 @@ namespace Bit.Core.Services
|
||||
}
|
||||
|
||||
// Non-state storage
|
||||
await SetProtectedPinAsync(null, userId);
|
||||
await SetPinProtectedAsync(null, userId);
|
||||
await SetKeyEncryptedAsync(null, userId);
|
||||
await SetKeyHashAsync(null, userId);
|
||||
await SetEncKeyEncryptedAsync(null, userId);
|
||||
await SetOrgKeysEncryptedAsync(null, userId);
|
||||
await SetPrivateKeyEncryptedAsync(null, userId);
|
||||
await SetLastActiveTimeAsync(null, userId);
|
||||
await SetPreviousPageInfoAsync(null, userId);
|
||||
await SetInvalidUnlockAttemptsAsync(null, userId);
|
||||
await SetLocalDataAsync(null, userId);
|
||||
await SetEncryptedCiphersAsync(null, userId);
|
||||
await SetEncryptedCollectionsAsync(null, userId);
|
||||
await SetLastSyncAsync(null, userId);
|
||||
await SetEncryptedFoldersAsync(null, userId);
|
||||
await SetEncryptedPoliciesAsync(null, userId);
|
||||
await SetUsesKeyConnectorAsync(null, userId);
|
||||
await SetOrganizationsAsync(null, userId);
|
||||
await SetEncryptedPasswordGenerationHistoryAsync(null, userId);
|
||||
await SetEncryptedSendsAsync(null, userId);
|
||||
await SetSettingsAsync(null, userId);
|
||||
await SetApprovePasswordlessLoginsAsync(null, userId);
|
||||
await Task.WhenAll(
|
||||
SetUserKeyAutoUnlockAsync(null, userId),
|
||||
SetProtectedPinAsync(null, userId),
|
||||
SetKeyHashAsync(null, userId),
|
||||
SetOrgKeysEncryptedAsync(null, userId),
|
||||
SetPrivateKeyEncryptedAsync(null, userId),
|
||||
SetLastActiveTimeAsync(null, userId),
|
||||
SetPreviousPageInfoAsync(null, userId),
|
||||
SetInvalidUnlockAttemptsAsync(null, userId),
|
||||
SetLocalDataAsync(null, userId),
|
||||
SetEncryptedCiphersAsync(null, userId),
|
||||
SetEncryptedCollectionsAsync(null, userId),
|
||||
SetLastSyncAsync(null, userId),
|
||||
SetEncryptedFoldersAsync(null, userId),
|
||||
SetEncryptedPoliciesAsync(null, userId),
|
||||
SetUsesKeyConnectorAsync(null, userId),
|
||||
SetOrganizationsAsync(null, userId),
|
||||
SetEncryptedPasswordGenerationHistoryAsync(null, userId),
|
||||
SetEncryptedSendsAsync(null, userId),
|
||||
SetSettingsAsync(null, userId),
|
||||
SetApprovePasswordlessLoginsAsync(null, userId),
|
||||
SetEncKeyEncryptedAsync(null, userId),
|
||||
SetKeyEncryptedAsync(null, userId),
|
||||
SetPinProtectedAsync(null, userId));
|
||||
}
|
||||
|
||||
private async Task ScaffoldNewAccountAsync(Account account)
|
||||
@@ -1742,7 +1725,41 @@ namespace Bit.Core.Services
|
||||
shouldConnect ?? await GetShouldConnectToWatchAsync(), await GetDefaultStorageOptionsAsync());
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[Obsolete("Use GetPinKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
public async Task<string> GetPinProtectedAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
return await GetValueAsync<string>(Constants.PinProtectedKey(reconciledOptions.UserId), reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use SetPinKeyEncryptedUserKeyAsync instead")]
|
||||
public async Task SetPinProtectedAsync(string value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultStorageOptionsAsync());
|
||||
await SetValueAsync(Constants.PinProtectedKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetPinKeyEncryptedUserKeyEphemeralAsync instead, left for migration purposes")]
|
||||
public async Task<EncString> GetPinProtectedKeyAsync(string userId = null)
|
||||
{
|
||||
return (await GetAccountAsync(
|
||||
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
|
||||
))?.VolatileData?.PinProtectedKey;
|
||||
}
|
||||
|
||||
[Obsolete("Use SetPinKeyEncryptedUserKeyEphemeralAsync instead")]
|
||||
public async Task SetPinProtectedKeyAsync(EncString value, string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultInMemoryOptionsAsync());
|
||||
var account = await GetAccountAsync(reconciledOptions);
|
||||
account.VolatileData.PinProtectedKey = value;
|
||||
await SaveAccountAsync(account, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
public async Task<string> GetEncKeyEncryptedAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
@@ -1750,7 +1767,7 @@ namespace Bit.Core.Services
|
||||
return await GetValueAsync<string>(Constants.EncKeyKey(reconciledOptions.UserId), reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[Obsolete("Use SetMasterKeyEncryptedUserKeyAsync instead, left for migration purposes")]
|
||||
public async Task SetEncKeyEncryptedAsync(string value, string userId)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
@@ -1758,15 +1775,7 @@ namespace Bit.Core.Services
|
||||
await SetValueAsync(Constants.EncKeyKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public async Task<string> GetKeyEncryptedAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultSecureStorageOptionsAsync());
|
||||
return await GetValueAsync<string>(Constants.KeyKey(reconciledOptions.UserId), reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[Obsolete("Left for migration purposes")]
|
||||
public async Task SetKeyEncryptedAsync(string value, string userId)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
@@ -1774,22 +1783,20 @@ namespace Bit.Core.Services
|
||||
await SetValueAsync(Constants.KeyKey(reconciledOptions.UserId), value, reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
[Obsolete("Use GetUserKeyAutoUnlock instead, left for migration purposes")]
|
||||
public async Task<string> GetKeyEncryptedAsync(string userId = null)
|
||||
{
|
||||
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
|
||||
await GetDefaultSecureStorageOptionsAsync());
|
||||
return await GetValueAsync<string>(Constants.KeyKey(reconciledOptions.UserId), reconciledOptions);
|
||||
}
|
||||
|
||||
[Obsolete("Use GetMasterKeyAsync instead, left for migration purposes")]
|
||||
public async Task<SymmetricCryptoKey> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +328,7 @@ namespace Bit.Core.Services
|
||||
return;
|
||||
}
|
||||
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(response.Key);
|
||||
await _cryptoService.SetPrivateKeyAsync(response.PrivateKey);
|
||||
await _cryptoService.SetUserPrivateKeyAsync(response.PrivateKey);
|
||||
await _cryptoService.SetOrgKeysAsync(response.Organizations);
|
||||
await _stateService.SetSecurityStampAsync(response.SecurityStamp);
|
||||
var organizations = response.Organizations.ToDictionary(o => o.Id, o => new OrganizationData(o));
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Bit.Core.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(secret, null);
|
||||
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(secret, null);
|
||||
if (!passwordValid)
|
||||
{
|
||||
await InvalidSecretErrorAsync(verificationType);
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
public enum PinLockEnum
|
||||
public enum PinLockType
|
||||
{
|
||||
Disabled,
|
||||
Persistent,
|
||||
@@ -61,15 +59,26 @@ namespace Bit.Core.Services
|
||||
|
||||
public async Task<bool> IsLockedAsync(string userId = null)
|
||||
{
|
||||
var hasKey = await _cryptoService.HasUserKeyAsync(userId);
|
||||
if (hasKey)
|
||||
var biometricSet = await IsBiometricLockSetAsync(userId);
|
||||
if (biometricSet && await _stateService.GetBiometricLockedAsync(userId))
|
||||
{
|
||||
var biometricSet = await IsBiometricLockSetAsync(userId);
|
||||
if (biometricSet && await _stateService.GetBiometricLockedAsync(userId))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!await _cryptoService.HasUserKeyAsync(userId))
|
||||
{
|
||||
if (await _cryptoService.HasAutoUnlockKeyAsync(userId))
|
||||
{
|
||||
await _cryptoService.SetUserKeyAsync(await _cryptoService.GetAutoUnlockKeyAsync(userId));
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check again to verify auto key was set
|
||||
var hasKey = await _cryptoService.HasUserKeyAsync(userId);
|
||||
return !hasKey;
|
||||
}
|
||||
|
||||
@@ -172,11 +181,11 @@ namespace Bit.Core.Services
|
||||
|
||||
if (await _keyConnectorService.GetUsesKeyConnector())
|
||||
{
|
||||
var pinStatus = await IsPinLockSetAsync(userId);
|
||||
var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync()
|
||||
var pinStatus = await GetPinLockTypeAsync(userId);
|
||||
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
||||
?? await _stateService.GetPinProtectedKeyAsync();
|
||||
var pinEnabled = (pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) ||
|
||||
pinStatus == PinLockEnum.Persistent;
|
||||
var pinEnabled = (pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
||||
pinStatus == PinLockType.Persistent;
|
||||
|
||||
if (!pinEnabled && !await IsBiometricLockSetAsync())
|
||||
{
|
||||
@@ -198,6 +207,7 @@ namespace Bit.Core.Services
|
||||
await Task.WhenAll(
|
||||
_cryptoService.ClearUserKeyAsync(userId),
|
||||
_cryptoService.ClearMasterKeyAsync(userId),
|
||||
_stateService.SetUserKeyAutoUnlockAsync(null, userId),
|
||||
_cryptoService.ClearOrgKeysAsync(true, userId),
|
||||
_cryptoService.ClearKeyPairAsync(true, userId));
|
||||
|
||||
@@ -223,30 +233,27 @@ namespace Bit.Core.Services
|
||||
{
|
||||
await _stateService.SetVaultTimeoutAsync(timeout);
|
||||
await _stateService.SetVaultTimeoutActionAsync(action);
|
||||
await _cryptoService.ToggleKeysAsync();
|
||||
await _cryptoService.RefreshKeysAsync();
|
||||
await _tokenService.ToggleTokensAsync();
|
||||
}
|
||||
|
||||
public async Task<PinLockEnum> IsPinLockSetAsync(string userId = null)
|
||||
public async Task<PinLockType> GetPinLockTypeAsync(string userId = null)
|
||||
{
|
||||
// we can't depend on only the protected pin being set because old
|
||||
// versions only used it for MP on Restart
|
||||
var pinIsEnabled = await _stateService.GetProtectedPinAsync(userId);
|
||||
var userKeyPin = await _stateService.GetUserKeyPinAsync(userId);
|
||||
var oldUserKeyPin = await _stateService.GetPinProtectedAsync(userId);
|
||||
var isPinEnabled = await _stateService.GetProtectedPinAsync(userId) != null;
|
||||
var hasUserKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync(userId) != null;
|
||||
var hasOldUserKeyPin = await _stateService.GetPinProtectedAsync(userId) != null;
|
||||
|
||||
if (userKeyPin != null || oldUserKeyPin != null)
|
||||
if (hasUserKeyPin || hasOldUserKeyPin)
|
||||
{
|
||||
return PinLockEnum.Persistent;
|
||||
return PinLockType.Persistent;
|
||||
}
|
||||
else if (pinIsEnabled != null && userKeyPin == null && oldUserKeyPin == null)
|
||||
else if (isPinEnabled && !hasUserKeyPin && !hasOldUserKeyPin)
|
||||
{
|
||||
return PinLockEnum.Transient;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PinLockEnum.Disabled;
|
||||
return PinLockType.Transient;
|
||||
}
|
||||
return PinLockType.Disabled;
|
||||
}
|
||||
|
||||
public async Task<bool> IsBiometricLockSetAsync(string userId = null)
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
private IBiometricService _biometricService;
|
||||
private IKeyConnectorService _keyConnectorService;
|
||||
private IAccountsManager _accountManager;
|
||||
private PinLockEnum _pinStatus;
|
||||
private PinLockType _pinStatus;
|
||||
private bool _pinEnabled;
|
||||
private bool _biometricEnabled;
|
||||
private bool _biometricIntegrityValid = true;
|
||||
@@ -104,18 +104,18 @@ namespace Bit.iOS.Core.Controllers
|
||||
if (autofillExtension && await _stateService.GetPasswordRepromptAutofillAsync())
|
||||
{
|
||||
_passwordReprompt = true;
|
||||
_pinStatus = PinLockEnum.Disabled;
|
||||
_pinStatus = PinLockType.Disabled;
|
||||
_pinEnabled = false;
|
||||
_biometricEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pinStatus = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||
_pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync();
|
||||
|
||||
var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync()
|
||||
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
||||
?? await _stateService.GetPinProtectedKeyAsync();
|
||||
_pinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockEnum.Persistent;
|
||||
_pinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockType.Persistent;
|
||||
|
||||
_biometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync()
|
||||
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
||||
@@ -257,15 +257,15 @@ namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
EncString userKeyPin = null;
|
||||
EncString oldPinProtected = null;
|
||||
if (_pinStatus == PinLockEnum.Persistent)
|
||||
if (_pinStatus == PinLockType.Persistent)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync();
|
||||
var oldEncryptedKey = await _stateService.GetPinProtectedAsync();
|
||||
oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null;
|
||||
}
|
||||
else if (_pinStatus == PinLockEnum.Transient)
|
||||
else if (_pinStatus == PinLockType.Transient)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync();
|
||||
oldPinProtected = await _stateService.GetPinProtectedKeyAsync();
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
if (oldPinProtected != null)
|
||||
{
|
||||
userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync(
|
||||
_pinStatus == PinLockEnum.Transient,
|
||||
_pinStatus == PinLockType.Transient,
|
||||
inputtedValue,
|
||||
email,
|
||||
kdfConfig,
|
||||
@@ -312,18 +312,18 @@ namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
var masterKey = await _cryptoService.MakeMasterKeyAsync(inputtedValue, email, kdfConfig);
|
||||
|
||||
var storedPasswordHash = await _cryptoService.GetPasswordHashAsync();
|
||||
var storedPasswordHash = await _cryptoService.GetMasterKeyHashAsync();
|
||||
if (storedPasswordHash == null)
|
||||
{
|
||||
var oldKey = await _secureStorageService.GetAsync<string>("oldKey");
|
||||
if (masterKey.KeyB64 == oldKey)
|
||||
{
|
||||
var localPasswordHash = await _cryptoService.HashPasswordAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization);
|
||||
var localPasswordHash = await _cryptoService.HashMasterKeyAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization);
|
||||
await _secureStorageService.RemoveAsync("oldKey");
|
||||
await _cryptoService.SetPasswordHashAsync(localPasswordHash);
|
||||
await _cryptoService.SetMasterKeyHashAsync(localPasswordHash);
|
||||
}
|
||||
}
|
||||
var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(inputtedValue, masterKey);
|
||||
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(inputtedValue, masterKey);
|
||||
if (passwordValid)
|
||||
{
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
using System;
|
||||
using UIKit;
|
||||
using Foundation;
|
||||
using Bit.iOS.Core.Views;
|
||||
using Bit.App.Resources;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models;
|
||||
using Xamarin.Forms;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Bit.iOS.Core.Views;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
@@ -30,7 +30,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
private IPlatformUtilsService _platformUtilsService;
|
||||
private IBiometricService _biometricService;
|
||||
private IKeyConnectorService _keyConnectorService;
|
||||
private PinLockEnum _pinStatus;
|
||||
private PinLockType _pinStatus;
|
||||
private bool _pinEnabled;
|
||||
private bool _biometricEnabled;
|
||||
private bool _biometricIntegrityValid = true;
|
||||
@@ -96,18 +96,18 @@ namespace Bit.iOS.Core.Controllers
|
||||
if (autofillExtension && await _stateService.GetPasswordRepromptAutofillAsync())
|
||||
{
|
||||
_passwordReprompt = true;
|
||||
_pinStatus = PinLockEnum.Disabled;
|
||||
_pinStatus = PinLockType.Disabled;
|
||||
_pinEnabled = false;
|
||||
_biometricEnabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pinStatus = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||
_pinStatus = await _vaultTimeoutService.GetPinLockTypeAsync();
|
||||
|
||||
var ephemeralPinSet = await _stateService.GetUserKeyPinEphemeralAsync()
|
||||
var ephemeralPinSet = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync()
|
||||
?? await _stateService.GetPinProtectedKeyAsync();
|
||||
_pinEnabled = (_pinStatus == PinLockEnum.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockEnum.Persistent;
|
||||
_pinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
|
||||
_pinStatus == PinLockType.Persistent;
|
||||
|
||||
_biometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync()
|
||||
&& await _cryptoService.HasEncryptedUserKeyAsync();
|
||||
@@ -129,7 +129,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
BaseNavItem.Title = AppResources.VerifyMasterPassword;
|
||||
}
|
||||
|
||||
|
||||
BaseCancelButton.Title = AppResources.Cancel;
|
||||
|
||||
if (_biometricUnlockOnly)
|
||||
@@ -224,15 +224,15 @@ namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
EncString userKeyPin = null;
|
||||
EncString oldPinProtected = null;
|
||||
if (_pinStatus == PinLockEnum.Persistent)
|
||||
if (_pinStatus == PinLockType.Persistent)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyAsync();
|
||||
var oldEncryptedKey = await _stateService.GetPinProtectedAsync();
|
||||
oldPinProtected = oldEncryptedKey != null ? new EncString(oldEncryptedKey) : null;
|
||||
}
|
||||
else if (_pinStatus == PinLockEnum.Transient)
|
||||
else if (_pinStatus == PinLockType.Transient)
|
||||
{
|
||||
userKeyPin = await _stateService.GetUserKeyPinEphemeralAsync();
|
||||
userKeyPin = await _stateService.GetPinKeyEncryptedUserKeyEphemeralAsync();
|
||||
oldPinProtected = await _stateService.GetPinProtectedKeyAsync();
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
if (oldPinProtected != null)
|
||||
{
|
||||
userKey = await _cryptoService.DecryptAndMigrateOldPinKeyAsync(
|
||||
_pinStatus == PinLockEnum.Transient,
|
||||
_pinStatus == PinLockType.Transient,
|
||||
inputtedValue,
|
||||
email,
|
||||
kdfConfig,
|
||||
@@ -284,19 +284,19 @@ namespace Bit.iOS.Core.Controllers
|
||||
else
|
||||
{
|
||||
var masterKey = await _cryptoService.MakeMasterKeyAsync(inputtedValue, email, kdfConfig);
|
||||
|
||||
var storedPasswordHash = await _cryptoService.GetPasswordHashAsync();
|
||||
|
||||
var storedPasswordHash = await _cryptoService.GetMasterKeyHashAsync();
|
||||
if (storedPasswordHash == null)
|
||||
{
|
||||
var oldKey = await _secureStorageService.GetAsync<string>("oldKey");
|
||||
if (masterKey.KeyB64 == oldKey)
|
||||
{
|
||||
var localPasswordHash = await _cryptoService.HashPasswordAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization);
|
||||
var localPasswordHash = await _cryptoService.HashMasterKeyAsync(inputtedValue, masterKey, HashPurpose.LocalAuthorization);
|
||||
await _secureStorageService.RemoveAsync("oldKey");
|
||||
await _cryptoService.SetPasswordHashAsync(localPasswordHash);
|
||||
await _cryptoService.SetMasterKeyHashAsync(localPasswordHash);
|
||||
}
|
||||
}
|
||||
var passwordValid = await _cryptoService.CompareAndUpdatePasswordHashAsync(inputtedValue, masterKey);
|
||||
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(inputtedValue, masterKey);
|
||||
if (passwordValid)
|
||||
{
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
@@ -395,7 +395,7 @@ namespace Bit.iOS.Core.Controllers
|
||||
});
|
||||
PresentViewController(alert, true, null);
|
||||
}
|
||||
|
||||
|
||||
private async Task LogOutAsync()
|
||||
{
|
||||
await AppHelpers.LogOutAsync(await _stateService.GetActiveUserIdAsync());
|
||||
|
||||
Reference in New Issue
Block a user