1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-15 15:53:44 +00:00

[PM-2713] Final merge from Key Migration branch to TDE Feature branch (#2667)

* [PM-2713] add async to key connector service methods

* [PM-2713] rename ephemeral pin key

* add state for biometric key and accept UserKey instead of string for auto key

* Get UserKey from bio state on unlock

* PM-2713 Fix auto-migrating EncKeyEncrypted into MasterKey encrypted UserKey when requesting DecryptUserKeyWithMasterKeyAsync is called

* renaming bio key and fix build

* PM-3194 Fix biometrics button to be shown on upgrade when no UserKey is present yet

* revert removal of key connector service from auth service

* PM-2713 set user key when using KC

* clear enc user key after migration

* use is true for nullable bool

* PR feedback, refactor kc service

---------

Co-authored-by: Federico Maccaroni <fedemkr@gmail.com>
This commit is contained in:
Jake Fink
2023-08-10 14:09:53 -04:00
committed by GitHub
parent 9001fa1ccf
commit 62b6d21371
22 changed files with 164 additions and 76 deletions

View File

@@ -157,9 +157,9 @@ namespace Bit.Droid
messagingService, broadcasterService);
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
platformUtilsService, new LazyResolve<IEventService>());
var biometricService = new BiometricService(stateService);
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
var biometricService = new BiometricService(stateService, cryptoService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Android.OS;
using Android.Security.Keystore;
using Bit.App.Services;
using Bit.Core.Abstractions;
using Bit.Core.Services;
using Java.Security;
@@ -9,10 +10,8 @@ using Javax.Crypto;
namespace Bit.Droid.Services
{
public class BiometricService : IBiometricService
public class BiometricService : BaseBiometricService
{
private readonly IStateService _stateService;
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
private const string KeyStoreName = "AndroidKeyStore";
@@ -24,14 +23,14 @@ namespace Bit.Droid.Services
private readonly KeyStore _keystore;
public BiometricService(IStateService stateService)
public BiometricService(IStateService stateService, ICryptoService cryptoService)
: base(stateService, cryptoService)
{
_stateService = stateService;
_keystore = KeyStore.GetInstance(KeyStoreName);
_keystore.Load(null);
}
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
public override async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
@@ -41,7 +40,7 @@ namespace Bit.Droid.Services
return true;
}
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
public override async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
{
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
{

View File

@@ -180,7 +180,7 @@ namespace Bit.App.Pages
PinEnabled = (_pinStatus == PinLockType.Transient && ephemeralPinSet != null) ||
_pinStatus == PinLockType.Persistent;
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasEncryptedUserKeyAsync();
BiometricEnabled = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _biometricService.CanUseBiometricsUnlockAsync();
// Users without MP and without biometric or pin has no MP to unlock with
_hasMasterPassword = await _userVerificationService.HasMasterPasswordAsync();
@@ -305,7 +305,7 @@ namespace Bit.App.Pages
{
Pin = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(userKey);
await SetUserKeyAndContinueAsync(userKey);
}
}
catch
@@ -372,7 +372,7 @@ namespace Bit.App.Pages
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
await _cryptoService.SetMasterKeyAsync(masterKey);
await SetKeyAndContinueAsync(userKey);
await SetUserKeyAndContinueAsync(userKey);
// Re-enable biometrics
if (BiometricEnabled & !BiometricIntegrityValid)
@@ -470,11 +470,12 @@ namespace Bit.App.Pages
await _stateService.SetBiometricLockedAsync(!success);
if (success)
{
await DoContinueAsync();
var userKey = await _cryptoService.GetBiometricUnlockKeyAsync();
await SetUserKeyAndContinueAsync(userKey);
}
}
private async Task SetKeyAndContinueAsync(UserKey key)
private async Task SetUserKeyAndContinueAsync(UserKey key)
{
var hasKey = await _cryptoService.HasUserKeyAsync();
if (!hasKey)

View File

@@ -30,14 +30,14 @@ namespace Bit.App.Pages
public async Task Init()
{
Organization = await _keyConnectorService.GetManagingOrganization();
Organization = await _keyConnectorService.GetManagingOrganizationAsync();
}
public async Task MigrateAccount()
{
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
await _keyConnectorService.MigrateUser();
await _keyConnectorService.MigrateUserAsync();
await _syncService.FullSyncAsync(true);
await _deviceActionService.HideLoadingAsync();

View File

@@ -94,7 +94,7 @@ namespace Bit.App.Pages
}
});
await UpdateVaultButtonTitleAsync();
if (await _keyConnectorService.UserNeedsMigration())
if (await _keyConnectorService.UserNeedsMigrationAsync())
{
_messagingService.Send("convertAccountToKeyConnector");
}

View File

@@ -0,0 +1,25 @@
using System.Threading.Tasks;
using Bit.Core.Abstractions;
namespace Bit.App.Services
{
public abstract class BaseBiometricService : IBiometricService
{
protected readonly IStateService _stateService;
protected readonly ICryptoService _cryptoService;
protected BaseBiometricService(IStateService stateService, ICryptoService cryptoService)
{
_stateService = stateService;
_cryptoService = cryptoService;
}
public async Task<bool> CanUseBiometricsUnlockAsync()
{
return await _cryptoService.HasEncryptedUserKeyAsync() || await _stateService.GetKeyEncryptedAsync() != null;
}
public abstract Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
public abstract Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null);
}
}

