diff --git a/src/keepass2android/ChallengeXCKey.cs b/src/keepass2android/ChallengeXCKey.cs index 3e342a75..72a469ea 100644 --- a/src/keepass2android/ChallengeXCKey.cs +++ b/src/keepass2android/ChallengeXCKey.cs @@ -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)) diff --git a/src/keepass2android/LockingActivity.cs b/src/keepass2android/LockingActivity.cs index 8103c795..4c2eb773 100644 --- a/src/keepass2android/LockingActivity.cs +++ b/src/keepass2android/LockingActivity.cs @@ -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 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 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 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; } - } + } } diff --git a/src/keepass2android/PasswordActivity.cs b/src/keepass2android/PasswordActivity.cs index f188fd74..1f5b3313 100644 --- a/src/keepass2android/PasswordActivity.cs +++ b/src/keepass2android/PasswordActivity.cs @@ -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) { diff --git a/src/keepass2android/Properties/AndroidManifest_debug.xml b/src/keepass2android/Properties/AndroidManifest_debug.xml index 79ad3ef7..827a3602 100644 --- a/src/keepass2android/Properties/AndroidManifest_debug.xml +++ b/src/keepass2android/Properties/AndroidManifest_debug.xml @@ -118,7 +118,6 @@ - diff --git a/src/keepass2android/Properties/AndroidManifest_net.xml b/src/keepass2android/Properties/AndroidManifest_net.xml index 83c71c54..aeb9d4b0 100644 --- a/src/keepass2android/Properties/AndroidManifest_net.xml +++ b/src/keepass2android/Properties/AndroidManifest_net.xml @@ -142,7 +142,6 @@ - diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index 0f78bf06..74e437a2 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -566,18 +566,9 @@ Error updating OTP auxiliary file! Saving auxiliary OTP file… - NFC Challenge-Response - Challenging - Please swipe your YubiKey NEO - Please swipe and hold your YubiKey NEO - Failed getting response, is the YubiKey and/or YubiChallenge configured correctly? - YubiKey NEO lost during operation - Error communicating with YubiKey. - NFC seems to be off, turn on? - This device seems to not support NFC - YubiKey Error - The response from the YubiKey is incorrect - + Could not find an app that can handle the challenge. + Please install %1$s from Google Play. + %1$s is no longer supported. The challenge response is incorrect. Could not load auxiliary challenge file! diff --git a/src/keepass2android/YubiChallengeActivity.cs b/src/keepass2android/YubiChallengeActivity.cs deleted file mode 100644 index cc0ebd1b..00000000 --- a/src/keepass2android/YubiChallengeActivity.cs +++ /dev/null @@ -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 - } - } -} \ No newline at end of file diff --git a/src/keepass2android/keepass2android.csproj b/src/keepass2android/keepass2android.csproj index 260deb5c..682428e0 100644 --- a/src/keepass2android/keepass2android.csproj +++ b/src/keepass2android/keepass2android.csproj @@ -309,7 +309,6 @@ -