first working - but still incomplete - implementation for OTP/Yubikey

This commit is contained in:
Philipp Crocoll 2013-11-17 17:01:53 +01:00
parent c686cbeeb3
commit 66cd05b9f4
10 changed files with 446 additions and 229 deletions

2
.gitignore vendored
View File

@ -166,3 +166,5 @@ Thumbs.db
/src/AppCompatV7Binding/obj/Release
/src/java/workspace/DriveTest
/src/Components

View File

@ -0,0 +1,63 @@
using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.OS;
using Java.Util.Regex;
namespace keepass2android
{
[Activity(Label = "@string/app_name",
ConfigurationChanges = ConfigChanges.Orientation |
ConfigChanges.KeyboardHidden,
NoHistory = true,
ExcludeFromRecents = true,
Theme = "@android:style/Theme.Dialog")]
[IntentFilter(new[] { "android.nfc.action.NDEF_DISCOVERED" },
Label = "@string/app_name",
Categories = new[] { Intent.CategoryDefault },
DataHost = "my.yubico.com",
DataPathPrefix = "/neo",
DataScheme = "https")]
public class NfcOtpActivity : Activity
{
private String GetOtpFromIntent(Intent intent)
{
String data = intent.DataString;
Matcher matcher = OtpPattern.Matcher(data);
if (matcher.Matches())
{
String otp = matcher.Group(1);
return otp;
}
return null;
}
private static readonly Java.Util.Regex.Pattern OtpPattern = Java.Util.Regex.Pattern.Compile("^https://my\\.yubico\\.com/neo/(.+)$");
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
Intent i = new Intent(this, typeof (PasswordActivity));
i.SetAction(Intents.StartWithOtp);
//things to consider:
// PasswordActivity should be resumed if currently active -> this is why single top is used and why PasswordActivity is started
// If PasswordActivity is not open already, it may be the wrong place to send our OTP to because maybe the user first needs to select
// a file (which might require UI action like entering credentials, all of which is handled in FileSelectActivity)
// FileSelectActivity is not on the back stack, it finishes itself.
// -> PasswordActivity needs to handle this and return to FSA.
i.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
i.PutExtra(Intents.OtpExtraKey, GetOtpFromIntent(Intent));
StartActivity(i);
Finish();
}
}
}

View File

