remove internal YubiChallenge activity in favor of ykdroid (allows to reduce required permissions)

This commit is contained in:
Philipp Crocoll
2018-07-16 13:07:29 +02:00
parent 848b6862be
commit a627dac4b7
8 changed files with 38 additions and 253 deletions

View File

@@ -33,17 +33,16 @@ namespace keepass2android
}
}
var chalIntent = Activity.GetYubichallengeIntent(challenge64);
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(challenge64, true);
if (chalIntent == null)
throw new Exception("YubiChallenge not installed.");
Activity.StartActivityForResult(chalIntent, _requestCode);
{
Error = Activity.GetString(Resource.String.NoChallengeApp);
}
else
{
Activity.StartActivityForResult(chalIntent, _requestCode);
}
});
while ((Response == null) && (Error == null))

View File

@@ -123,29 +123,37 @@ namespace keepass2android
}
public Intent GetYubichallengeIntent(byte[] challenge)
public Intent TryGetYubichallengeIntentOrPrompt(byte[] challenge, bool promptToInstall)
{
Intent chalIntent = new Intent("net.pp3345.ykdroid.intent.action.CHALLENGE_RESPONSE");
chalIntent.PutExtra("challenge", challenge);
IList<ResolveInfo> activities = PackageManager.QueryIntentActivities(chalIntent, 0);
bool isIntentSafe = activities.Count > 0;
if (isIntentSafe)
{
Intent chalIntent = new Intent("net.pp3345.ykdroid.intent.action.CHALLENGE_RESPONSE");
chalIntent.PutExtra("challenge", challenge);
IList<ResolveInfo> activities = PackageManager.QueryIntentActivities(chalIntent, 0);
bool isIntentSafe = activities.Count > 0;
if (isIntentSafe)
{
return chalIntent;
}
}
{
Intent chalIntent = new Intent(this, typeof(YubiChallengeActivity));
chalIntent.PutExtra("challenge", challenge);
return chalIntent;
}
if (promptToInstall)
{
AlertDialog.Builder b = new AlertDialog.Builder(this);
string message = GetString(Resource.String.NoChallengeApp) + " " + GetString(Resource.String.PleaseInstallApp, new Java.Lang.Object[]{"ykDroid"});
Intent yubichalIntent = new Intent("com.yubichallenge.NFCActivity.CHALLENGE");
IList<ResolveInfo> yubichallengeactivities = PackageManager.QueryIntentActivities(yubichalIntent, 0);
bool hasYubichallenge = yubichallengeactivities.Count > 0;
if (hasYubichallenge)
message += " " + GetString(Resource.String.AppOutdated, new Java.Lang.Object[] {"YubiChallenge"});
b.SetMessage(message);
b.SetPositiveButton(Android.Resource.String.Ok,
delegate { Util.GotoUrl(this, GetString(Resource.String.MarketURL) + "net.pp3345.ykdroid"); });
b.SetNegativeButton(Resource.String.cancel, delegate { });
b.Create().Show();
}
return null;
}
}
}
}

View File

@@ -625,7 +625,7 @@ namespace keepass2android
protected override void HandleSuccess()
{
var chalIntent = Activity.GetYubichallengeIntent(Activity._chalInfo.Challenge);
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(Activity._chalInfo.Challenge, true);
if (chalIntent != null)
{

View File

@@ -118,7 +118,6 @@
<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" />

View File

@@ -142,7 +142,6 @@
<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.READ_EXTERNAL_STORAGE" />

View File

@@ -566,18 +566,9 @@
<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="NoChallengeApp">Could not find an app that can handle the challenge.</string>
<string name="PleaseInstallApp">Please install %1$s from Google Play.</string>
<string name="AppOutdated">%1$s is no longer supported.</string>
<string name="bad_resp">The challenge response is incorrect.</string>
<string name="CouldntLoadChalAuxFile">Could not load auxiliary challenge file!</string>

View File

@@ -1,210 +0,0 @@
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();
isoTag.Timeout = 30000;
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
}
}
}

View File

@@ -309,7 +309,6 @@
<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">