diff --git a/src/FingerprintTest/FingerprintModule.cs b/src/FingerprintTest/FingerprintModule.cs
index faefaff8..f60baab7 100644
--- a/src/FingerprintTest/FingerprintModule.cs
+++ b/src/FingerprintTest/FingerprintModule.cs
@@ -9,8 +9,11 @@ using Android.Hardware.Fingerprints;
using Android.OS;
using Android.Security.Keystore;
using Android.Preferences;
+using Android.Util;
+using Android.Widget;
using Java.IO;
using Java.Security.Cert;
+using Javax.Crypto.Spec;
namespace keepass2android
{
@@ -25,7 +28,7 @@ namespace keepass2android
public FingerprintManager FingerprintManager
{
- get { return (FingerprintManager) Context.GetSystemService("FingerprintManager"); }
+ get { return (FingerprintManager) Context.GetSystemService(Context.FingerprintService); }
}
public KeyguardManager KeyguardManager
@@ -103,8 +106,9 @@ namespace keepass2android
}
}
- public class FingerprintEncryptionModule: FingerprintManager.AuthenticationCallback
+ public abstract class FingerprintCrypt: FingerprintManager.AuthenticationCallback
{
+ protected const string FailedToInitCipher = "Failed to init Cipher";
public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString)
{
_callback.OnAuthenticationError(errorCode, errString);
@@ -126,37 +130,191 @@ namespace keepass2android
_callback.OnAuthenticationSucceeded(result);
}
- private readonly FingerprintModule _fingerprint;
- private readonly string _keyId;
- private Cipher _cipher;
+ protected readonly string _keyId;
+
+ protected Cipher _cipher;
private bool _selfCancelled;
private CancellationSignal _cancellationSignal;
- private FingerprintManager.CryptoObject _cryptoObject;
+ protected FingerprintManager.CryptoObject _cryptoObject;
private FingerprintManager.AuthenticationCallback _callback;
+ protected KeyStore _keystore;
+
+ private FingerprintManager _fingerprintManager;
- public FingerprintEncryptionModule(FingerprintModule fingerprint, string keyId)
+ public FingerprintCrypt(FingerprintModule fingerprint, string keyId)
{
- _fingerprint = fingerprint;
+
_keyId = keyId;
+
_cipher = fingerprint.Cipher;
+ _keystore = fingerprint.Keystore;
+
+ _fingerprintManager = fingerprint.FingerprintManager;
+
+ }
+
+ public abstract bool InitCipher();
+ protected static string GetAlias(string keyId)
+ {
+ return "keepass2android." + keyId;
+ }
+ protected static string GetIvPrefKey(string prefKey)
+ {
+ return prefKey + "_iv";
+ }
+ public bool IsFingerprintAuthAvailable
+ {
+ get
+ {
+ return _fingerprintManager.IsHardwareDetected
+ && _fingerprintManager.HasEnrolledFingerprints;
+ }
+ }
+
+ public void StartListening(FingerprintManager.AuthenticationCallback callback)
+ {
+ if (!IsFingerprintAuthAvailable)
+ return;
+
+ _cancellationSignal = new CancellationSignal();
+ _selfCancelled = false;
+ _callback = callback;
+ _fingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null);
+
+ }
+
+ public void StopListening()
+ {
+ if (_cancellationSignal != null)
+ {
+ _selfCancelled = true;
+ _cancellationSignal.Cancel();
+ _cancellationSignal = null;
+ }
+ }
+
+ public string Encrypt(string textToEncrypt)
+ {
+ return Base64.EncodeToString(_cipher.DoFinal(System.Text.Encoding.UTF8.GetBytes(textToEncrypt)), 0);
+ }
+
+
+ public void StoreEncrypted(string textToEncrypt, string prefKey, Context context)
+ {
+ var edit = PreferenceManager.GetDefaultSharedPreferences(context).Edit();
+
+ edit.PutString(prefKey, Encrypt(textToEncrypt));
+ edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv,0));
+ edit.Commit();
+ }
+
+
+
+ private byte[] CipherIv
+ {
+ get { return _cipher.GetIV(); }
+ }
+ }
+
+ public class FingerprintDecryption : FingerprintCrypt
+ {
+ private readonly byte[] _iv;
+
+
+ public FingerprintDecryption(FingerprintModule fingerprint, string keyId, byte[] iv) : base(fingerprint, keyId)
+ {
+ _iv = iv;
+ }
+
+ public FingerprintDecryption(FingerprintModule fingerprint, string keyId, Context context, string prefKey)
+ : base(fingerprint, keyId)
+ {
+ _iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
+ }
+
+ public override bool InitCipher()
+ {
+
+ try
+ {
+ _keystore.Load(null);
+ var key = _keystore.GetKey(GetAlias(_keyId), null);
+ var ivParams = new IvParameterSpec(_iv);
+ _cipher.Init(CipherMode.DecryptMode, key, ivParams);
+
+ _cryptoObject = new FingerprintManager.CryptoObject(_cipher);
+ return true;
+ }
+ catch (KeyPermanentlyInvalidatedException)
+ {
+ return false;
+ }
+ catch (KeyStoreException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ catch (CertificateException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ catch (UnrecoverableKeyException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new RuntimeException(FailedToInitCipher, e);
+ }
+ }
+
+
+ public string Decrypt(string encryted)
+ {
+ byte[] encryptedBytes = Base64.Decode(encryted, 0);
+ return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
+ }
+
+ public string DecryptStored(string prefKey, Context context)
+ {
+ string enc = PreferenceManager.GetDefaultSharedPreferences(context).GetString(prefKey, null);
+
+ Toast.MakeText(context, "len="+Base64.Decode(enc, 0).Length.ToString(), ToastLength.Long).Show();
+ return Decrypt(enc);
+ }
+ }
+
+ public class FingerprintEncryption : FingerprintCrypt
+ {
+
+ private KeyGenerator _keyGen;
+
+
+ public FingerprintEncryption(FingerprintModule fingerprint, string keyId) :
+ base(fingerprint, keyId)
+ {
+ _keyGen = fingerprint.KeyGenerator;
CreateKey();
}
+
///
/// Creates a symmetric key in the Android Key Store which can only be used after the user
/// has authenticated with fingerprint.
///
private void CreateKey()
{
- // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
- // for your flow. Use of keys is necessary if you need to know if the set of
- // enrolled fingerprints has changed.
try
{
- _fingerprint.Keystore.Load(null);
- // Set the alias of the entry in Android KeyStore where the key will appear
- // and the constrains (purposes) in the constructor of the Builder
- _fingerprint.KeyGenerator.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
+ _keystore.Load(null);
+ _keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
.SetBlockModes(KeyProperties.BlockModeCbc)
// Require the user to authenticate with a fingerprint to authorize every use
@@ -164,7 +322,7 @@ namespace keepass2android
.SetUserAuthenticationRequired(true)
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
.Build());
- _fingerprint.KeyGenerator.GenerateKey();
+ _keyGen.GenerateKey();
}
catch (NoSuchAlgorithmException e)
{
@@ -184,13 +342,14 @@ namespace keepass2android
}
}
- public bool InitCipher()
+ public override bool InitCipher()
{
try
{
- _fingerprint.Keystore.Load(null);
- var key = _fingerprint.Keystore.GetKey(GetAlias(_keyId), null);
+ _keystore.Load(null);
+ var key = _keystore.GetKey(GetAlias(_keyId), null);
_cipher.Init(CipherMode.EncryptMode, key);
+
_cryptoObject = new FingerprintManager.CryptoObject(_cipher);
return true;
}
@@ -200,69 +359,28 @@ namespace keepass2android
}
catch (KeyStoreException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
catch (CertificateException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
catch (UnrecoverableKeyException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
catch (IOException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
catch (NoSuchAlgorithmException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
catch (InvalidKeyException e)
{
- throw new RuntimeException("Failed to init Cipher", e);
+ throw new RuntimeException(FailedToInitCipher, e);
}
}
-
- private string GetAlias(string keyId)
- {
- return "keepass2android." + keyId;
- }
-
- public bool IsFingerprintAuthAvailable
- {
- get
- {
- return _fingerprint.FingerprintManager.IsHardwareDetected
- && _fingerprint.FingerprintManager.HasEnrolledFingerprints;
- }
- }
-
- public void StartListening(FingerprintManager.AuthenticationCallback callback)
- {
- if (!IsFingerprintAuthAvailable)
- return;
-
- _cancellationSignal = new CancellationSignal();
- _selfCancelled = false;
- _callback = callback;
- _fingerprint.FingerprintManager.Authenticate(_cryptoObject, _cancellationSignal, 0 /* flags */, this, null);
-
- }
-
- public void StopListening()
- {
- if (_cancellationSignal != null)
- {
- _selfCancelled = true;
- _cancellationSignal.Cancel();
- _cancellationSignal = null;
- }
- }
-
- public void Encrypt(string textToEncrypt)
- {
- _cipher.DoFinal(MemUtil)
- }
}
}
\ No newline at end of file
diff --git a/src/FingerprintTest/FingerprintTest.csproj b/src/FingerprintTest/FingerprintTest.csproj
index 4049c489..0a8741aa 100644
--- a/src/FingerprintTest/FingerprintTest.csproj
+++ b/src/FingerprintTest/FingerprintTest.csproj
@@ -81,7 +81,7 @@
False
- 21.0.3.0
+ 22.2.0.0
diff --git a/src/FingerprintTest/FingerprintTest.csproj.bak b/src/FingerprintTest/FingerprintTest.csproj.bak
index d9192d70..e603be28 100644
--- a/src/FingerprintTest/FingerprintTest.csproj.bak
+++ b/src/FingerprintTest/FingerprintTest.csproj.bak
@@ -47,14 +47,22 @@
+
+ ..\packages\Xamarin.Android.Support.v4.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll
+
+
+ ..\packages\Xamarin.Android.Support.v7.AppCompat.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll
+
+
+
@@ -70,6 +78,12 @@
+
+
+ False
+ 21.0.3.0
+
+