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