diff --git a/src/BiometricBinding/Additions/AboutAdditions.txt b/src/BiometricBinding/Additions/AboutAdditions.txt
new file mode 100644
index 00000000..c2403076
--- /dev/null
+++ b/src/BiometricBinding/Additions/AboutAdditions.txt
@@ -0,0 +1,48 @@
+Additions allow you to add arbitrary C# to the generated classes
+before they are compiled. This can be helpful for providing convenience
+methods or adding pure C# classes.
+
+== Adding Methods to Generated Classes ==
+
+Let's say the library being bound has a Rectangle class with a constructor
+that takes an x and y position, and a width and length size. It will look like
+this:
+
+public partial class Rectangle
+{
+ public Rectangle (int x, int y, int width, int height)
+ {
+ // JNI bindings
+ }
+}
+
+Imagine we want to add a constructor to this class that takes a Point and
+Size structure instead of 4 ints. We can add a new file called Rectangle.cs
+with a partial class containing our new method:
+
+public partial class Rectangle
+{
+ public Rectangle (Point location, Size size) :
+ this (location.X, location.Y, size.Width, size.Height)
+ {
+ }
+}
+
+At compile time, the additions class will be added to the generated class
+and the final assembly will a Rectangle class with both constructors.
+
+
+== Adding C# Classes ==
+
+Another thing that can be done is adding fully C# managed classes to the
+generated library. In the above example, let's assume that there isn't a
+Point class available in Java or our library. The one we create doesn't need
+to interact with Java, so we'll create it like a normal class in C#.
+
+By adding a Point.cs file with this class, it will end up in the binding library:
+
+public class Point
+{
+ public int X { get; set; }
+ public int Y { get; set; }
+}
\ No newline at end of file
diff --git a/src/BiometricBinding/BiometricBinding.csproj b/src/BiometricBinding/BiometricBinding.csproj
new file mode 100644
index 00000000..b92aa63b
--- /dev/null
+++ b/src/BiometricBinding/BiometricBinding.csproj
@@ -0,0 +1,70 @@
+
+
+
+ Debug
+ AnyCPU
+ 8.0.30703
+ 2.0
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}
+ {10368E6C-D01B-4462-8E8B-01FC667A7035};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {77efb91c-a7e9-4b0e-a7c5-31eeec3c6d46}
+ Library
+ Properties
+ BiometricBinding
+ BiometricBinding
+ 512
+ false
+ v10.0
+ class-parse
+ XAJavaInterop1
+ PackageReference
+
+
+ true
+ portable
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ portable
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.0.0-preview02
+
+
+
+
+
\ No newline at end of file
diff --git a/src/BiometricBinding/Jars/AboutJars.txt b/src/BiometricBinding/Jars/AboutJars.txt
new file mode 100644
index 00000000..c359b62f
--- /dev/null
+++ b/src/BiometricBinding/Jars/AboutJars.txt
@@ -0,0 +1,24 @@
+This directory is for Android .jars.
+
+There are 2 types of jars that are supported:
+
+== Input Jar ==
+
+This is the jar that bindings should be generated for.
+
+For example, if you were binding the Google Maps library, this would
+be Google's "maps.jar".
+
+Set the build action for these jars in the properties page to "InputJar".
+
+
+== Reference Jars ==
+
+These are jars that are referenced by the input jar. C# bindings will
+not be created for these jars. These jars will be used to resolve
+types used by the input jar.
+
+NOTE: Do not add "android.jar" as a reference jar. It will be added automatically
+based on the Target Framework selected.
+
+Set the build action for these jars in the properties page to "ReferenceJar".
\ No newline at end of file
diff --git a/src/BiometricBinding/Jars/biometric-1.0.0-rc02.aar b/src/BiometricBinding/Jars/biometric-1.0.0-rc02.aar
new file mode 100644
index 00000000..128ee2c8
Binary files /dev/null and b/src/BiometricBinding/Jars/biometric-1.0.0-rc02.aar differ
diff --git a/src/BiometricBinding/Properties/AssemblyInfo.cs b/src/BiometricBinding/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..f874d2fc
--- /dev/null
+++ b/src/BiometricBinding/Properties/AssemblyInfo.cs
@@ -0,0 +1,30 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("BiometricBinding")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BiometricBinding")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/BiometricBinding/Transforms/EnumFields.xml b/src/BiometricBinding/Transforms/EnumFields.xml
new file mode 100644
index 00000000..22959957
--- /dev/null
+++ b/src/BiometricBinding/Transforms/EnumFields.xml
@@ -0,0 +1,14 @@
+
+
+
\ No newline at end of file
diff --git a/src/BiometricBinding/Transforms/EnumMethods.xml b/src/BiometricBinding/Transforms/EnumMethods.xml
new file mode 100644
index 00000000..49216c61
--- /dev/null
+++ b/src/BiometricBinding/Transforms/EnumMethods.xml
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/src/BiometricBinding/Transforms/Metadata.xml b/src/BiometricBinding/Transforms/Metadata.xml
new file mode 100644
index 00000000..91493a25
--- /dev/null
+++ b/src/BiometricBinding/Transforms/Metadata.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/src/KeePass.sln b/src/KeePass.sln
index da7c6ee4..652a3fb4 100644
--- a/src/KeePass.sln
+++ b/src/KeePass.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2009
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29418.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KeePassLib2Android", "KeePassLib2Android\KeePassLib2Android.csproj", "{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}"
EndProject
@@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamsungPass", "SamsungPass\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCloudBindings", "PCloudBindings\PCloudBindings.csproj", "{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BiometricBinding", "BiometricBinding\BiometricBinding.csproj", "{2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -315,6 +317,30 @@ Global
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|Win32.Build.0 = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.ActiveCfg = ReleaseNoNet|Any CPU
{2DB80C77-D46F-4970-B967-E9FFA9B2AC2E}.ReleaseNoNet|x64.Build.0 = ReleaseNoNet|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|Win32.Build.0 = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Debug|x64.Build.0 = Debug|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|Win32.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.Release|x64.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|Win32.Build.0 = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
+ {2B1DE455-BF8E-4F8A-87BE-AE7EA354F3E4}.ReleaseNoNet|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java b/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java
index acad23d0..dc75569b 100644
--- a/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java
+++ b/src/java/KP2ASoftkeyboard_AS/app/src/main/java/keepass2android/softkeyboard/LatinKeyboardBaseView.java
@@ -26,6 +26,7 @@ import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region.Op;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -774,7 +775,9 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
mKeyboardChanged = false;
}
final Canvas canvas = mCanvas;
- canvas.clipRect(mDirtyRect, Op.REPLACE);
+ canvas.save();
+ canvas.clipRect(new RectF(mDirtyRect));
+
if (mKeyboard == null) return;
@@ -907,6 +910,8 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
}
}
+ canvas.restore();
+
mDrawPending = false;
mDirtyRect.setEmpty();
}
diff --git a/src/keepass2android/BiometricModule.cs b/src/keepass2android/BiometricModule.cs
new file mode 100644
index 00000000..7f81a02c
--- /dev/null
+++ b/src/keepass2android/BiometricModule.cs
@@ -0,0 +1,549 @@
+using System;
+using Android.Content;
+using Javax.Crypto;
+using Java.Security;
+using Java.Lang;
+using Android.Views.InputMethods;
+using Android.App;
+using Android.OS;
+using Android.Security.Keystore;
+using Android.Preferences;
+using Android.Util;
+using Android.Widget;
+using Androidx.Biometric;
+using AndroidX.Fragment.App;
+using Java.IO;
+using Java.Security.Cert;
+using Java.Util.Concurrent;
+using Javax.Crypto.Spec;
+using Exception = System.Exception;
+using File = System.IO.File;
+
+namespace keepass2android
+{
+
+ public static class Kp2aLog
+ {
+ private static bool? _logToFile;
+
+ private static object _fileLocker = new object();
+
+ public static void Log(string message)
+ {
+ if (message != null)
+ Android.Util.Log.Debug("KP2A", message);
+ if (LogToFile)
+ {
+ lock (_fileLocker)
+ {
+ try
+ {
+ using (var streamWriter = System.IO.File.AppendText(LogFilename))
+ {
+ string stringToLog = DateTime.Now + ":" + DateTime.Now.Millisecond + " -- " + message;
+ streamWriter.WriteLine(stringToLog);
+ }
+ }
+ catch (Exception e)
+ {
+ Android.Util.Log.Debug("KP2A", "Couldn't write to log file. " + e);
+ }
+ }
+
+ }
+
+ }
+
+ private static string LogFilename
+ {
+ get { return Application.Context.FilesDir.CanonicalPath + "/keepass2android.log"; }
+ }
+
+ private static bool LogToFile
+ {
+ get
+ {
+ if (_logToFile == null)
+ _logToFile = System.IO.File.Exists(LogFilename);
+ return (bool)_logToFile;
+ }
+ }
+ public static event EventHandler OnUnexpectedError;
+
+ public static void LogUnexpectedError(Exception exception)
+ {
+ Log(exception.ToString());
+ if (OnUnexpectedError != null)
+ OnUnexpectedError(null, exception);
+ }
+
+ public static void CreateLogFile()
+ {
+ if (!System.IO.File.Exists(LogFilename))
+ {
+ System.IO.File.Create(LogFilename).Dispose();
+ _logToFile = true;
+ }
+
+
+ }
+
+ public static void FinishLogFile()
+ {
+ if (System.IO.File.Exists(LogFilename))
+ {
+ _logToFile = false;
+ int count = 0;
+ while (System.IO.File.Exists(LogFilename + "." + count))
+ count++;
+ System.IO.File.Move(LogFilename, LogFilename + "." + count);
+
+ }
+
+ }
+
+ public static void SendLog(Context ctx)
+ {
+ if (!System.IO.File.Exists(LogFilename))
+ return;
+ Intent sendIntent = new Intent();
+ sendIntent.SetAction(Intent.ActionSend);
+ sendIntent.PutExtra(Intent.ExtraText, File.ReadAllText(LogFilename));
+ sendIntent.PutExtra(Intent.ExtraEmail, "crocoapps@gmail.com");
+ sendIntent.PutExtra(Intent.ExtraSubject, "Keepass2Android log");
+ sendIntent.SetType("text/plain");
+ ctx.StartActivity(Intent.CreateChooser(sendIntent, "Send log to..."));
+ }
+ }
+ public interface IBiometricAuthCallback
+ {
+ void OnBiometricAuthSucceeded();
+ void OnBiometricError(string toString);
+ }
+
+ public class BiometricModule
+ {
+ public AndroidX.Fragment.App.FragmentActivity Activity { get; set; }
+
+ public BiometricModule(AndroidX.Fragment.App.FragmentActivity activity)
+ {
+ Activity = activity;
+ }
+
+
+ public KeyguardManager KeyguardManager
+ {
+ get
+ {
+ return (KeyguardManager)Activity.GetSystemService("keyguard");
+ }
+ }
+
+
+ public KeyStore Keystore
+ {
+ get
+ {
+ try
+ {
+ return KeyStore.GetInstance("AndroidKeyStore");
+ }
+ catch (KeyStoreException e)
+ {
+ throw new RuntimeException("Failed to get an instance of KeyStore", e);
+ }
+ }
+ }
+
+ public KeyGenerator KeyGenerator
+ {
+ get
+ {
+ try
+ {
+ return KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, "AndroidKeyStore");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
+ }
+ }
+ }
+
+ public Cipher Cipher
+ {
+ get
+ {
+ try
+ {
+ return Cipher.GetInstance(KeyProperties.KeyAlgorithmAes + "/"
+ + KeyProperties.BlockModeCbc + "/"
+ + KeyProperties.EncryptionPaddingPkcs7);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException("Failed to get an instance of Cipher", e);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new RuntimeException("Failed to get an instance of Cipher", e);
+ }
+ }
+ }
+
+ public ISharedPreferences SharedPreferences
+ {
+ get { return PreferenceManager.GetDefaultSharedPreferences(Activity); }
+ }
+
+ public bool IsAvailable
+ {
+ get
+ {
+ return BiometricManager.From(Activity).CanAuthenticate() ==
+ BiometricManager.BiometricSuccess;
+ }
+ }
+
+ public bool IsHardwareAvailable
+ {
+ get
+ {
+ var result = BiometricManager.From(Activity).CanAuthenticate();
+ return result == BiometricManager.BiometricSuccess
+ || result == BiometricManager.BiometricErrorNoneEnrolled;
+ }
+ }
+ }
+
+ public abstract class BiometricCrypt : IBiometricIdentifier
+ {
+ protected const string FailedToInitCipher = "Failed to init Cipher";
+
+ protected readonly string _keyId;
+
+ protected Cipher _cipher;
+ private CancellationSignal _cancellationSignal;
+ protected BiometricPrompt.CryptoObject _cryptoObject;
+
+ protected KeyStore _keystore;
+
+ private BiometricPrompt _biometricPrompt;
+ private FragmentActivity _activity;
+
+ public BiometricCrypt(BiometricModule biometric, string keyId)
+ {
+ Kp2aLog.Log("FP: Create " + this.GetType().Name);
+ _keyId = keyId;
+ _cipher = biometric.Cipher;
+ _keystore = biometric.Keystore;
+ _activity = biometric.Activity;
+
+
+
+ }
+
+ public abstract bool Init();
+
+
+ protected static string GetAlias(string keyId)
+ {
+ return "keepass2android." + keyId;
+ }
+ protected static string GetIvPrefKey(string prefKey)
+ {
+ return prefKey + "_iv";
+ }
+
+ public void StartListening(IBiometricAuthCallback callback)
+ {
+
+ StartListening(new BiometricAuthCallbackAdapter(callback, _activity));
+ }
+
+ public void StopListening()
+ {
+
+ }
+
+ public bool HasUserInterface
+ {
+ get { return true; }
+
+ }
+
+ public void StartListening(BiometricPrompt.AuthenticationCallback callback)
+ {
+
+ Kp2aLog.Log("Fingerprint: StartListening ");
+
+ var executor = Executors.NewSingleThreadExecutor();
+ _biometricPrompt = new Androidx.Biometric.BiometricPrompt(_activity, executor, callback);
+
+ BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
+ .SetTitle(_activity.GetString(AppNames.AppNameResource))
+ .SetSubtitle(_activity.GetString(Resource.String.unlock_database_title))
+ .SetNegativeButtonText(_activity.GetString(Android.Resource.String.Cancel))
+ .Build();
+
+
+ _biometricPrompt.Authenticate(promptInfo, _cryptoObject);
+
+ }
+
+ public string Encrypt(string textToEncrypt)
+ {
+ Kp2aLog.Log("FP: Encrypting");
+ 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();
+ StoreEncrypted(textToEncrypt, prefKey, edit);
+ edit.Commit();
+ }
+
+ public void StoreEncrypted(string textToEncrypt, string prefKey, ISharedPreferencesEditor edit)
+ {
+ edit.PutString(prefKey, Encrypt(textToEncrypt));
+ edit.PutString(GetIvPrefKey(prefKey), Base64.EncodeToString(CipherIv, 0));
+
+ }
+
+
+ private byte[] CipherIv
+ {
+ get { return _cipher.GetIV(); }
+ }
+ }
+
+ public interface IBiometricIdentifier
+ {
+ bool Init();
+ void StartListening(IBiometricAuthCallback callback);
+
+ void StopListening();
+ bool HasUserInterface { get; }
+ }
+
+ public class BiometricDecryption : BiometricCrypt
+ {
+ private readonly Context _context;
+ private readonly byte[] _iv;
+
+
+ public BiometricDecryption(BiometricModule biometric, string keyId, byte[] iv) : base(biometric, keyId)
+ {
+ _iv = iv;
+ }
+
+ public BiometricDecryption(BiometricModule biometric, string keyId, Context context, string prefKey)
+ : base(biometric, keyId)
+ {
+ _context = context;
+ _iv = Base64.Decode(PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null), 0);
+ }
+
+ public static bool IsSetUp(Context context, string prefKey)
+ {
+ return PreferenceManager.GetDefaultSharedPreferences(context).GetString(GetIvPrefKey(prefKey), null) != null;
+ }
+
+ public override bool Init()
+ {
+ Kp2aLog.Log("FP: Init for Dec");
+ try
+ {
+ _keystore.Load(null);
+ var key = _keystore.GetKey(GetAlias(_keyId), null);
+ var ivParams = new IvParameterSpec(_iv);
+ _cipher.Init(CipherMode.DecryptMode, key, ivParams);
+
+ _cryptoObject = new BiometricPrompt.CryptoObject(_cipher);
+ return true;
+ }
+ catch (KeyPermanentlyInvalidatedException e)
+ {
+ Kp2aLog.Log("FP: KeyPermanentlyInvalidatedException." + e.ToString());
+ 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)
+ {
+ Kp2aLog.Log("FP: Decrypting ");
+ byte[] encryptedBytes = Base64.Decode(encryted, 0);
+ return System.Text.Encoding.UTF8.GetString(_cipher.DoFinal(encryptedBytes));
+ }
+
+ public string DecryptStored(string prefKey)
+ {
+ string enc = PreferenceManager.GetDefaultSharedPreferences(_context).GetString(prefKey, null);
+ return Decrypt(enc);
+ }
+ }
+
+ public class BiometricEncryption : BiometricCrypt
+ {
+
+ private KeyGenerator _keyGen;
+
+
+ public BiometricEncryption(BiometricModule biometric, string keyId) :
+ base(biometric, keyId)
+ {
+ _keyGen = biometric.KeyGenerator;
+ Kp2aLog.Log("FP: CreateKey ");
+ CreateKey();
+ }
+
+
+ ///
+ /// Creates a symmetric key in the Android Key Store which can only be used after the user
+ /// has authenticated with biometry.
+ ///
+ private void CreateKey()
+ {
+ try
+ {
+ _keystore.Load(null);
+ _keyGen.Init(new KeyGenParameterSpec.Builder(GetAlias(_keyId),
+ KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt)
+ .SetBlockModes(KeyProperties.BlockModeCbc)
+ // Require the user to authenticate with biometry to authorize every use
+ // of the key
+ .SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7)
+ .SetUserAuthenticationRequired(true)
+
+ .Build());
+ _keyGen.GenerateKey();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (CertificateException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (System.Exception e)
+ {
+ Kp2aLog.LogUnexpectedError(e);
+ }
+ }
+
+ public override bool Init()
+ {
+ Kp2aLog.Log("FP: Init for Enc ");
+ try
+ {
+ _keystore.Load(null);
+ var key = _keystore.GetKey(GetAlias(_keyId), null);
+ _cipher.Init(CipherMode.EncryptMode, key);
+
+ _cryptoObject = new BiometricPrompt.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 class BiometricAuthCallbackAdapter : BiometricPrompt.AuthenticationCallback
+ {
+ private readonly IBiometricAuthCallback _callback;
+ private readonly Context _context;
+
+ public BiometricAuthCallbackAdapter(IBiometricAuthCallback callback, Context context)
+ {
+ _callback = callback;
+ _context = context;
+ }
+
+
+ public override void OnAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result)
+ {
+ new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricAuthSucceeded());
+ }
+
+ public override void OnAuthenticationError(int errorCode, ICharSequence errString)
+ {
+
+ new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(errString.ToString()));
+ }
+
+
+ public override void OnAuthenticationFailed()
+ {
+ new Handler(Looper.MainLooper).Post(() => _callback.OnBiometricError(_context.Resources.GetString(Resource.String.fingerprint_not_recognized)));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/keepass2android/CloseImmediatelyActivity.cs b/src/keepass2android/CloseImmediatelyActivity.cs
index 5a047923..1d7baac1 100644
--- a/src/keepass2android/CloseImmediatelyActivity.cs
+++ b/src/keepass2android/CloseImmediatelyActivity.cs
@@ -15,7 +15,7 @@ using Android.Widget;
namespace keepass2android
{
[Activity(Label = AppNames.AppName, Theme = "@style/MyTheme_ActionBar", ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden)]
- public class CloseImmediatelyActivity : AppCompatActivity
+ public class CloseImmediatelyActivity : AndroidX.AppCompat.App.AppCompatActivity
{
protected override void OnResume()
{
diff --git a/src/keepass2android/ConfigureChildDatabasesActivity.cs b/src/keepass2android/ConfigureChildDatabasesActivity.cs
index a80132dd..4c2800ee 100644
--- a/src/keepass2android/ConfigureChildDatabasesActivity.cs
+++ b/src/keepass2android/ConfigureChildDatabasesActivity.cs
@@ -284,7 +284,7 @@ namespace keepass2android
var listView = FindViewById(Android.Resource.Id.List);
listView.Adapter = _adapter;
- SetSupportActionBar(FindViewById(Resource.Id.mytoolbar));
+ SetSupportActionBar(FindViewById(Resource.Id.mytoolbar));
FindViewById