From c7e7007bfadb769478862ce35f9da281bfb7c5ff Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 29 Dec 2015 14:18:09 +0100 Subject: [PATCH] start implementing Fingerprint stuff --- src/FingerprintTest/Assets/AboutAssets.txt | 19 ++ src/FingerprintTest/FingerprintModule.cs | 268 ++++++++++++++++++ src/FingerprintTest/FingerprintTest.csproj | 95 +++++++ .../FingerprintTest.csproj.bak | 81 ++++++ src/FingerprintTest/GettingStarted.Xamarin | 4 + src/FingerprintTest/MainActivity.cs | 105 +++++++ .../Properties/AndroidManifest.xml | 5 + .../Properties/AssemblyInfo.cs | 30 ++ .../Resources/AboutResources.txt | 50 ++++ .../Resources/drawable/Icon.png | Bin 0 -> 4147 bytes .../Resources/layout/Main.axml | 13 + .../Resources/values/Strings.xml | 5 + src/FingerprintTest/packages.config | 5 + 13 files changed, 680 insertions(+) create mode 100644 src/FingerprintTest/Assets/AboutAssets.txt create mode 100644 src/FingerprintTest/FingerprintModule.cs create mode 100644 src/FingerprintTest/FingerprintTest.csproj create mode 100644 src/FingerprintTest/FingerprintTest.csproj.bak create mode 100644 src/FingerprintTest/GettingStarted.Xamarin create mode 100644 src/FingerprintTest/MainActivity.cs create mode 100644 src/FingerprintTest/Properties/AndroidManifest.xml create mode 100644 src/FingerprintTest/Properties/AssemblyInfo.cs create mode 100644 src/FingerprintTest/Resources/AboutResources.txt create mode 100644 src/FingerprintTest/Resources/drawable/Icon.png create mode 100644 src/FingerprintTest/Resources/layout/Main.axml create mode 100644 src/FingerprintTest/Resources/values/Strings.xml create mode 100644 src/FingerprintTest/packages.config diff --git a/src/FingerprintTest/Assets/AboutAssets.txt b/src/FingerprintTest/Assets/AboutAssets.txt new file mode 100644 index 00000000..ee398862 --- /dev/null +++ b/src/FingerprintTest/Assets/AboutAssets.txt @@ -0,0 +1,19 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories) and given a Build Action of "AndroidAsset". + +These files will be deployed with you package and will be accessible using Android's +AssetManager, like this: + +public class ReadAsset : Activity +{ + protected override void OnCreate (Bundle bundle) + { + base.OnCreate (bundle); + + InputStream input = Assets.Open ("my_asset.txt"); + } +} + +Additionally, some Android functions will automatically load asset files: + +Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); \ No newline at end of file diff --git a/src/FingerprintTest/FingerprintModule.cs b/src/FingerprintTest/FingerprintModule.cs new file mode 100644 index 00000000..faefaff8 --- /dev/null +++ b/src/FingerprintTest/FingerprintModule.cs @@ -0,0 +1,268 @@ +using System; +using Android.Content; +using Javax.Crypto; +using Java.Security; +using Java.Lang; +using Android.Views.InputMethods; +using Android.App; +using Android.Hardware.Fingerprints; +using Android.OS; +using Android.Security.Keystore; +using Android.Preferences; +using Java.IO; +using Java.Security.Cert; + +namespace keepass2android +{ + public class FingerprintModule + { + public Context Context { get; set; } + + public FingerprintModule (Context context) + { + Context = context; + } + + public FingerprintManager FingerprintManager + { + get { return (FingerprintManager) Context.GetSystemService("FingerprintManager"); } + } + + public KeyguardManager KeyguardManager + { + get + { + return (KeyguardManager) Context.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 InputMethodManager InputMethodManager + { + get { return (InputMethodManager) Context.GetSystemService(Context.InputMethodService); } + } + + public ISharedPreferences SharedPreferences + { + get { return PreferenceManager.GetDefaultSharedPreferences(Context); } + } + } + + public class FingerprintEncryptionModule: FingerprintManager.AuthenticationCallback + { + public override void OnAuthenticationError(FingerprintState errorCode, ICharSequence errString) + { + _callback.OnAuthenticationError(errorCode, errString); + } + + public override void OnAuthenticationFailed() + { + if (!_selfCancelled) + _callback.OnAuthenticationFailed(); + } + + public override void OnAuthenticationHelp(FingerprintState helpCode, ICharSequence helpString) + { + _callback.OnAuthenticationHelp(helpCode, helpString); + } + + public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) + { + _callback.OnAuthenticationSucceeded(result); + } + + private readonly FingerprintModule _fingerprint; + private readonly string _keyId; + private Cipher _cipher; + private bool _selfCancelled; + private CancellationSignal _cancellationSignal; + private FingerprintManager.CryptoObject _cryptoObject; + private FingerprintManager.AuthenticationCallback _callback; + + public FingerprintEncryptionModule(FingerprintModule fingerprint, string keyId) + { + _fingerprint = fingerprint; + _keyId = keyId; + _cipher = fingerprint.Cipher; + 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), + KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) + .SetBlockModes(KeyProperties.BlockModeCbc) + // Require the user to authenticate with a fingerprint to authorize every use + // of the key + .SetUserAuthenticationRequired(true) + .SetEncryptionPaddings(KeyProperties.EncryptionPaddingPkcs7) + .Build()); + _fingerprint.KeyGenerator.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); + } + } + + public bool InitCipher() + { + try + { + _fingerprint.Keystore.Load(null); + var key = _fingerprint.Keystore.GetKey(GetAlias(_keyId), null); + _cipher.Init(CipherMode.EncryptMode, key); + _cryptoObject = new FingerprintManager.CryptoObject(_cipher); + return true; + } + catch (KeyPermanentlyInvalidatedException) + { + return false; + } + catch (KeyStoreException e) + { + throw new RuntimeException("Failed to init Cipher", e); + } + catch (CertificateException e) + { + throw new RuntimeException("Failed to init Cipher", e); + } + catch (UnrecoverableKeyException e) + { + throw new RuntimeException("Failed to init Cipher", e); + } + catch (IOException e) + { + throw new RuntimeException("Failed to init Cipher", e); + } + catch (NoSuchAlgorithmException e) + { + throw new RuntimeException("Failed to init Cipher", e); + } + catch (InvalidKeyException e) + { + throw new RuntimeException("Failed to init Cipher", 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 new file mode 100644 index 00000000..4049c489 --- /dev/null +++ b/src/FingerprintTest/FingerprintTest.csproj @@ -0,0 +1,95 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {52C0A0E7-D625-44BE-948E-D98BC6C82F0F} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + FingerprintTest + FingerprintTest + 512 + true + Resources\Resource.Designer.cs + Off + True + v6.0 + Properties\AndroidManifest.xml + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + True + None + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + False + SdkOnly + + + + + + + + + + ..\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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + 21.0.3.0 + + + + + \ No newline at end of file diff --git a/src/FingerprintTest/FingerprintTest.csproj.bak b/src/FingerprintTest/FingerprintTest.csproj.bak new file mode 100644 index 00000000..d9192d70 --- /dev/null +++ b/src/FingerprintTest/FingerprintTest.csproj.bak @@ -0,0 +1,81 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {52C0A0E7-D625-44BE-948E-D98BC6C82F0F} + {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + FingerprintTest + FingerprintTest + 512 + true + Resources\Resource.Designer.cs + Off + True + v5.0 + Properties\AndroidManifest.xml + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + True + None + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + False + SdkOnly + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/FingerprintTest/GettingStarted.Xamarin b/src/FingerprintTest/GettingStarted.Xamarin new file mode 100644 index 00000000..e9d4f6a4 --- /dev/null +++ b/src/FingerprintTest/GettingStarted.Xamarin @@ -0,0 +1,4 @@ + + GS\Android\CS\AndroidApp\GettingStarted.html + false + \ No newline at end of file diff --git a/src/FingerprintTest/MainActivity.cs b/src/FingerprintTest/MainActivity.cs new file mode 100644 index 00000000..ac8b6c93 --- /dev/null +++ b/src/FingerprintTest/MainActivity.cs @@ -0,0 +1,105 @@ +using System; +using Android; +using Android.App; +using Android.Content; +using Android.Content.PM; +using Android.Hardware.Fingerprints; +using Android.Runtime; +using Android.Views; +using Android.Widget; +using Android.OS; +using Android.Preferences; +using Android.Support.V7.App; +using keepass2android; + +namespace FingerprintTest +{ + [Activity(Label = "FingerprintTest", MainLauncher = true, Icon = "@drawable/icon")] + public class MainActivity : AppCompatActivity + { + int count = 1; + const int FINGERPRINT_PERMISSION_REQUEST_CODE = 0; + + protected override void OnCreate(Bundle bundle) + { + base.OnCreate(bundle); + + // Set our view from the "main" layout resource + SetContentView(Resource.Layout.Main); + + // Get our button from the layout resource, + // and attach an event to it + Button button = FindViewById