implemented loading of files with KeepassXC Challenge (#4).
requires write support, handling of Challenge/Response errors (or user cancels). Caution: saving corrupts the file at the moment!
This commit is contained in:
@@ -55,7 +55,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
|
|||||||
get { return "AES-KDF"; }
|
get { return "AES-KDF"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public AesKdf()
|
public override byte[] GetSeed(KdfParameters p)
|
||||||
|
{ return p.GetByteArray(ParamSeed); }
|
||||||
|
|
||||||
|
public AesKdf()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -68,7 +68,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
|
|||||||
get { return "Argon2"; }
|
get { return "Argon2"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Argon2Kdf()
|
public override byte[] GetSeed(KdfParameters p)
|
||||||
|
{ return p.GetByteArray(ParamSalt); }
|
||||||
|
|
||||||
|
public Argon2Kdf()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,7 +36,9 @@ namespace KeePassLib.Cryptography.KeyDerivation
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual KdfParameters GetDefaultParameters()
|
public abstract byte[] GetSeed(KdfParameters p);
|
||||||
|
|
||||||
|
public virtual KdfParameters GetDefaultParameters()
|
||||||
{
|
{
|
||||||
return new KdfParameters(this.Uuid);
|
return new KdfParameters(this.Uuid);
|
||||||
}
|
}
|
||||||
|
@@ -20,11 +20,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
using KeePassLib.Cryptography;
|
using KeePassLib.Cryptography;
|
||||||
using KeePassLib.Cryptography.KeyDerivation;
|
using KeePassLib.Cryptography.KeyDerivation;
|
||||||
using KeePassLib.Native;
|
|
||||||
using KeePassLib.Resources;
|
using KeePassLib.Resources;
|
||||||
using KeePassLib.Security;
|
using KeePassLib.Security;
|
||||||
using KeePassLib.Utility;
|
using KeePassLib.Utility;
|
||||||
@@ -168,7 +165,7 @@ namespace KeePassLib.Keys
|
|||||||
/// Creates the composite key from the supplied user key sources (password,
|
/// Creates the composite key from the supplied user key sources (password,
|
||||||
/// key file, user account, computer ID, etc.).
|
/// key file, user account, computer ID, etc.).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private byte[] CreateRawCompositeKey32(byte[] mPbMasterSeed)
|
private byte[] CreateRawCompositeKey32(byte[] mPbMasterSeed, byte[] mPbKdfSeed)
|
||||||
{
|
{
|
||||||
ValidateUserKeys();
|
ValidateUserKeys();
|
||||||
|
|
||||||
@@ -178,7 +175,7 @@ namespace KeePassLib.Keys
|
|||||||
foreach(IUserKey pKey in m_vUserKeys)
|
foreach(IUserKey pKey in m_vUserKeys)
|
||||||
{
|
{
|
||||||
if (pKey is ISeedBasedUserKey)
|
if (pKey is ISeedBasedUserKey)
|
||||||
((ISeedBasedUserKey)pKey).SetParams(mPbMasterSeed);
|
((ISeedBasedUserKey)pKey).SetParams(mPbMasterSeed, mPbKdfSeed);
|
||||||
ProtectedBinary b = pKey.KeyData;
|
ProtectedBinary b = pKey.KeyData;
|
||||||
if(b != null)
|
if(b != null)
|
||||||
{
|
{
|
||||||
@@ -211,15 +208,17 @@ namespace KeePassLib.Keys
|
|||||||
{
|
{
|
||||||
if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); }
|
if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); }
|
||||||
|
|
||||||
byte[] pbRaw32 = CreateRawCompositeKey32(mPbMasterSeed);
|
|
||||||
|
KdfEngine kdf = KdfPool.Get(p.KdfUuid);
|
||||||
|
if (kdf == null) // CryptographicExceptions are translated to "file corrupted"
|
||||||
|
throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph +
|
||||||
|
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
||||||
|
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
||||||
|
|
||||||
|
byte[] pbRaw32 = CreateRawCompositeKey32(mPbMasterSeed, kdf.GetSeed(p));
|
||||||
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
if((pbRaw32 == null) || (pbRaw32.Length != 32))
|
||||||
{ Debug.Assert(false); return null; }
|
{ Debug.Assert(false); return null; }
|
||||||
|
|
||||||
KdfEngine kdf = KdfPool.Get(p.KdfUuid);
|
|
||||||
if(kdf == null) // CryptographicExceptions are translated to "file corrupted"
|
|
||||||
throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph +
|
|
||||||
KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph +
|
|
||||||
"UUID: " + p.KdfUuid.ToHexString() + ".");
|
|
||||||
|
|
||||||
byte[] pbTrf32 = kdf.Transform(pbRaw32, p);
|
byte[] pbTrf32 = kdf.Transform(pbRaw32, p);
|
||||||
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
if(pbTrf32 == null) { Debug.Assert(false); return null; }
|
||||||
@@ -256,7 +255,7 @@ namespace KeePassLib.Keys
|
|||||||
|
|
||||||
public interface ISeedBasedUserKey
|
public interface ISeedBasedUserKey
|
||||||
{
|
{
|
||||||
void SetParams(byte[] masterSeed);
|
void SetParams(byte[] masterSeed, byte[] mPbKdfSeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class InvalidCompositeKeyException : Exception
|
public sealed class InvalidCompositeKeyException : Exception
|
||||||
|
84
src/keepass2android/ChallengeXCKey.cs
Normal file
84
src/keepass2android/ChallengeXCKey.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using Java.Lang;
|
||||||
|
using KeePassLib.Cryptography;
|
||||||
|
using KeePassLib.Keys;
|
||||||
|
using KeePassLib.Security;
|
||||||
|
using Exception = System.Exception;
|
||||||
|
|
||||||
|
namespace keepass2android
|
||||||
|
{
|
||||||
|
class ChallengeXCKey : IUserKey, ISeedBasedUserKey
|
||||||
|
{
|
||||||
|
private readonly int _requestCode;
|
||||||
|
|
||||||
|
public ProtectedBinary KeyData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Activity == null)
|
||||||
|
throw new Exception("Need an active Keepass2Android activity to challenge Yubikey!");
|
||||||
|
Activity.RunOnUiThread(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
byte[] challenge = _kdfSeed;
|
||||||
|
byte[] challenge64 = new byte[64];
|
||||||
|
for (int i = 0; i < 64; i++)
|
||||||
|
{
|
||||||
|
if (i < challenge.Length)
|
||||||
|
{
|
||||||
|
challenge64[i] = challenge[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
challenge64[i] = (byte)(challenge64.Length - challenge.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(challenge64, true);
|
||||||
|
|
||||||
|
if (chalIntent == null)
|
||||||
|
throw new Exception("YubiChallenge not installed.");
|
||||||
|
|
||||||
|
Activity.StartActivityForResult(chalIntent, _requestCode);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
while ((Response == null) && (Error == null))
|
||||||
|
{
|
||||||
|
Thread.Sleep(50);
|
||||||
|
}
|
||||||
|
if (Error != null)
|
||||||
|
throw new Exception("YubiChallenge failed: " + Error);
|
||||||
|
|
||||||
|
return new ProtectedBinary(true, CryptoUtil.HashSha256(Response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] _kdfSeed;
|
||||||
|
|
||||||
|
public ChallengeXCKey(LockingActivity activity, int requestCode)
|
||||||
|
{
|
||||||
|
this.Activity = activity;
|
||||||
|
_requestCode = requestCode;
|
||||||
|
Response = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetParams(byte[] masterSeed, byte[] mPbKdfSeed)
|
||||||
|
{
|
||||||
|
_kdfSeed = mPbKdfSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Response { get; set; }
|
||||||
|
|
||||||
|
public string Error { get; set; }
|
||||||
|
|
||||||
|
public LockingActivity Activity
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,6 +16,10 @@ This file is part of Keepass2Android, Copyright 2013 Philipp Crocoll. This file
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Android.App;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Content.PM;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
@@ -35,7 +39,38 @@ namespace keepass2android
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnPause() {
|
protected override void OnStart()
|
||||||
|
{
|
||||||
|
base.OnStart();
|
||||||
|
|
||||||
|
if (App.Kp2a.GetDb().Loaded)
|
||||||
|
{
|
||||||
|
var xcKey = App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
|
||||||
|
if (xcKey != null)
|
||||||
|
{
|
||||||
|
xcKey.Activity = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStop()
|
||||||
|
{
|
||||||
|
base.OnStop();
|
||||||
|
if (App.Kp2a.GetDb().Loaded)
|
||||||
|
{
|
||||||
|
var xcKey = App.Kp2a.GetDb().KpDatabase.MasterKey.GetUserKey<ChallengeXCKey>();
|
||||||
|
if (xcKey != null)
|
||||||
|
{
|
||||||
|
//don't store a pointer to this activity in the static database object to avoid memory leak
|
||||||
|
xcKey.Activity = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPause() {
|
||||||
base.OnPause();
|
base.OnPause();
|
||||||
|
|
||||||
TimeoutHelper.Pause(this);
|
TimeoutHelper.Pause(this);
|
||||||
@@ -52,6 +87,30 @@ namespace keepass2android
|
|||||||
|
|
||||||
TimeoutHelper.Resume(this);
|
TimeoutHelper.Resume(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public Intent TryGetYubichallengeIntentOrPrompt(byte[] challenge, bool promptToInstall)
|
||||||
|
{
|
||||||
|
Intent chalIntent = new Intent("com.yubichallenge.NFCActivity.CHALLENGE");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
@@ -60,7 +61,6 @@ using Process = Android.OS.Process;
|
|||||||
|
|
||||||
using KeeChallenge;
|
using KeeChallenge;
|
||||||
using KeePassLib.Cryptography.KeyDerivation;
|
using KeePassLib.Cryptography.KeyDerivation;
|
||||||
using KeePassLib.Security;
|
|
||||||
using AlertDialog = Android.App.AlertDialog;
|
using AlertDialog = Android.App.AlertDialog;
|
||||||
using Enum = System.Enum;
|
using Enum = System.Enum;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
@@ -69,72 +69,7 @@ using Toolbar = Android.Support.V7.Widget.Toolbar;
|
|||||||
|
|
||||||
namespace keepass2android
|
namespace keepass2android
|
||||||
{
|
{
|
||||||
class ChallengeXCKey : IUserKey, ISeedBasedUserKey
|
[Activity(Label = "@string/app_name",
|
||||||
{
|
|
||||||
private readonly Activity _activity;
|
|
||||||
private readonly int _requestCode;
|
|
||||||
|
|
||||||
public ProtectedBinary KeyData
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
|
|
||||||
_activity.RunOnUiThread(
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
//TODO refactor to use code from PasswordActivity including notice to install Yubichallenge
|
|
||||||
Intent chalIntent = new Intent("com.yubichallenge.NFCActivity.CHALLENGE");
|
|
||||||
byte[] challenge = _masterSeed;
|
|
||||||
byte[] challenge64 = new byte[64];
|
|
||||||
for (int i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
if (i < challenge.Length)
|
|
||||||
{
|
|
||||||
challenge64[i] = challenge[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
challenge64[i] = (byte) (challenge64.Length - challenge.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Kp2aLog.Log(MemUtil.ByteArrayToHexString(challenge64));
|
|
||||||
|
|
||||||
chalIntent.PutExtra("challenge", challenge64);
|
|
||||||
chalIntent.PutExtra("slot", 2);
|
|
||||||
IList<ResolveInfo> activities = _activity.PackageManager.QueryIntentActivities(chalIntent, 0);
|
|
||||||
bool isIntentSafe = activities.Count > 0;
|
|
||||||
if (isIntentSafe)
|
|
||||||
{
|
|
||||||
_activity.StartActivityForResult(chalIntent, _requestCode);
|
|
||||||
}
|
|
||||||
else throw new Exception("TODO implement: you need YubiChallenge");
|
|
||||||
});
|
|
||||||
while (Response == null)
|
|
||||||
Thread.Sleep(100);
|
|
||||||
|
|
||||||
return new ProtectedBinary(true, Response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] _masterSeed;
|
|
||||||
|
|
||||||
public ChallengeXCKey(Activity activity, int requestCode)
|
|
||||||
{
|
|
||||||
this._activity = activity;
|
|
||||||
_requestCode = requestCode;
|
|
||||||
Response = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetParams(byte[] masterSeed)
|
|
||||||
{
|
|
||||||
_masterSeed = masterSeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Response { get; set; }
|
|
||||||
}
|
|
||||||
[Activity(Label = "@string/app_name",
|
|
||||||
ConfigurationChanges = ConfigChanges.Orientation,
|
ConfigurationChanges = ConfigChanges.Orientation,
|
||||||
LaunchMode = LaunchMode.SingleInstance,
|
LaunchMode = LaunchMode.SingleInstance,
|
||||||
WindowSoftInputMode = SoftInput.AdjustResize,
|
WindowSoftInputMode = SoftInput.AdjustResize,
|
||||||
@@ -434,69 +369,91 @@ namespace keepass2android
|
|||||||
|
|
||||||
GetAuxFileLoader().LoadAuxFile(false);
|
GetAuxFileLoader().LoadAuxFile(false);
|
||||||
}
|
}
|
||||||
if (requestCode == RequestCodeChallengeYubikey && resultCode == Result.Ok)
|
if (requestCode == RequestCodeChallengeYubikey)
|
||||||
{
|
{
|
||||||
try
|
if (resultCode == Result.Ok)
|
||||||
{
|
{
|
||||||
byte[] challengeResponse = data.GetByteArrayExtra("response");
|
|
||||||
if (_currentlyWaitingKey != null)
|
|
||||||
{
|
try
|
||||||
_currentlyWaitingKey.Response = challengeResponse;
|
{
|
||||||
return;
|
byte[] challengeResponse = data.GetByteArrayExtra("response");
|
||||||
}
|
if (_currentlyWaitingKey != null)
|
||||||
else
|
{
|
||||||
{
|
if ((challengeResponse != null) && (challengeResponse.Length > 0))
|
||||||
_challengeProv = new KeeChallengeProv();
|
{
|
||||||
_challengeSecret = _challengeProv.GetSecret(_chalInfo, challengeResponse);
|
_currentlyWaitingKey.Response = challengeResponse;
|
||||||
Array.Clear(challengeResponse, 0, challengeResponse.Length);
|
}
|
||||||
}
|
else
|
||||||
|
_currentlyWaitingKey.Error = "Did not receive a valid response.";
|
||||||
}
|
|
||||||
catch (Exception e)
|
return;
|
||||||
{
|
|
||||||
Kp2aLog.Log(e.ToString());
|
}
|
||||||
Toast.MakeText(this, "Error: " + e.Message, ToastLength.Long).Show();
|
else
|
||||||
return;
|
{
|
||||||
}
|
_challengeProv = new KeeChallengeProv();
|
||||||
|
_challengeSecret = _challengeProv.GetSecret(_chalInfo, challengeResponse);
|
||||||
UpdateOkButtonState();
|
Array.Clear(challengeResponse, 0, challengeResponse.Length);
|
||||||
FindViewById(Resource.Id.otpInitView).Visibility = ViewStates.Gone;
|
}
|
||||||
|
|
||||||
if (_challengeSecret != null)
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
new LoadingDialog<object, object, object>(this, true,
|
{
|
||||||
//doInBackground
|
if (_currentlyWaitingKey != null)
|
||||||
delegate
|
{
|
||||||
{
|
_currentlyWaitingKey.Error = e.Message;
|
||||||
//save aux file
|
}
|
||||||
try
|
Kp2aLog.Log(e.ToString());
|
||||||
{
|
Toast.MakeText(this, "Error: " + e.Message, ToastLength.Long).Show();
|
||||||
ChallengeInfo temp = _challengeProv.Encrypt(_challengeSecret);
|
return;
|
||||||
if (!temp.Save(_otpAuxIoc))
|
}
|
||||||
{
|
|
||||||
Toast.MakeText(this, Resource.String.ErrorUpdatingChalAuxFile, ToastLength.Long).Show();
|
UpdateOkButtonState();
|
||||||
return false;
|
FindViewById(Resource.Id.otpInitView).Visibility = ViewStates.Gone;
|
||||||
}
|
|
||||||
|
if (_challengeSecret != null)
|
||||||
}
|
{
|
||||||
catch (Exception e)
|
new LoadingDialog<object, object, object>(this, true,
|
||||||
{
|
//doInBackground
|
||||||
Kp2aLog.LogUnexpectedError(e);
|
delegate
|
||||||
}
|
{
|
||||||
return null;
|
//save aux file
|
||||||
}
|
try
|
||||||
, delegate
|
{
|
||||||
{
|
ChallengeInfo temp = _challengeProv.Encrypt(_challengeSecret);
|
||||||
|
if (!temp.Save(_otpAuxIoc))
|
||||||
}).Execute();
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.ErrorUpdatingChalAuxFile, ToastLength.Long)
|
||||||
}
|
.Show();
|
||||||
else
|
return false;
|
||||||
{
|
}
|
||||||
Toast.MakeText(this, Resource.String.bad_resp, ToastLength.Long).Show();
|
|
||||||
return;
|
}
|
||||||
}
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
Kp2aLog.LogUnexpectedError(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
, delegate
|
||||||
|
{
|
||||||
|
|
||||||
|
}).Execute();
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Toast.MakeText(this, Resource.String.bad_resp, ToastLength.Long).Show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (_currentlyWaitingKey != null)
|
||||||
|
_currentlyWaitingKey.Error = "Cancelled Yubichallenge.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuxFileLoader GetAuxFileLoader()
|
private AuxFileLoader GetAuxFileLoader()
|
||||||
@@ -690,27 +647,12 @@ namespace keepass2android
|
|||||||
|
|
||||||
protected override void HandleSuccess()
|
protected override void HandleSuccess()
|
||||||
{
|
{
|
||||||
Intent chalIntent = new Intent("com.yubichallenge.NFCActivity.CHALLENGE");
|
var chalIntent = Activity.TryGetYubichallengeIntentOrPrompt(Activity._chalInfo.Challenge, true);
|
||||||
chalIntent.PutExtra("challenge", Activity._chalInfo.Challenge);
|
|
||||||
chalIntent.PutExtra("slot", 2);
|
if (chalIntent != null)
|
||||||
IList<ResolveInfo> activities = Activity.PackageManager.QueryIntentActivities(chalIntent, 0);
|
{
|
||||||
bool isIntentSafe = activities.Count > 0;
|
Activity.StartActivityForResult(chalIntent, RequestCodeChallengeYubikey);
|
||||||
if (isIntentSafe)
|
}
|
||||||
{
|
|
||||||
Activity.StartActivityForResult(chalIntent, RequestCodeChallengeYubikey);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AlertDialog.Builder b = new AlertDialog.Builder(Activity);
|
|
||||||
b.SetMessage(Resource.String.YubiChallengeNotInstalled);
|
|
||||||
b.SetPositiveButton(Android.Resource.String.Ok,
|
|
||||||
delegate
|
|
||||||
{
|
|
||||||
Util.GotoUrl(Activity, Activity.GetString(Resource.String.MarketURL) + "com.yubichallenge");
|
|
||||||
});
|
|
||||||
b.SetNegativeButton(Resource.String.cancel, delegate { });
|
|
||||||
b.Create().Show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetErrorMessage()
|
protected override string GetErrorMessage()
|
||||||
@@ -746,7 +688,8 @@ namespace keepass2android
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowOtpEntry(IList<string> prefilledOtps)
|
|
||||||
|
private void ShowOtpEntry(IList<string> prefilledOtps)
|
||||||
{
|
{
|
||||||
FindViewById(Resource.Id.otpInitView).Visibility = ViewStates.Gone;
|
FindViewById(Resource.Id.otpInitView).Visibility = ViewStates.Gone;
|
||||||
FindViewById(Resource.Id.otpEntry).Visibility = ViewStates.Visible;
|
FindViewById(Resource.Id.otpEntry).Visibility = ViewStates.Visible;
|
||||||
|
@@ -864,6 +864,7 @@ Erstes öffentliches Release</string>
|
|||||||
<item>Kennwort + OTP Secret (Recovery-Modus)</item>
|
<item>Kennwort + OTP Secret (Recovery-Modus)</item>
|
||||||
<item>Passwort + Challenge-Response</item>
|
<item>Passwort + Challenge-Response</item>
|
||||||
<item>Passwort + Challenge-Response-Secret (Recovery-Modus)</item>
|
<item>Passwort + Challenge-Response-Secret (Recovery-Modus)</item>
|
||||||
|
<item>Password + Challenge-Response for KeepassXC database</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="AcceptAllServerCertificates_options">
|
<string-array name="AcceptAllServerCertificates_options">
|
||||||
<item>Fehler bei Zertifikatsvalidierung ignorieren</item>
|
<item>Fehler bei Zertifikatsvalidierung ignorieren</item>
|
||||||
|
@@ -1069,6 +1069,7 @@ Initial public release
|
|||||||
<item>Password + OTP secret (recovery mode)</item>
|
<item>Password + OTP secret (recovery mode)</item>
|
||||||
<item>Password + Challenge-Response</item>
|
<item>Password + Challenge-Response</item>
|
||||||
<item>Password + Challenge-Response secret (recovery mode)</item>
|
<item>Password + Challenge-Response secret (recovery mode)</item>
|
||||||
|
<item>Password + Challenge-Response for KeepassXC database</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="AcceptAllServerCertificates_options">
|
<string-array name="AcceptAllServerCertificates_options">
|
||||||
<item>Ignore certificate validation failures</item>
|
<item>Ignore certificate validation failures</item>
|
||||||
|
@@ -171,6 +171,7 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ChallengeXCKey.cs" />
|
||||||
<Compile Include="EntryActivityClasses\ViewImagePopupItem.cs" />
|
<Compile Include="EntryActivityClasses\ViewImagePopupItem.cs" />
|
||||||
<Compile Include="ImageViewActivity.cs" />
|
<Compile Include="ImageViewActivity.cs" />
|
||||||
<Compile Include="addons\OtpKeyProv\EncodingUtil.cs" />
|
<Compile Include="addons\OtpKeyProv\EncodingUtil.cs" />
|
||||||
|
Reference in New Issue
Block a user