Bitwarden-app-android-iphon.../src/Android/Services/BiometricService.cs

106 lines
3.4 KiB
C#

using System;
using System.Threading.Tasks;
using Android.OS;
using Android.Security.Keystore;
using Bit.Core.Abstractions;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Java.Security;
using Javax.Crypto;
namespace Bit.Droid.Services
{
public class BiometricService : IBiometricService
{
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
private const string KeyStoreName = "AndroidKeyStore";
private const string KeyAlgorithm = KeyProperties.KeyAlgorithmAes;
private const string BlockMode = KeyProperties.BlockModeCbc;
private const string EncryptionPadding = KeyProperties.EncryptionPaddingPkcs7;
private const string Transformation = KeyAlgorithm + "/" + BlockMode + "/" + EncryptionPadding;
private readonly KeyStore _keystore;
public BiometricService()
{
_keystore = KeyStore.GetInstance(KeyStoreName);
_keystore.Load(null);
}
public Task<bool> SetupBiometricAsync(string bioIntegrityKey = null)
{
// bioIntegrityKey used in iOS only
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
CreateKey();
}
return Task.FromResult(true);
}
public Task<bool> ValidateIntegrityAsync(string bioIntegrityKey = null)
{
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
{
return Task.FromResult(true);
}
try
{
_keystore.Load(null);
var key = _keystore.GetKey(KeyName, null);
var cipher = Cipher.GetInstance(Transformation);
if (key == null || cipher == null)
{
return Task.FromResult(true);
}
cipher.Init(CipherMode.EncryptMode, key);
}
catch (KeyPermanentlyInvalidatedException e)
{
// Biometric has changed
return Task.FromResult(false);
}
catch (UnrecoverableKeyException e)
{
// Biometric was disabled and re-enabled
return Task.FromResult(false);
}
catch (InvalidKeyException e)
{
// Fallback for old bitwarden users without a key
LoggerHelper.LogEvenIfCantBeResolved(e);
CreateKey();
}
return Task.FromResult(true);
}
private void CreateKey()
{
try
{
var keyGen = KeyGenerator.GetInstance(KeyAlgorithm, KeyStoreName);
var keyGenSpec =
new KeyGenParameterSpec.Builder(KeyName, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(BlockMode)
.SetEncryptionPaddings(EncryptionPadding)
.SetUserAuthenticationRequired(true)
.Build();
keyGen.Init(keyGenSpec);
keyGen.GenerateKey();
}
catch (Exception e)
{
// Catch silently to allow biometrics to function on devices that are in a state where key generation
// is not functioning
LoggerHelper.LogEvenIfCantBeResolved(e);
}
}
}
}