View File

@@ -71,7 +71,7 @@ namespace Bit.Core.Abstractions
Task<OrganizationAutoEnrollStatusResponse> GetOrganizationAutoEnrollStatusAsync(string identifier);
Task PutOrganizationUserResetPasswordEnrollmentAsync(string orgId, string userId,
OrganizationUserResetPasswordEnrollmentRequest request);
Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnector(string keyConnectorUrl);
Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnectorAsync(string keyConnectorUrl);
Task PostUserKeyToKeyConnector(string keyConnectorUrl, KeyConnectorUserKeyRequest request);
Task PostSetKeyConnectorKey(SetKeyConnectorKeyRequest request);
Task PostConvertToKeyConnector();

View File

@@ -4,6 +4,7 @@ namespace Bit.Core.Abstractions
{
public interface IBiometricService
{
Task<bool> CanUseBiometricsUnlockAsync();
Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null);
Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null);
}

View File

@@ -21,6 +21,7 @@ namespace Bit.Core.Abstractions
Task SetMasterKeyEncryptedUserKeyAsync(string value, string userId = null);
Task<UserKey> GetAutoUnlockKeyAsync(string userId = null);
Task<bool> HasAutoUnlockKeyAsync(string userId = null);
Task<UserKey> GetBiometricUnlockKeyAsync(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);

View File

@@ -6,12 +6,12 @@ namespace Bit.Core.Abstractions
{
public interface IKeyConnectorService
{
Task SetUsesKeyConnector(bool usesKeyConnector);
Task SetUsesKeyConnectorAsync(bool usesKeyConnector);
Task<bool> GetUsesKeyConnectorAsync();
Task<bool> UserNeedsMigration();
Task MigrateUser();
Task GetAndSetKeyAsync(string url);
Task<Organization> GetManagingOrganization();
Task<bool> UserNeedsMigrationAsync();
Task MigrateUserAsync();
Task SetMasterKeyFromUrlAsync(string url);
Task<Organization> GetManagingOrganizationAsync();
Task ConvertNewUserToKeyConnectorAsync(string orgId, IdentityTokenResponse tokenResponse);
}
}

View File

@@ -20,7 +20,7 @@ namespace Bit.Core.Abstractions
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 SetUserKeyAutoUnlockAsync(UserKey value, string userId = null);
Task<string> GetActiveUserIdAsync();
Task<string> GetActiveUserEmailAsync();
Task<T> GetActiveUserCustomDataAsync<T>(Func<Account, T> dataMapper);
@@ -35,6 +35,8 @@ namespace Bit.Core.Abstractions
Task<EnvironmentUrlData> GetPreAuthEnvironmentUrlsAsync();
Task SetPreAuthEnvironmentUrlsAsync(EnvironmentUrlData value);
Task<EnvironmentUrlData> GetEnvironmentUrlsAsync(string userId = null);
Task<UserKey> GetUserKeyBiometricUnlockAsync(string userId = null);
Task SetUserKeyBiometricUnlockAsync(UserKey value, string userId = null);
Task<bool?> GetBiometricUnlockAsync(string userId = null);
Task SetBiometricUnlockAsync(bool? value, string userId = null);
Task<bool> GetBiometricLockedAsync(string userId = null);

View File

@@ -87,6 +87,7 @@ namespace Bit.Core
public static string VaultTimeoutActionKey(string userId) => $"vaultTimeoutAction_{userId}";
public static string MasterKeyEncryptedUserKeyKey(string userId) => $"masterKeyEncryptedUserKey_{userId}";
public static string UserKeyAutoUnlockKey(string userId) => $"autoUnlock_{userId}";
public static string UserKeyBiometricUnlockKey(string userId) => $"biometricUnlock_{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}";

