From 92a0ce98bbd4eba8f6582e03f3211e084f6eb3f2 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Mon, 11 Mar 2019 11:46:02 +0100 Subject: [PATCH] make nfc implementation compatible to Yubikey NEO 5 (closes https://github.com/PhilippC/keepass2android/issues/564) --- src/keepass2android/NfcOtpActivity.cs | 63 ++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/src/keepass2android/NfcOtpActivity.cs b/src/keepass2android/NfcOtpActivity.cs index 6e374cb3..b5781eae 100644 --- a/src/keepass2android/NfcOtpActivity.cs +++ b/src/keepass2android/NfcOtpActivity.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Android.App; using Android.Content; using Android.Content.PM; @@ -8,6 +9,7 @@ using Android.Widget; using Java.Util; using Java.Util.Regex; using Keepass2android.Yubiclip.Scancode; +using Pattern = Java.Util.Regex.Pattern; namespace keepass2android { @@ -34,8 +36,42 @@ namespace keepass2android { private String GetOtpFromIntent(Intent intent) { - String data = intent.DataString; - Matcher matcher = OtpPattern.Matcher(data); + var patterns = new List{OTP_PATTERN, OTP_PATTERN2}; + foreach (var pattern in patterns) + { + + Matcher matcher = pattern.Matcher(intent.DataString); + if (matcher.Matches()) + { + String otp = matcher.Group(1); + return otp; + } + else + { + IParcelable[] raw = intent.GetParcelableArrayExtra(NfcAdapter.ExtraNdefMessages); + byte[] bytes = ((NdefMessage)raw[0]).ToByteArray(); + if (bytes[0] == URL_NDEF_RECORD && Arrays.Equals(URL_PREFIX_BYTES, Arrays.CopyOfRange(bytes, 3, 3 + URL_PREFIX_BYTES.Length))) + { + if (Arrays.Equals(new Java.Lang.String("/neo/").GetBytes(), Arrays.CopyOfRange(bytes, 18, 18 + 5))) + { + bytes[22] = (byte)'#'; + } + for (int i = 0; i < bytes.Length; i++) + { + if (bytes[i] == '#') + { + bytes = Arrays.CopyOfRange(bytes, i + 1, bytes.Length); + String layout = "US"; + KeyboardLayout kbd = KeyboardLayout.ForName(layout); + String otp = kbd.FromScanCodes(bytes); + return otp; + } + } + } + } + } + /* + Matcher matcher = OtpPattern.Matcher(data); if (matcher.Matches()) { String otp = matcher.Group(1); @@ -51,16 +87,29 @@ namespace keepass2android KeyboardLayout kbd = KeyboardLayout.ForName(layout); String otp = kbd.FromScanCodes(bytes); return otp; - } + }*/ return null; } - //private static readonly Java.Util.Regex.Pattern OtpPattern = Java.Util.Regex.Pattern.Compile("^https://my\\.yubico\\.com/neo/(.+)$"); - private static readonly Java.Util.Regex.Pattern OtpPattern = Java.Util.Regex.Pattern.Compile("^https://my\\.yubico\\.com/neo/([a-zA-Z0-9!]+)$"); - private const int DATA_OFFSET = 23; + private static String URL_PREFIX = "https://my.yubico.com/"; + private static byte URL_NDEF_RECORD = (byte)0xd1; + private static byte[] URL_PREFIX_BYTES = new byte[URL_PREFIX.Length + 2 - 8]; - private ActivityDesign _design; + private static Pattern OTP_PATTERN = Pattern.Compile("^https://my\\.yubico\\.com/[a-z]+/#?([a-zA-Z0-9!]+)$"); + private static Pattern OTP_PATTERN2 = Pattern.Compile("^https://keepass2android\\.crocoll\\.net/[a-z]+/#?([a-zA-Z0-9!]+)$"); + + static NfcOtpActivity() + { + URL_PREFIX_BYTES[0] = 85; + URL_PREFIX_BYTES[1] = 4; + Java.Lang.JavaSystem.Arraycopy(new Java.Lang.String(URL_PREFIX.Substring(8)).GetBytes(), 0, URL_PREFIX_BYTES, 2, URL_PREFIX_BYTES.Length - 2); + } + + + + + private ActivityDesign _design; public NfcOtpActivity() {