create own YubiChallenge activity
This commit is contained in:
@@ -33,7 +33,7 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
}
|
||||
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(challenge64, true);
|
||||
var chalIntent = Activity.GetYubichallengeIntent(challenge64);
|
||||
|
||||
if (chalIntent == null)
|
||||
throw new Exception("YubiChallenge not installed.");
|
||||
|
||||
@@ -218,14 +218,18 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
//update the Entry output in the App database and notify the CopyToClipboard service
|
||||
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value));
|
||||
Intent updateKeyboardIntent = new Intent(this, typeof(CopyToClipboardService));
|
||||
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
|
||||
updateKeyboardIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
|
||||
StartService(updateKeyboardIntent);
|
||||
|
||||
//notify plugins
|
||||
NotifyPluginsOnModification(Strings.PrefixString+key);
|
||||
if (App.Kp2a.GetDb()?.LastOpenedEntry != null)
|
||||
{
|
||||
App.Kp2a.GetDb().LastOpenedEntry.OutputStrings.Set(key, new ProtectedString(isProtected, value));
|
||||
Intent updateKeyboardIntent = new Intent(this, typeof(CopyToClipboardService));
|
||||
updateKeyboardIntent.SetAction(Intents.UpdateKeyboard);
|
||||
updateKeyboardIntent.PutExtra(KeyEntry, Entry.Uuid.ToHexString());
|
||||
StartService(updateKeyboardIntent);
|
||||
|
||||
//notify plugins
|
||||
NotifyPluginsOnModification(Strings.PrefixString + key);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddPluginAction(string pluginPackage, string fieldId, string popupItemId, string displayText, int iconId, Bundle bundleExtra)
|
||||
|
||||
@@ -123,27 +123,12 @@ namespace keepass2android
|
||||
}
|
||||
|
||||
|
||||
public Intent TryGetYubichallengeIntentOrPrompt(byte[] challenge, bool promptToInstall)
|
||||
public Intent GetYubichallengeIntent(byte[] challenge)
|
||||
{
|
||||
Intent chalIntent = new Intent("com.yubichallenge.NFCActivity.CHALLENGE");
|
||||
Intent chalIntent = new Intent(this, typeof(YubiChallengeActivity));
|
||||
chalIntent.PutExtra("challenge", challenge);
|
||||
chalIntent.PutExtra("slot", 2);
|
||||
IList<ResolveInfo> activities = PackageManager.QueryIntentActivities(chalIntent, 0);
|
||||
bool isIntentSafe = activities.Count > 0;
|
||||
if (isIntentSafe)
|
||||
{
|
||||
return chalIntent;
|
||||
}
|
||||
if (promptToInstall)
|
||||
{
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(this);
|
||||
b.SetMessage(Resource.String.YubiChallengeNotInstalled);
|
||||
b.SetPositiveButton(Android.Resource.String.Ok,
|
||||
delegate { Util.GotoUrl(this, GetString(Resource.String.MarketURL) + "com.yubichallenge"); });
|
||||
b.SetNegativeButton(Resource.String.cancel, delegate { });
|
||||
b.Create().Show();
|
||||
}
|
||||
return null;
|
||||
return chalIntent;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,7 +625,7 @@ namespace keepass2android
|
||||
|
||||
protected override void HandleSuccess()
|
||||
{
|
||||
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(Activity._chalInfo.Challenge, true);
|
||||
var chalIntent = Activity.GetYubichallengeIntent(Activity._chalInfo.Challenge);
|
||||
|
||||
if (chalIntent != null)
|
||||
{
|
||||
|
||||
@@ -139,6 +139,7 @@
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W" android:value="426.0dip" />
|
||||
<meta-data android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H" android:value="360.0dip" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
@@ -864,7 +864,6 @@ Erstes öffentliches Release</string>
|
||||
<item>Kennwort + OTP Secret (Recovery-Modus)</item>
|
||||
<item>Passwort + Challenge-Response</item>
|
||||
<item>Passwort + Challenge-Response-Secret (Recovery-Modus)</item>
|
||||
<item>Password + Challenge-Response for KeepassXC database</item>
|
||||
</string-array>
|
||||
<string-array name="AcceptAllServerCertificates_options">
|
||||
<item>Fehler bei Zertifikatsvalidierung ignorieren</item>
|
||||
|
||||
@@ -554,7 +554,6 @@
|
||||
<string name="init_otp">Load OTP auxiliary file…</string>
|
||||
<string name="otp_explanation">Enter the next One-time-passwords (OTPs). Swipe your Yubikey NEO at the back of your device to enter via NFC.</string>
|
||||
<string name="otp_hint">OTP %1$d</string>
|
||||
<string name="YubiChallengeNotInstalled">Could not find an app that can handle the challenge. Please install Yubichallenge from Google Play.</string>
|
||||
<string name="CouldntLoadOtpAuxFile">Could not load auxiliary OTP file!</string>
|
||||
<string name="CouldntLoadOtpAuxFile_Hint">Please use the OtpKeyProv plugin in KeePass 2.x (PC) to configure your database for use with OTPs!</string>
|
||||
<string name="otp_discarded_because_no_db">Please select database first. OTP is discarded for security reasons.</string>
|
||||
@@ -567,6 +566,19 @@
|
||||
<string name="ErrorUpdatingOtpAuxFile">Error updating OTP auxiliary file!</string>
|
||||
<string name="SavingOtpAuxFile">Saving auxiliary OTP file…</string>
|
||||
|
||||
<string name="yubichallenge_title_activity_nfc">NFC Challenge-Response</string>
|
||||
<string name="yubichallenge_challenging">Challenging</string>
|
||||
<string name="yubichallenge_swipe">Please swipe your YubiKey NEO</string>
|
||||
<string name="yubichallenge_swipe_and_hold">Please swipe and hold your YubiKey NEO</string>
|
||||
<string name="yubichallenge_challenge_failed">Failed getting response, is the YubiKey and/or YubiChallenge configured correctly?</string>
|
||||
<string name="yubichallenge_lost_tag">YubiKey NEO lost during operation</string>
|
||||
<string name="yubichallenge_tag_error">Error communicating with YubiKey.</string>
|
||||
<string name="yubichallenge_nfc_off">NFC seems to be off, turn on?</string>
|
||||
<string name="yubichallenge_no_nfc">This device seems to not support NFC</string>
|
||||
<string name="yubichallenge_response_error">YubiKey Error</string>
|
||||
<string name="yubichallenge_bad_resp">The response from the YubiKey is incorrect</string>
|
||||
|
||||
|
||||
<string name="bad_resp">The challenge response is incorrect.</string>
|
||||
<string name="CouldntLoadChalAuxFile">Could not load auxiliary challenge file!</string>
|
||||
<string name="CouldntLoadChalAuxFile_Hint">Please use the KeeChallenge plugin in KeePass 2.x (PC) to configure your database for use with challenge-response!</string>
|
||||
@@ -986,7 +998,7 @@
|
||||
* Improved determination of lock-state in some situations\n
|
||||
* Database files are loaded to memory while you are typing your password for increased loading speed (see settings)\n
|
||||
* Entries can be added to root group\n
|
||||
* Bug fixes (resolving reference fields, problems with keyboard on Italian an Chinese devices)
|
||||
* Bug fixes (resolving reference fields, problems with keyboard on Italian and Chinese devices)
|
||||
</string>
|
||||
<string name="ChangeLog_0_8_4">
|
||||
<b>Version 0.8.4</b>\n
|
||||
@@ -1086,7 +1098,6 @@ Initial public release
|
||||
<item>Password + OTP secret (recovery mode)</item>
|
||||
<item>Password + Challenge-Response</item>
|
||||
<item>Password + Challenge-Response secret (recovery mode)</item>
|
||||
<item>Password + Challenge-Response for KeepassXC database</item>
|
||||
</string-array>
|
||||
<string-array name="AcceptAllServerCertificates_options">
|
||||
<item>Ignore certificate validation failures</item>
|
||||
|
||||
209
src/keepass2android/YubiChallengeActivity.cs
Normal file
209
src/keepass2android/YubiChallengeActivity.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Nfc;
|
||||
using Android.Nfc.Tech;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using Android.Runtime;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Java.IO;
|
||||
|
||||
namespace keepass2android
|
||||
{
|
||||
[Activity(Label = "@string/yubichallenge_title_activity_nfc")]
|
||||
[IntentFilter(new string[] { "android.nfc.action.NDEF_DISCOVERED" }, Categories = new string[]{Android.Content.Intent.CategoryDefault})]
|
||||
public class YubiChallengeActivity : Activity
|
||||
{
|
||||
private byte[] challenge;
|
||||
private int slot;
|
||||
|
||||
private const byte SLOT_CHAL_HMAC1 = 0x30;
|
||||
private const byte SLOT_CHAL_HMAC2 = 0x38;
|
||||
private const byte CHAL_BYTES = 0x40; // 64
|
||||
private const byte RESP_BYTES = 20;
|
||||
|
||||
private static byte[] selectCommand = { 0x00, (byte) 0xA4, 0x04,
|
||||
0x00, 0x07, (byte) 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00 };
|
||||
private static byte[] chalCommand = { 0x00, 0x01, SLOT_CHAL_HMAC2,
|
||||
0x00, CHAL_BYTES };
|
||||
|
||||
private AlertDialog swipeDialog;
|
||||
|
||||
private const int PERMISSIONS_REQUEST_NFC = 901234845;
|
||||
|
||||
protected override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
|
||||
|
||||
challenge = Intent.GetByteArrayExtra("challenge");
|
||||
slot = PreferenceManager.GetDefaultSharedPreferences(this).GetInt("pref_Slot", 2);
|
||||
if (challenge == null) return;
|
||||
else if (challenge.Length != CHAL_BYTES) return;
|
||||
else ChallengeYubiKey();
|
||||
}
|
||||
|
||||
protected override void OnNewIntent(Intent intent)
|
||||
{
|
||||
base.OnNewIntent(intent);
|
||||
|
||||
Tag tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
|
||||
SetResult(Result.Canceled, intent);
|
||||
if (tag != null)
|
||||
{
|
||||
IsoDep isoTag = IsoDep.Get(tag);
|
||||
try
|
||||
{
|
||||
isoTag.Connect();
|
||||
byte[] resp = isoTag.Transceive(selectCommand);
|
||||
int length = resp.Length;
|
||||
if (resp[length - 2] == (byte)0x90 && resp[length - 1] == 0x00)
|
||||
DoChallengeYubiKey(isoTag, slot, challenge);
|
||||
else
|
||||
{
|
||||
Toast.MakeText(this, Resource.String.yubichallenge_tag_error, ToastLength.Long)
|
||||
.Show();
|
||||
|
||||
}
|
||||
|
||||
isoTag.Close();
|
||||
}
|
||||
catch (TagLostException e)
|
||||
{
|
||||
Toast.MakeText(this, Resource.String.yubichallenge_lost_tag, ToastLength.Long)
|
||||
.Show();
|
||||
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Toast.MakeText(this, GetString(Resource.String.yubichallenge_tag_error) + e.Message,
|
||||
ToastLength.Long).Show();
|
||||
}
|
||||
}
|
||||
else SetResult(Result.Canceled, intent);
|
||||
Finish();
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
{
|
||||
base.OnPause();
|
||||
if (swipeDialog != null)
|
||||
{
|
||||
swipeDialog.Dismiss();
|
||||
swipeDialog = null;
|
||||
}
|
||||
DisableDispatch();
|
||||
}
|
||||
|
||||
private void DisableDispatch()
|
||||
{
|
||||
NfcAdapter adapter = NfcAdapter.GetDefaultAdapter(this);
|
||||
if (adapter != null)
|
||||
{
|
||||
adapter.DisableForegroundDispatch(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoChallengeYubiKey(IsoDep isoTag, int slot, byte[] challenge)
|
||||
{
|
||||
if (challenge == null || challenge.Length != CHAL_BYTES)
|
||||
return;
|
||||
|
||||
byte[] apdu = new byte[chalCommand.Length + CHAL_BYTES];
|
||||
chalCommand.CopyTo(apdu, 0);
|
||||
|
||||
if (slot == 1)
|
||||
apdu[2] = SLOT_CHAL_HMAC1;
|
||||
challenge.CopyTo(apdu, chalCommand.Length);
|
||||
|
||||
byte[] respApdu = isoTag.Transceive(apdu);
|
||||
if (respApdu.Length == 22 && respApdu[20] == (byte) 0x90
|
||||
&& respApdu[21] == 0x00)
|
||||
{
|
||||
// Get the secret
|
||||
byte[] resp = new byte[RESP_BYTES];
|
||||
Array.Copy(respApdu, 0, resp, 0, RESP_BYTES);
|
||||
Intent data = Intent;
|
||||
data.PutExtra("response", resp);
|
||||
SetResult(Result.Ok, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.MakeText(this, Resource.String.yubichallenge_challenge_failed, ToastLength.Long)
|
||||
.Show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void ChallengeYubiKey()
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.SetTitle(Resource.String.yubichallenge_challenging);
|
||||
builder.SetMessage(Resource.String.yubichallenge_swipe);
|
||||
builder.SetNegativeButton(Android.Resource.String.Cancel, (obj, args) => Finish());
|
||||
builder.SetCancelable(false);
|
||||
swipeDialog = builder.Show();
|
||||
|
||||
EnableDispatch();
|
||||
}
|
||||
|
||||
public override void OnBackPressed()
|
||||
{
|
||||
base.OnBackPressed();
|
||||
Finish();
|
||||
}
|
||||
|
||||
private void EnableDispatch()
|
||||
{
|
||||
Intent intent = Intent;
|
||||
intent.AddFlags(ActivityFlags.SingleTop);
|
||||
|
||||
PendingIntent tagIntent = PendingIntent.GetActivity(
|
||||
this, 0, intent, 0);
|
||||
|
||||
IntentFilter iso = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
|
||||
NfcAdapter adapter = NfcAdapter.GetDefaultAdapter(this);
|
||||
if (adapter == null)
|
||||
{
|
||||
Toast.MakeText(this, Resource.String.yubichallenge_no_nfc, ToastLength.Long).Show();
|
||||
return;
|
||||
}
|
||||
if (adapter.IsEnabled)
|
||||
{
|
||||
// register for foreground dispatch so we'll receive tags according to our intent filters
|
||||
adapter.EnableForegroundDispatch(
|
||||
this, tagIntent, new IntentFilter[] { iso },
|
||||
new String[][] { new String[] { Java.Lang.Class.FromType(typeof(IsoDep)).Name }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
|
||||
dialog.SetTitle(Resource.String.yubichallenge_nfc_off);
|
||||
dialog.SetPositiveButton(Android.Resource.String.Yes, (sender, args) =>
|
||||
{
|
||||
Intent settings = new Intent(Android.Provider.Settings.ActionNfcSettings);
|
||||
StartActivity(settings);
|
||||
((Dialog)sender).Dismiss();
|
||||
});
|
||||
dialog.SetNegativeButton(Android.Resource.String.No, (sender, args) =>
|
||||
{
|
||||
((Dialog)sender).Dismiss();
|
||||
});
|
||||
dialog.Show();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
SetResult(Result.Canceled);
|
||||
// Create your application here
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,6 +307,7 @@
|
||||
<Compile Include="AttachmentContentProvider.cs" />
|
||||
<Compile Include="app\AppTask.cs" />
|
||||
<Compile Include="views\TextWithHelp.cs" />
|
||||
<Compile Include="YubiChallengeActivity.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\xml\searchable.xml">
|
||||
|
||||
Reference in New Issue
Block a user