View File

@@ -121,7 +121,7 @@ namespace Bit.Core.Models.Domain
{
public UserKey UserKey;
public MasterKey MasterKey;
public EncString UserKeyPinEphemeral;
public EncString PinKeyEncryptedUserKeyEphemeral;
public bool? BiometricLocked;
[Obsolete("Jul 6 2023: Key has been deprecated. We will use the User Key in the future. It remains here for migration during app upgrade.")]
public SymmetricCryptoKey Key;

View File

@@ -511,7 +511,7 @@ namespace Bit.Core.Services
#region Key Connector
public async Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnector(string keyConnectorUrl)
public async Task<KeyConnectorUserKeyResponse> GetMasterKeyFromKeyConnectorAsync(string keyConnectorUrl)
{
using (var requestMessage = new HttpRequestMessage())
{

View File

@@ -48,7 +48,6 @@ namespace Bit.Core.Services
II18nService i18nService,
IPlatformUtilsService platformUtilsService,
IMessagingService messagingService,
IVaultTimeoutService vaultTimeoutService,
IKeyConnectorService keyConnectorService,
IPasswordGenerationService passwordGenerationService,
IPolicyService policyService,
@@ -510,6 +509,7 @@ namespace Bit.Core.Services
await _cryptoService.SetUserKeyAsync(userKey);
}
// Trusted Device
var decryptOptions = await _stateService.GetAccountDecryptionOptions();
var hasUserKey = await _cryptoService.HasUserKeyAsync();
if (decryptOptions?.TrustedDeviceOption != null && !hasUserKey)
@@ -524,22 +524,24 @@ namespace Bit.Core.Services
if (code == null || tokenResponse.Key != null)
{
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key);
// Key Connector
if (!string.IsNullOrEmpty(tokenResponse.KeyConnectorUrl) || !string.IsNullOrEmpty(decryptOptions?.KeyConnectorOption?.KeyConnectorUrl))
{
await _cryptoService.SetMasterKeyEncryptedUserKeyAsync(tokenResponse.Key);
if (masterKey != null)
{
await _cryptoService.SetMasterKeyAsync(masterKey);
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
await _cryptoService.SetUserKeyAsync(userKey);
}
var url = tokenResponse.KeyConnectorUrl ?? decryptOptions.KeyConnectorOption.KeyConnectorUrl;
await _keyConnectorService.SetMasterKeyFromUrlAsync(url);
}
// Login with Device
if (masterKey != null && !string.IsNullOrEmpty(authRequestId))
{
await _cryptoService.SetMasterKeyAsync(masterKey);
}
// Decrypt UserKey with MasterKey
masterKey ??= await _stateService.GetMasterKeyAsync();
if (masterKey != null)
{
var userKey = await _cryptoService.DecryptUserKeyWithMasterKeyAsync(masterKey);
await _cryptoService.SetUserKeyAsync(userKey);
}
@@ -571,7 +573,7 @@ namespace Bit.Core.Services
}
else
{
await _keyConnectorService.GetAndSetKeyAsync(tokenResponse.KeyConnectorUrl);
await _keyConnectorService.SetMasterKeyFromUrlAsync(tokenResponse.KeyConnectorUrl);
}
}
}

View File