@ -25,7 +25,6 @@ using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Lang;
using Java.Net;
using Android.Preferences;
using Java.IO;
@ -33,7 +32,6 @@ using Android.Text;
using Android.Content.PM;
using KeePassLib.Keys;
using KeePassLib.Serialization;
using KeePassLib.Utility;
using OtpKeyProv;
using keepass2android.Io;
using keepass2android.Utils;
@ -47,6 +45,7 @@ namespace keepass2android
{
[Activity (Label = "@string/app_name",
ConfigurationChanges=ConfigChanges.Orientation|ConfigChanges.KeyboardHidden,
LaunchMode = LaunchMode.SingleInstance,
Theme="@style/Base")]
public class PasswordActivity : LockingActivity {
@ -80,6 +79,9 @@ namespace keepass2android
internal AppTask AppTask;
private bool _killOnDestroy;
private string _password = "";
//OTPs which should be entered into the OTP fields as soon as these become visible
private readonly List<String> _pendingOtps = new List<string>();
private const int RequestCodePrepareDbFile = 1000;
private const int RequestCodePrepareOtpAuxFile = 1001;
@ -139,8 +141,10 @@ namespace keepass2android
Intent i = new Intent(act, typeof(PasswordActivity));
i.SetFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
i.PutExtra(KeyFilename, fileName);
appTask.ToIntent(i);
act.StartActivityForResult(i, 0);
}
@ -155,7 +159,9 @@ namespace keepass2android
}
Intent i = new Intent(act, typeof(PasswordActivity));
PutIoConnectionToIntent(ioc, i);
i.SetFlags(ActivityFlags.ClearTask);
appTask.ToIntent(i);
@ -259,29 +265,39 @@ namespace keepass2android
Toast.MakeText(this, GetString(Resource.String.CouldntLoadOtpAuxFile), ToastLength.Long).Show();
return;
}
FindViewById(Resource.Id.init_otp).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.otpInitView).Visibility = ViewStates.Gone;
FindViewById(Resource.Id.otpEntry).Visibility = ViewStates.Visible;
int c = 0;
foreach (int otpId in _otpTextViewIds)
{
c++;
var otpTextView = FindViewById<EditText>(otpId);
otpTextView.Text = "";
otpTextView.Hint = GetString(Resource.String.otp_hint, new Object[] {c});
otpTextView.SetFilters(new IInputFilter[] {new InputFilterLengthFilter((int)_otpInfo.OtpLength) });
if (c > _otpInfo.OtpsRequired)
foreach (int otpId in _otpTextViewIds)
{
otpTextView.Visibility = ViewStates.Gone;
}
else
{
otpTextView.TextChanged += (sender, args) =>
c++;
var otpTextView = FindViewById<EditText>(otpId);
if (c <= _pendingOtps.Count)
{
UpdateOkButtonState();
};
otpTextView.Text = _pendingOtps[c-1];
}
else
{
otpTextView.Text = "";
}
otpTextView.Hint = GetString(Resource.String.otp_hint, new Object[] {c});
otpTextView.SetFilters(new IInputFilter[] {new InputFilterLengthFilter((int)_otpInfo.OtpLength) });
if (c > _otpInfo.OtpsRequired)
{
otpTextView.Visibility = ViewStates.Gone;
}
else
{
otpTextView.TextChanged += (sender, args) =>
{
UpdateOkButtonState();
};
}
}
_pendingOtps.Clear();
}
}
).Execute();
}
@ -290,6 +306,8 @@ namespace keepass2android
base.OnCreate(savedInstanceState);
if (savedInstanceState != null)
_showPassword = savedInstanceState.GetBoolean(ShowpasswordKey, false);
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
Intent i = Intent;
String action = i.Action;
@ -302,6 +320,7 @@ namespace keepass2android
if (action != null && action.Equals(ViewIntent))
{
//started from "view" intent (e.g. from file browser)
_ioConnection.Path = i.DataString;
if (! _ioConnection.Path.Substring(0, 7).Equals("file://"))
@ -333,7 +352,54 @@ namespace keepass2android
_keyFileOrProvider = GetKeyFile(_ioConnection.Path);
} else
}
else if ((action != null) && (action.Equals(Intents.StartWithOtp)))
{
//create called after detecting an OTP via NFC
//this means the Activity was not on the back stack before, i.e. no database has been selected
_ioConnection = null;
//see if we can get a database from recent:
if (App.Kp2a.FileDbHelper.HasRecentFiles())
{
ICursor filesCursor = App.Kp2a.FileDbHelper.FetchAllFiles();
StartManagingCursor(filesCursor);
filesCursor.MoveToFirst();
IOConnectionInfo ioc = App.Kp2a.FileDbHelper.CursorToIoc(filesCursor);
if (App.Kp2a.GetFileStorage(ioc).RequiresSetup(ioc) == false)
{
IFileStorage fileStorage = App.Kp2a.GetFileStorage(ioc);
if (!fileStorage.RequiresCredentials(ioc))
{
//ok, we can use this file
_ioConnection = ioc;
}
}
}
if (_ioConnection == null)
{
//We need to go to FileSelectActivity first.
//For security reasons: discard the OTP (otherwise the user might not select a database now and forget
//about the OTP, but it would still be stored in the Intents and later be passed to PasswordActivity again.
Toast.MakeText(this, GetString(Resource.String.otp_discarded_because_no_db), ToastLength.Long).Show();
GoToFileSelectActivity();
Finish();
return;
}
//user obviously wants to use OTP:
_keyFileOrProvider = KeyProviderIdOtp;
//remember the OTP for later use
_pendingOtps.Add(Intent.GetStringExtra(Intents.OtpExtraKey));
Intent.RemoveExtra(Intents.OtpExtraKey);
}
else
{
SetIoConnectionFromIntent(_ioConnection, i);
_keyFileOrProvider = i.GetStringExtra(KeyKeyfile);
@ -350,7 +416,7 @@ namespace keepass2android
App.Kp2a.LockDatabase(false);
}
AppTask = AppTask.GetTaskInOnCreate(savedInstanceState, Intent);
SetContentView(Resource.Layout.password);
PopulateView();
@ -509,6 +575,10 @@ namespace keepass2android
FindViewById(Resource.Id.otpView).Visibility = KeyProviderType == KeyProviders.Otp
? ViewStates.Visible
: ViewStates.Gone;
if (KeyProviderType == KeyProviders.Otp)
{
FindViewById(Resource.Id.otps_pending).Visibility = _pendingOtps.Count > 0 ? ViewStates.Visible : ViewStates.Gone;
}
UpdateOkButtonState();
}
@ -715,6 +785,61 @@ namespace keepass2android
base.OnSaveInstanceState(outState);
AppTask.ToBundle(outState);
outState.PutBoolean(ShowpasswordKey, _showPassword);
//TODO:
// * save OTP state
//more OTP TODO:
// * NfcOtp: Ask for close when db open
// * Caching of aux file
// * -> implement IFileStorage in JavaFileStorage based on ListFiles
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
//this method is called from the NfcOtpActivity's startActivity() if the activity is already running
//note: it's not called in other cases because OnNewIntent requires the activity to be on top already
//which is never the case when started from another activity (in the same task).
//NfcOtpActivity sets the ClearTop flag to get OnNewIntent called.
if ((intent != null) && (intent.HasExtra(Intents.OtpExtraKey)))
{
string otp = intent.GetStringExtra(Intents.OtpExtraKey);
if (_otpInfo == null)
{
//Entering OTPs not yet initialized:
_pendingOtps.Add(otp);
UpdateKeyProviderUiState();
}
else
{
//Entering OTPs is initialized. Write OTP into first empty field:
bool foundEmptyField = false;
foreach (int otpId in _otpTextViewIds)
{
EditText otpEdit = FindViewById<EditText>(otpId);
if ((otpEdit.Visibility == ViewStates.Visible) && String.IsNullOrEmpty(otpEdit.Text))
{
otpEdit.Text = otp;
foundEmptyField = true;
break;
}
}
//did we find a field?
if (!foundEmptyField)
{
Toast.MakeText(this, GetString(Resource.String.otp_discarded_no_space), ToastLength.Long).Show();
}
}
Spinner passwordModeSpinner = FindViewById<Spinner>(Resource.Id.password_mode_spinner);
if (passwordModeSpinner.SelectedItemPosition != (int) KeyProviders.Otp)
{
passwordModeSpinner.SetSelection((int)KeyProviders.Otp);
}
}
}
protected override void OnResume()

