start implementing Fingerprint stuff

This commit is contained in:
Philipp Crocoll 2015-12-29 14:18:09 +01:00
parent b93d9095db
commit c7e7007bfa
13 changed files with 680 additions and 0 deletions

View File

@ -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");

View File

@ -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();
}
/// <summary>
/// Creates a symmetric key in the Android Key Store which can only be used after the user
/// has authenticated with fingerprint.
/// </summary>
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)
}
}
}

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{52C0A0E7-D625-44BE-948E-D98BC6C82F0F}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FingerprintTest</RootNamespace>
<AssemblyName>FingerprintTest</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
<Reference Include="Xamarin.Android.Support.v4">
<HintPath>..\packages\Xamarin.Android.Support.v4.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat">
<HintPath>..\packages\Xamarin.Android.Support.v7.AppCompat.23.1.1.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="FingerprintModule.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="GettingStarted.Xamarin" />
<None Include="packages.config" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Main.axml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<XamarinComponentReference Include="xamandroidsupportv7appcompat">
<Visible>False</Visible>
<Version>21.0.3.0</Version>
</XamarinComponentReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{52C0A0E7-D625-44BE-948E-D98BC6C82F0F}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>FingerprintTest</RootNamespace>
<AssemblyName>FingerprintTest</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="GettingStarted.Xamarin" />
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Main.axml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,4 @@
<GettingStarted>
<LocalContent>GS\Android\CS\AndroidApp\GettingStarted.html</LocalContent>
<EmbeddedNavigation>false</EmbeddedNavigation>
</GettingStarted>

View File

@ -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<Button>(Resource.Id.MyButton);
button.Visibility = ViewStates.Gone;
RequestPermissions(new[] { Manifest.Permission.UseFingerprint }, FINGERPRINT_PERMISSION_REQUEST_CODE);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
if (requestCode == FINGERPRINT_PERMISSION_REQUEST_CODE && grantResults[0] == Android.Content.PM.Permission.Granted)
{
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Visibility = ViewStates.Visible;
button.Enabled = true;
var fingerprint = new keepass2android.FingerprintModule(this);
button.Click += (sender, args) =>
{
};
if (!fingerprint.KeyguardManager.IsKeyguardSecure)
{
button.Enabled = false;
// Show a message that the user hasn't set up a fingerprint or lock screen.
Toast.MakeText(this, "Secure lock screen hasn't set up.\n"
+ "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint", ToastLength.Long).Show();
return;
}
if (!fingerprint.FingerprintManager.HasEnrolledFingerprints)
{
button.Enabled = false;
// This happens when no fingerprints are registered.
Toast.MakeText(this, "Go to 'Settings -> Security -> Fingerprint' " +
"and register at least one fingerprint", ToastLength.Long).Show();
return;
}
var fingerprintEnc = new FingerprintEncryptionModule(fingerprint, "abc");
if (fingerprintEnc.InitCipher())
{
fingerprintEnc.StartListening(new EncryptionCallback(this, fingerprintEnc));
}
else
{
Toast.MakeText(this, "Error initiating cipher", ToastLength.Long).Show();
}
}
}
}
public class EncryptionCallback : FingerprintManager.AuthenticationCallback
{
private readonly FingerprintEncryptionModule _fingerprintEnc;
public EncryptionCallback(Context context, FingerprintEncryptionModule fingerprintEnc)
{
_fingerprintEnc = fingerprintEnc;
}
public override void OnAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)
{
_fingerprintEnc.Encrypt("abc");
var edit = PreferenceManager.GetDefaultSharedPreferences(Application.Context).Edit();
edit.PutString("encrypted", );
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="FingerprintTest.FingerprintTest" android:versionCode="1" android:versionName="1.0">
<uses-sdk android:targetSdkVersion="15" />
<application android:label="FingerprintTest" android:icon="@drawable/Icon"></application>
</manifest>

View File

@ -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("FingerprintTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FingerprintTest")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[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")]

View File

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="@+id/MyButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/Hello"
/>
</LinearLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">FingerprintTest</string>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Xamarin.Android.Support.v4" version="23.1.1.0" targetFramework="MonoAndroid60" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="23.1.1.0" targetFramework="MonoAndroid60" />
</packages>