@@ -101,7 +101,7 @@ namespace Bit.Core.Services
public async Task<UserKey> GetAutoUnlockKeyAsync(string userId = null)
{
await MigrateAutoUnlockKeyIfNeededAsync(userId);
await MigrateAutoAndBioKeysIfNeededAsync(userId);
return await _stateService.GetUserKeyAutoUnlockAsync(userId);
}
@@ -110,6 +110,12 @@ namespace Bit.Core.Services
return await GetAutoUnlockKeyAsync(userId) != null;
}
public async Task<UserKey> GetBiometricUnlockKeyAsync(string userId = null)
{
await MigrateAutoAndBioKeysIfNeededAsync(userId);
return await _stateService.GetUserKeyBiometricUnlockAsync(userId);
}
public Task SetMasterKeyAsync(MasterKey masterKey, string userId = null)
{
return _stateService.SetMasterKeyAsync(masterKey, userId);
@@ -149,7 +155,7 @@ namespace Bit.Core.Services
public async Task<Tuple<UserKey, EncString>> EncryptUserKeyWithMasterKeyAsync(MasterKey masterKey)
{
var userKey = await GetUserKeyAsync() ?? await MakeUserKeyAsync();
return await BuildProtectedSymmetricKey(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes));
return await BuildProtectedSymmetricKeyAsync(masterKey, userKey.Key, keyBytes => new UserKey(keyBytes));
}
public async Task<UserKey> DecryptUserKeyWithMasterKeyAsync(MasterKey masterKey, EncString encUserKey = null, string userId = null)
@@ -163,10 +169,27 @@ namespace Bit.Core.Services
if (encUserKey == null)
{
var userKeyMasterKey = await _stateService.GetMasterKeyEncryptedUserKeyAsync(userId);
if (userKeyMasterKey == null)
if (userKeyMasterKey is null)
{
throw new Exception("No encrypted user key found");
// Migrate old key
var oldEncUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
if (oldEncUserKey is null)
{
throw new Exception("No encrypted user key nor old encKeyEncrypted found");
}
var userKey = await DecryptUserKeyWithMasterKeyAsync(
masterKey,
new EncString(oldEncUserKey),
userId
);
await SetMasterKeyEncryptedUserKeyAsync(oldEncUserKey, userId);
await _stateService.SetEncKeyEncryptedAsync(null, userId);
return userKey;
}
encUserKey = new EncString(userKeyMasterKey);
}
@@ -204,7 +227,7 @@ namespace Bit.Core.Services
}
var newSymKey = await _cryptoFunctionService.RandomBytesAsync(64);
return await BuildProtectedSymmetricKey(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes));
return await BuildProtectedSymmetricKeyAsync(key, newSymKey, keyBytes => new SymmetricCryptoKey(keyBytes));
}
public async Task<string> HashMasterKeyAsync(string password, MasterKey masterKey, HashPurpose hashPurpose = HashPurpose.ServerAuthorization)
@@ -676,10 +699,10 @@ namespace Bit.Core.Services
private async Task StoreAdditionalKeysAsync(UserKey userKey, string userId = null)
{
// Refresh, set, or clear the pin key
// Set, refresh, or clear the pin key
if (await _stateService.GetProtectedPinAsync(userId) != null)
{
await UpdateUserKeyPinAsync(userKey, userId);
await UpdatePinKeyAsync(userKey, userId);
}
else
{
@@ -687,18 +710,28 @@ namespace Bit.Core.Services
await _stateService.SetPinKeyEncryptedUserKeyEphemeralAsync(null, userId);
}
// Refresh, set, or clear the auto key
// Set, refresh, or clear the auto unlock key
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
{
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
await _stateService.SetUserKeyAutoUnlockAsync(userKey, userId);
}
else
{
await _stateService.SetUserKeyAutoUnlockAsync(null, userId);
}
// Set, refresh, or clear the biometric unlock key
if (await _stateService.GetBiometricUnlockAsync(userId) is true)
{
await _stateService.SetUserKeyBiometricUnlockAsync(userKey, userId);
}
else
{
await _stateService.SetUserKeyBiometricUnlockAsync(null, userId);
}
}
private async Task UpdateUserKeyPinAsync(UserKey userKey, string userId = null)
private async Task UpdatePinKeyAsync(UserKey userKey, string userId = null)
{
var pin = await DecryptToUtf8Async(new EncString(await _stateService.GetProtectedPinAsync(userId)));
var pinKey = await MakePinKeyAsync(
@@ -880,7 +913,7 @@ namespace Bit.Core.Services
}
// TODO: This needs to be moved into SymmetricCryptoKey model to remove the keyCreator hack
private async Task<Tuple<TKey, EncString>> BuildProtectedSymmetricKey<TKey>(SymmetricCryptoKey key,
private async Task<Tuple<TKey, EncString>> BuildProtectedSymmetricKeyAsync<TKey>(SymmetricCryptoKey key,
byte[] encKey, Func<byte[], TKey> keyCreator) where TKey : SymmetricCryptoKey
{
EncString encKeyEnc = null;
@@ -904,7 +937,7 @@ namespace Bit.Core.Services
private async Task<TKey> MakeKeyAsync<TKey>(string password, string salt, KdfConfig kdfConfig, Func<byte[], TKey> keyCreator)
where TKey : SymmetricCryptoKey
{
byte[] key = null;
byte[] key;
if (kdfConfig.Type == null || kdfConfig.Type == KdfType.PBKDF2_SHA256)
{
var iterations = kdfConfig.Iterations.GetValueOrDefault(5000);
@@ -962,23 +995,33 @@ 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)
private async Task MigrateAutoAndBioKeysIfNeededAsync(string userId = null)
{
var oldAutoKey = await _stateService.GetKeyEncryptedAsync(userId);
if (oldAutoKey == null)
var oldKey = await _stateService.GetKeyEncryptedAsync(userId);
if (oldKey == null)
{
return;
}
// Decrypt
var masterKey = new MasterKey(Convert.FromBase64String(oldAutoKey));
var masterKey = new MasterKey(Convert.FromBase64String(oldKey));
var encryptedUserKey = await _stateService.GetEncKeyEncryptedAsync(userId);
var userKey = await DecryptUserKeyWithMasterKeyAsync(
masterKey,
new EncString(encryptedUserKey),
userId);
// Migrate
await _stateService.SetUserKeyAutoUnlockAsync(userKey.KeyB64, userId);
if (await _stateService.GetVaultTimeoutAsync(userId) == null)
{
await _stateService.SetUserKeyAutoUnlockAsync(userKey, userId);
}
if (await _stateService.GetBiometricUnlockAsync(userId) is true)
{
await _stateService.SetUserKeyBiometricUnlockAsync(userKey, userId);
}
await _stateService.SetKeyEncryptedAsync(null, userId);
// Set encrypted user key just in case the user locks without syncing
await SetMasterKeyEncryptedUserKeyAsync(encryptedUserKey);
}

View File

@@ -27,13 +27,13 @@ namespace Bit.Core.Services
_organizationService = organizationService;
}
public async Task GetAndSetKeyAsync(string url)
public async Task SetMasterKeyFromUrlAsync(string url)
{
try
{
var masterKeyResponse = await _apiService.GetMasterKeyFromKeyConnector(url);
var masterKeyArr = Convert.FromBase64String(masterKeyResponse.Key);
var masterKey = new MasterKey(masterKeyArr);
var masterKeyResponse = await _apiService.GetMasterKeyFromKeyConnectorAsync(url);
var masterKeyBytes = Convert.FromBase64String(masterKeyResponse.Key);
var masterKey = new MasterKey(masterKeyBytes);
await _cryptoService.SetMasterKeyAsync(masterKey);
}
catch (Exception e)
@@ -42,7 +42,7 @@ namespace Bit.Core.Services
}
}
public async Task SetUsesKeyConnector(bool usesKeyConnector)
public async Task SetUsesKeyConnectorAsync(bool usesKeyConnector)
{
await _stateService.SetUsesKeyConnectorAsync(usesKeyConnector);
}
@@ -52,7 +52,7 @@ namespace Bit.Core.Services
return await _stateService.GetUsesKeyConnectorAsync();
}
public async Task<Organization> GetManagingOrganization()
public async Task<Organization> GetManagingOrganizationAsync()
{
var orgs = await _organizationService.GetAllAsync();
return orgs.Find(o =>
@@ -60,9 +60,9 @@ namespace Bit.Core.Services
!o.IsAdmin);
}
public async Task MigrateUser()
public async Task MigrateUserAsync()
{
var organization = await GetManagingOrganization();
var organization = await GetManagingOrganizationAsync();
var masterKey = await _cryptoService.GetMasterKeyAsync();
try
@@ -78,10 +78,10 @@ namespace Bit.Core.Services
await _apiService.PostConvertToKeyConnector();
}
public async Task<bool> UserNeedsMigration()
public async Task<bool> UserNeedsMigrationAsync()
{
var loggedInUsingSso = await _tokenService.GetIsExternal();
var requiredByOrganization = await GetManagingOrganization() != null;
var requiredByOrganization = await GetManagingOrganizationAsync() != null;
var userIsNotUsingKeyConnector = !await GetUsesKeyConnectorAsync();
return loggedInUsingSso && requiredByOrganization && userIsNotUsingKeyConnector;

View File

@@ -241,6 +241,19 @@ namespace Bit.Core.Services
))?.Settings?.EnvironmentUrls;
}
public async Task<UserKey> GetUserKeyBiometricUnlockAsync(string userId = null)
{
var keyB64 = await _storageMediatorService.GetAsync<string>(
await ComposeKeyAsync(Constants.UserKeyBiometricUnlockKey, userId), true);
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
}
public async Task SetUserKeyBiometricUnlockAsync(UserKey value, string userId = null)
{
await _storageMediatorService.SaveAsync(
await ComposeKeyAsync(Constants.UserKeyBiometricUnlockKey, userId), value?.KeyB64, true);
}
public async Task<bool?> GetBiometricUnlockAsync(string userId = null)
{
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
@@ -353,10 +366,10 @@ namespace Bit.Core.Services
return keyB64 == null ? null : new UserKey(Convert.FromBase64String(keyB64));
}
public async Task SetUserKeyAutoUnlockAsync(string value, string userId = null)
public async Task SetUserKeyAutoUnlockAsync(UserKey value, string userId = null)
{
await _storageMediatorService.SaveAsync(
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value, true);
await ComposeKeyAsync(Constants.UserKeyAutoUnlockKey, userId), value?.KeyB64, true);
}
public async Task<bool> CanAccessPremiumAsync(string userId = null)
@@ -428,7 +441,7 @@ namespace Bit.Core.Services
{
return (await GetAccountAsync(
ReconcileOptions(new StorageOptions { UserId = userId }, await GetDefaultInMemoryOptionsAsync())
))?.VolatileData?.UserKeyPinEphemeral;
))?.VolatileData?.PinKeyEncryptedUserKeyEphemeral;
}
public async Task SetPinKeyEncryptedUserKeyEphemeralAsync(EncString value, string userId = null)
@@ -436,7 +449,7 @@ namespace Bit.Core.Services
var reconciledOptions = ReconcileOptions(new StorageOptions { UserId = userId },
await GetDefaultInMemoryOptionsAsync());
var account = await GetAccountAsync(reconciledOptions);
account.VolatileData.UserKeyPinEphemeral = value;
account.VolatileData.PinKeyEncryptedUserKeyEphemeral = value;
await SaveAccountAsync(account, reconciledOptions);
}
@@ -1520,6 +1533,7 @@ namespace Bit.Core.Services
// Non-state storage
await Task.WhenAll(
SetUserKeyAutoUnlockAsync(null, userId),
SetUserKeyBiometricUnlockAsync(null, userId),
SetProtectedPinAsync(null, userId),
SetKeyHashAsync(null, userId),
SetOrgKeysEncryptedAsync(null, userId),

View File

@@ -337,7 +337,7 @@ namespace Bit.Core.Services
await _stateService.SetNameAsync(response.Name);
await _stateService.SetPersonalPremiumAsync(response.Premium);
await _stateService.SetAvatarColorAsync(response.AvatarColor);
await _keyConnectorService.SetUsesKeyConnector(response.UsesKeyConnector);
await _keyConnectorService.SetUsesKeyConnectorAsync(response.UsesKeyConnector);
}
private async Task SyncFoldersAsync(string userId, List<FolderResponse> response)