View File

@ -738,17 +738,17 @@ namespace keepass2android
// aapt resource value: 0x7f07008c
public const int IconGridView = 2131165324;
// aapt resource value: 0x7f0700a8
public const int QuickUnlock_button = 2131165352;
// aapt resource value: 0x7f0700a9
public const int QuickUnlock_buttonLock = 2131165353;
// aapt resource value: 0x7f0700a6
public const int QuickUnlock_button = 2131165350;
public const int QuickUnlock_label = 2131165350;
// aapt resource value: 0x7f0700a7
public const int QuickUnlock_buttonLock = 2131165351;
// aapt resource value: 0x7f0700a4
public const int QuickUnlock_label = 2131165348;
// aapt resource value: 0x7f0700a5
public const int QuickUnlock_password = 2131165349;
public const int QuickUnlock_password = 2131165351;
// aapt resource value: 0x7f07006d
public const int RelativeLayout = 2131165293;
@ -771,8 +771,8 @@ namespace keepass2android
// aapt resource value: 0x7f07007f
public const int add_group = 2131165311;
// aapt resource value: 0x7f0700ba
public const int add_url_entry = 2131165370;
// aapt resource value: 0x7f0700bc
public const int add_url_entry = 2131165372;
// aapt resource value: 0x7f07003c
public const int advanced_container = 2131165244;
@ -822,38 +822,38 @@ namespace keepass2android
// aapt resource value: 0x7f070082
public const int cancel_insert_element = 2131165314;
// aapt resource value: 0x7f0700b7
public const int cbCaseSensitive = 2131165367;
// aapt resource value: 0x7f0700b9
public const int cbCaseSensitive = 2131165369;
// aapt resource value: 0x7f0700b8
public const int cbExcludeExpiredEntries = 2131165368;
// aapt resource value: 0x7f0700ad
public const int cbRegEx = 2131165357;
// aapt resource value: 0x7f0700b6
public const int cbSearchInGroupName = 2131165366;
// aapt resource value: 0x7f0700b3
public const int cbSearchInNotes = 2131165363;
// aapt resource value: 0x7f0700b4
public const int cbSearchInOtherStrings = 2131165364;
// aapt resource value: 0x7f0700b2
public const int cbSearchInPassword = 2131165362;
// aapt resource value: 0x7f0700b5
public const int cbSearchInTags = 2131165365;
// aapt resource value: 0x7f0700ba
public const int cbExcludeExpiredEntries = 2131165370;
// aapt resource value: 0x7f0700af
public const int cbSearchInTitle = 2131165359;
public const int cbRegEx = 2131165359;
// aapt resource value: 0x7f0700b0
public const int cbSearchInUrl = 2131165360;
// aapt resource value: 0x7f0700b8
public const int cbSearchInGroupName = 2131165368;
// aapt resource value: 0x7f0700b5
public const int cbSearchInNotes = 2131165365;
// aapt resource value: 0x7f0700b6
public const int cbSearchInOtherStrings = 2131165366;
// aapt resource value: 0x7f0700b4
public const int cbSearchInPassword = 2131165364;
// aapt resource value: 0x7f0700b7
public const int cbSearchInTags = 2131165367;
// aapt resource value: 0x7f0700b1
public const int cbSearchInUsername = 2131165361;
public const int cbSearchInTitle = 2131165361;
// aapt resource value: 0x7f0700b2
public const int cbSearchInUrl = 2131165362;
// aapt resource value: 0x7f0700b3
public const int cbSearchInUsername = 2131165363;
// aapt resource value: 0x7f07007d
public const int cb_brackets = 2131165309;
@ -885,14 +885,14 @@ namespace keepass2android
// aapt resource value: 0x7f070062
public const int create = 2131165282;
// aapt resource value: 0x7f0700c2
public const int cred_password = 2131165378;
// aapt resource value: 0x7f0700c4
public const int cred_password = 2131165380;
// aapt resource value: 0x7f0700c5
public const int cred_remember_mode = 2131165381;
// aapt resource value: 0x7f0700c3
public const int cred_remember_mode = 2131165379;
// aapt resource value: 0x7f0700c1
public const int cred_username = 2131165377;
public const int cred_username = 2131165379;
// aapt resource value: 0x7f07002c
public const int delete_extra = 2131165228;
@ -1095,8 +1095,8 @@ namespace keepass2android
// aapt resource value: 0x7f070088
public const int group_text = 2131165320;
// aapt resource value: 0x7f0700bf
public const int help = 2131165375;
// aapt resource value: 0x7f0700c1
public const int help = 2131165377;
// aapt resource value: 0x7f070004
public const int hybrid = 2131165188;
@ -1119,8 +1119,8 @@ namespace keepass2android
// aapt resource value: 0x7f070026
public const int imgoktfest = 2131165222;
// aapt resource value: 0x7f07009a
public const int init_otp = 2131165338;
// aapt resource value: 0x7f07009b
public const int init_otp = 2131165339;
// aapt resource value: 0x7f070081
public const int insert_element = 2131165313;
@ -1158,62 +1158,62 @@ namespace keepass2android
// aapt resource value: 0x7f070070
public const int length_label = 2131165296;
// aapt resource value: 0x7f0700ac
public const int linearLayout1 = 2131165356;
// aapt resource value: 0x7f0700cd
public const int menu_about = 2131165389;
// aapt resource value: 0x7f0700cc
public const int menu_app_settings = 2131165388;
// aapt resource value: 0x7f0700cb
public const int menu_cancel_edit = 2131165387;
// aapt resource value: 0x7f0700d3
public const int menu_change_db = 2131165395;
// aapt resource value: 0x7f0700ae
public const int linearLayout1 = 2131165358;
// aapt resource value: 0x7f0700cf
public const int menu_change_master_key = 2131165391;
// aapt resource value: 0x7f0700c4
public const int menu_donate = 2131165380;
// aapt resource value: 0x7f0700c6
public const int menu_goto_url = 2131165382;
// aapt resource value: 0x7f0700c7
public const int menu_lock = 2131165383;
// aapt resource value: 0x7f0700c9
public const int menu_rate = 2131165385;
public const int menu_about = 2131165391;
// aapt resource value: 0x7f0700ce
public const int menu_search = 2131165390;
public const int menu_app_settings = 2131165390;
// aapt resource value: 0x7f0700d2
public const int menu_search_advanced = 2131165394;
// aapt resource value: 0x7f0700cd
public const int menu_cancel_edit = 2131165389;
// aapt resource value: 0x7f0700d5
public const int menu_change_db = 2131165397;
// aapt resource value: 0x7f0700d1
public const int menu_sort = 2131165393;
public const int menu_change_master_key = 2131165393;
// aapt resource value: 0x7f0700c6
public const int menu_donate = 2131165382;
// aapt resource value: 0x7f0700c8
public const int menu_suggest_improvements = 2131165384;
public const int menu_goto_url = 2131165384;
// aapt resource value: 0x7f0700c9
public const int menu_lock = 2131165385;
// aapt resource value: 0x7f0700cb
public const int menu_rate = 2131165387;
// aapt resource value: 0x7f0700d0
public const int menu_sync = 2131165392;
public const int menu_search = 2131165392;
// aapt resource value: 0x7f0700c5
public const int menu_toggle_pass = 2131165381;
// aapt resource value: 0x7f0700d4
public const int menu_search_advanced = 2131165396;
// aapt resource value: 0x7f0700d3
public const int menu_sort = 2131165395;
// aapt resource value: 0x7f0700ca
public const int menu_translate = 2131165386;
public const int menu_suggest_improvements = 2131165386;
// aapt resource value: 0x7f0700d2
public const int menu_sync = 2131165394;
// aapt resource value: 0x7f0700c7
public const int menu_toggle_pass = 2131165383;
// aapt resource value: 0x7f0700cc
public const int menu_translate = 2131165388;
// aapt resource value: 0x7f070028
public const int no_donate = 2131165224;
// aapt resource value: 0x7f0700bb
public const int no_results = 2131165371;
// aapt resource value: 0x7f0700bd
public const int no_results = 2131165373;
// aapt resource value: 0x7f070000
public const int none = 2131165184;
@ -1230,35 +1230,41 @@ namespace keepass2android
// aapt resource value: 0x7f070061
public const int open = 2131165281;
// aapt resource value: 0x7f07009d
public const int otp1 = 2131165341;
// aapt resource value: 0x7f07009e
public const int otp2 = 2131165342;
// aapt resource value: 0x7f07009f
public const int otp3 = 2131165343;
public const int otp1 = 2131165343;
// aapt resource value: 0x7f0700a0
public const int otp4 = 2131165344;
public const int otp2 = 2131165344;
// aapt resource value: 0x7f0700a1
public const int otp5 = 2131165345;
public const int otp3 = 2131165345;
// aapt resource value: 0x7f0700a2
public const int otp6 = 2131165346;
public const int otp4 = 2131165346;
// aapt resource value: 0x7f07009b
public const int otpEntry = 2131165339;
// aapt resource value: 0x7f0700a3
public const int otp5 = 2131165347;
// aapt resource value: 0x7f0700a4
public const int otp6 = 2131165348;
// aapt resource value: 0x7f07009d
public const int otpEntry = 2131165341;
// aapt resource value: 0x7f07009a
public const int otpInitView = 2131165338;
// aapt resource value: 0x7f070099
public const int otpView = 2131165337;
// aapt resource value: 0x7f07009c
public const int otp_expl = 2131165340;
// aapt resource value: 0x7f07009e
public const int otp_expl = 2131165342;
// aapt resource value: 0x7f0700bd
public const int pass_conf_password = 2131165373;
// aapt resource value: 0x7f07009c
public const int otps_pending = 2131165340;
// aapt resource value: 0x7f0700bf
public const int pass_conf_password = 2131165375;
// aapt resource value: 0x7f070092
public const int pass_keyfile = 2131165330;
@ -1266,8 +1272,8 @@ namespace keepass2android
// aapt resource value: 0x7f070093
public const int pass_ok = 2131165331;
// aapt resource value: 0x7f0700bc
public const int pass_password = 2131165372;
// aapt resource value: 0x7f0700be
public const int pass_password = 2131165374;
// aapt resource value: 0x7f07006e
public const int password = 2131165294;
@ -1290,8 +1296,8 @@ namespace keepass2android
// aapt resource value: 0x7f07002b
public const int protection = 2131165227;
// aapt resource value: 0x7f0700a3
public const int qu_filename = 2131165347;
// aapt resource value: 0x7f0700a5
public const int qu_filename = 2131165349;
// aapt resource value: 0x7f070023
public const int rounds = 2131165219;
@ -1302,29 +1308,29 @@ namespace keepass2android
// aapt resource value: 0x7f070002
public const int satellite = 2131165186;
// aapt resource value: 0x7f0700ad
public const int scrollView1 = 2131165357;
// aapt resource value: 0x7f0700ac
public const int searchEditText = 2131165356;
// aapt resource value: 0x7f0700ab
public const int scrollView1 = 2131165355;
public const int search_button = 2131165355;
// aapt resource value: 0x7f0700b0
public const int search_in_label = 2131165360;
// aapt resource value: 0x7f0700aa
public const int searchEditText = 2131165354;
public const int search_label = 2131165354;
// aapt resource value: 0x7f0700a9
public const int search_button = 2131165353;
// aapt resource value: 0x7f0700ae
public const int search_in_label = 2131165358;
// aapt resource value: 0x7f0700a8
public const int search_label = 2131165352;
// aapt resource value: 0x7f0700b9
public const int select_other_entry = 2131165369;
// aapt resource value: 0x7f0700bb
public const int select_other_entry = 2131165371;
// aapt resource value: 0x7f07005c
public const int start_create = 2131165276;
// aapt resource value: 0x7f0700be
public const int start_create_import = 2131165374;
// aapt resource value: 0x7f0700c0
public const int start_create_import = 2131165376;
// aapt resource value: 0x7f07005a
public const int start_open_file = 2131165274;
@ -1335,8 +1341,8 @@ namespace keepass2android
// aapt resource value: 0x7f070003
public const int terrain = 2131165187;
// aapt resource value: 0x7f0700c0
public const int text = 2131165376;
// aapt resource value: 0x7f0700c2
public const int text = 2131165378;
// aapt resource value: 0x7f070069
public const int textView = 2131165289;
@ -1608,47 +1614,47 @@ namespace keepass2android
// aapt resource value: 0x7f080170
public const int CannotMoveGroupHere = 2131231088;
// aapt resource value: 0x7f0801a1
public const int ChangeLog = 2131231137;
// aapt resource value: 0x7f0801a0
public const int ChangeLog_0_7 = 2131231136;
// aapt resource value: 0x7f08019e
public const int ChangeLog = 2131231134;
public const int ChangeLog_0_8 = 2131231134;
// aapt resource value: 0x7f08019d
public const int ChangeLog_0_7 = 2131231133;
// aapt resource value: 0x7f08019b
public const int ChangeLog_0_8 = 2131231131;
// aapt resource value: 0x7f08019a
public const int ChangeLog_0_8_1 = 2131231130;
// aapt resource value: 0x7f080199
public const int ChangeLog_0_8_2 = 2131231129;
// aapt resource value: 0x7f080198
public const int ChangeLog_0_8_3 = 2131231128;
// aapt resource value: 0x7f080197
public const int ChangeLog_0_8_4 = 2131231127;
// aapt resource value: 0x7f080196
public const int ChangeLog_0_8_5 = 2131231126;
// aapt resource value: 0x7f080195
public const int ChangeLog_0_8_6 = 2131231125;
// aapt resource value: 0x7f080194
public const int ChangeLog_0_9 = 2131231124;
// aapt resource value: 0x7f080193
public const int ChangeLog_0_9_1 = 2131231123;
// aapt resource value: 0x7f080192
public const int ChangeLog_0_9_2 = 2131231122;
public const int ChangeLog_0_8_1 = 2131231133;
// aapt resource value: 0x7f08019c
public const int ChangeLog_keptDonate = 2131231132;
public const int ChangeLog_0_8_2 = 2131231132;
// aapt resource value: 0x7f080191
public const int ChangeLog_title = 2131231121;
// aapt resource value: 0x7f08019b
public const int ChangeLog_0_8_3 = 2131231131;
// aapt resource value: 0x7f08019a
public const int ChangeLog_0_8_4 = 2131231130;
// aapt resource value: 0x7f080199
public const int ChangeLog_0_8_5 = 2131231129;
// aapt resource value: 0x7f080198
public const int ChangeLog_0_8_6 = 2131231128;
// aapt resource value: 0x7f080197
public const int ChangeLog_0_9 = 2131231127;
// aapt resource value: 0x7f080196
public const int ChangeLog_0_9_1 = 2131231126;
// aapt resource value: 0x7f080195
public const int ChangeLog_0_9_2 = 2131231125;
// aapt resource value: 0x7f08019f
public const int ChangeLog_keptDonate = 2131231135;
// aapt resource value: 0x7f080194
public const int ChangeLog_title = 2131231124;
// aapt resource value: 0x7f080040
public const int CheckForFileChangesOnSave_key = 2131230784;
@ -2484,8 +2490,8 @@ namespace keepass2android
// aapt resource value: 0x7f0800b2
public const int list_size_title = 2131230898;
// aapt resource value: 0x7f080190
public const int loading = 2131231120;
// aapt resource value: 0x7f080193
public const int loading = 2131231123;
// aapt resource value: 0x7f0800b4
public const int loading_database = 2131230900;
@ -2607,12 +2613,21 @@ namespace keepass2android
// aapt resource value: 0x7f0800d3
public const int open_recent = 2131230931;
// aapt resource value: 0x7f080190
public const int otp_discarded_because_no_db = 2131231120;
// aapt resource value: 0x7f080191
public const int otp_discarded_no_space = 2131231121;
// aapt resource value: 0x7f08018d
public const int otp_explanation = 2131231117;
// aapt resource value: 0x7f08018e
public const int otp_hint = 2131231118;
// aapt resource value: 0x7f080192
public const int otps_pending = 2131231122;
// aapt resource value: 0x7f0800d6
public const int pass_filename = 2131230934;