View File

@@ -82,7 +82,7 @@ namespace Bit.Core.Utilities
var deviceTrustCryptoService = new DeviceTrustCryptoService(apiService, appIdService, cryptoFunctionService, cryptoService, stateService);
var passwordResetEnrollmentService = new PasswordResetEnrollmentService(apiService, cryptoService, organizationService, stateService);
var authService = new AuthService(cryptoService, cryptoFunctionService, apiService, stateService,
tokenService, appIdService, i18nService, platformUtilsService, messagingService, vaultTimeoutService,
tokenService, appIdService, i18nService, platformUtilsService, messagingService,
keyConnectorService, passwordGenerationService, policyService, deviceTrustCryptoService, passwordResetEnrollmentService);
var exportService = new ExportService(folderService, cipherService, cryptoService);
var auditService = new AuditService(cryptoFunctionService, apiService);

View File

@@ -1,20 +1,19 @@
using System.Threading.Tasks;
using Bit.App.Services;
using Bit.Core.Abstractions;
using Foundation;
using LocalAuthentication;
namespace Bit.iOS.Core.Services
{
public class BiometricService : IBiometricService
public class BiometricService : BaseBiometricService
{
private IStateService _stateService;
public BiometricService(IStateService stateService)
public BiometricService(IStateService stateService, ICryptoService cryptoService)
: base(stateService, cryptoService)
{
_stateService = stateService;
}
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
public override async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
{
if (bioIntegritySrcKey == null)
{
@@ -30,7 +29,7 @@ namespace Bit.iOS.Core.Services
return true;
}
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
public override async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
{
var state = GetState();
if (state == null)

View File

@@ -112,9 +112,9 @@ namespace Bit.iOS.Core.Utilities
var clipboardService = new ClipboardService(stateService);
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, clipboardService,
messagingService, broadcasterService);
var biometricService = new BiometricService(stateService);
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
var biometricService = new BiometricService(stateService, cryptoService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
ServiceContainer.Register<ISynchronousStorageService>(preferencesStorage);