View File

@ -104,11 +104,22 @@
android:layout_height="wrap_content"
android:orientation="vertical"
>
<Button
android:id="@+id/init_otp"
android:text="@string/init_otp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/otpInitView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:id="@+id/init_otp"
android:text="@string/init_otp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/otps_pending"
android:text="@string/otps_pending"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/otpEntry"
android:layout_width="fill_parent"

View File

@ -347,6 +347,9 @@
<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="CouldntLoadOtpAuxFile">Could not load auxiliary OTP file!</string>
<string name="otp_discarded_because_no_db">Please select database first. OTP is discarded for security reasons.</string>
<string name="otp_discarded_no_space">OTP discarded: All OTPs already entered!</string>
<string name="otps_pending">(One or more OTPs already available)</string>
<string name="loading">Loading…</string>

View File

@ -68,6 +68,7 @@ namespace keepass2android
{
Intent intent = new Intent(this, typeof(FileSelectActivity));
AppTask.ToIntent(intent);
intent.AddFlags(ActivityFlags.ClearTask | ActivityFlags.NewTask);
StartActivityForResult(intent, 0);
Finish();

View File

@ -86,54 +86,46 @@ namespace OtpKeyProv
/// based on the code in OtpKeyPromptForm.cs
public void SetSecret(OtpInfo otpInfo, List<string> lOtps, string secret, OtpDataFmt? fmt)
{
try
byte[] pbSecret = EncodingUtil.ParseKey(secret,
(fmt.HasValue ? fmt.Value : OtpDataFmt.Hex));
if (pbSecret != null)
{
byte[] pbSecret = EncodingUtil.ParseKey(secret,
(fmt.HasValue ? fmt.Value : OtpDataFmt.Hex));
if (pbSecret != null)
{
otpInfo.Secret = pbSecret;
return;
}
if (!string.IsNullOrEmpty(otpInfo.EncryptedSecret)) // < v2.0
{
byte[] pbKey32 = OtpUtil.KeyFromOtps(lOtps.ToArray(), 0,
lOtps.Count, Convert.FromBase64String(
otpInfo.TransformationKey), otpInfo.TransformationRounds);
if (pbKey32 == null) throw new InvalidOperationException();
pbSecret = OtpUtil.DecryptData(otpInfo.EncryptedSecret,
pbKey32, Convert.FromBase64String(otpInfo.EncryptionIV));
if (pbSecret == null) throw new InvalidOperationException();
otpInfo.Secret = pbSecret;
otpInfo.Counter += (ulong) otpInfo.OtpsRequired;
}
else // >= v2.0, supporting look-ahead
{
bool bSuccess = false;
for (int i = 0; i < otpInfo.EncryptedSecrets.Count; ++i)
{
OtpEncryptedData d = otpInfo.EncryptedSecrets[i];
pbSecret = OtpUtil.DecryptSecret(d, lOtps.ToArray(), 0,
lOtps.Count);
if (pbSecret != null)
{
otpInfo.Secret = pbSecret;
otpInfo.Counter += ((ulong) otpInfo.OtpsRequired +
(ulong) i);
bSuccess = true;
break;
}
}
if (!bSuccess) throw new InvalidOperationException();
}
otpInfo.Secret = pbSecret;
return;
}
catch (Exception)
if (!string.IsNullOrEmpty(otpInfo.EncryptedSecret)) // < v2.0
{
//todo
throw;
byte[] pbKey32 = OtpUtil.KeyFromOtps(lOtps.ToArray(), 0,
lOtps.Count, Convert.FromBase64String(
otpInfo.TransformationKey), otpInfo.TransformationRounds);
if (pbKey32 == null) throw new InvalidOperationException();
pbSecret = OtpUtil.DecryptData(otpInfo.EncryptedSecret,
pbKey32, Convert.FromBase64String(otpInfo.EncryptionIV));
if (pbSecret == null) throw new InvalidOperationException();
otpInfo.Secret = pbSecret;
otpInfo.Counter += (ulong) otpInfo.OtpsRequired;
}
else // >= v2.0, supporting look-ahead
{
bool bSuccess = false;
for (int i = 0; i < otpInfo.EncryptedSecrets.Count; ++i)
{
OtpEncryptedData d = otpInfo.EncryptedSecrets[i];
pbSecret = OtpUtil.DecryptSecret(d, lOtps.ToArray(), 0,
lOtps.Count);
if (pbSecret != null)
{
otpInfo.Secret = pbSecret;
otpInfo.Counter += ((ulong) otpInfo.OtpsRequired +
(ulong) i);
bSuccess = true;
break;
}
}
if (!bSuccess) throw new InvalidOperationException();
}
}

View File

@ -24,6 +24,7 @@ namespace keepass2android
/// </summary>
public class Intents
{
/// <summary>Broadcast this intent to lock the database (with quick unlock if enabled)</summary>
public const String LockDatabase = "keepass2android.lock_database";
/// <summary>Broadcast this intent to close the database (no quick unlock, full close)</summary>
@ -35,6 +36,9 @@ namespace keepass2android
public const String CopyUsername = "keepass2android.copy_username";
public const String CopyPassword = "keepass2android.copy_password";
public const String CheckKeyboard = "keepass2android.check_keyboard";
public const String StartWithOtp = "keepass2android.startWithOtp";
public const String OtpExtraKey = "keepass2android.Otp";
public const String FileBrowse = "org.openintents.action.PICK_FILE";
public const int RequestCodeFileBrowseForOpen = 987321;

View File

@ -97,6 +97,7 @@
<Compile Include="ChangeLog.cs" />
<Compile Include="icons\DrawableFactory.cs" />
<Compile Include="icons\Icons.cs" />
<Compile Include="NfcOtpActivity.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="KeePass.cs" />