+ first version of MasterKee plugin

This commit is contained in:
Philipp Crocoll 2014-07-13 20:58:10 +02:00
parent 2e56a007fc
commit d93946ed05
36 changed files with 1865 additions and 367 deletions

22
.gitignore vendored
View File

@ -260,3 +260,25 @@ Thumbs.db
/src/java/PluginInputStick/icons
/src/PluginSdkBinding/bin/Release
/src/MasterPassword/bin/Debug
/src/MasterPassword/obj/Debug
/src/MasterPassword/obj/Release
/src/MPTest/bin/Debug
/src/MPTest/obj/Debug
/src/MasterKeePlugin/obj/Release
/src/MasterKeePlugin/bin/Debug
/src/MasterKeePlugin/bin/Release
/src/MasterKeePlugin/obj/Debug
/src/PluginSdkBinding/obj/Release
/src/MasterPassword/bin/Release
/src/java/MasterKee
/src/PluginSdkBinding/obj/ReleaseNoNet

View File

@ -29,6 +29,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginTOTP", "PluginTOTP\Pl
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PluginHostTest", "PluginHostTest\PluginHostTest.csproj", "{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterKeePlugin", "MasterKeePlugin\MasterKeePlugin.csproj", "{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MasterPassword", "MasterPassword\MasterPassword.csproj", "{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MPTest", "MPTest\MPTest.csproj", "{96A3EA5A-7024-479F-A5B1-06654D0867A3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -336,6 +342,66 @@ Global
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{C9F4AE81-0996-4E17-B3F2-D0F652F6AC50}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Mixed Platforms.Deploy.0 = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|Win32.ActiveCfg = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Debug|x64.ActiveCfg = Debug|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.Build.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Any CPU.Deploy.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Mixed Platforms.Deploy.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|Win32.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.Release|x64.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Any CPU.Deploy.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Mixed Platforms.Deploy.0 = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|Win32.ActiveCfg = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Debug|x64.ActiveCfg = Debug|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Any CPU.Build.0 = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|Win32.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.Release|x64.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{2F7CB5B4-AC2A-4790-B0F3-42E6C9A060D5}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|Win32.ActiveCfg = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Debug|x64.ActiveCfg = Debug|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Any CPU.Build.0 = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|Win32.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.Release|x64.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Any CPU.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Any CPU.Build.0 = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Mixed Platforms.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Mixed Platforms.Build.0 = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|Win32.ActiveCfg = Release|Any CPU
{96A3EA5A-7024-479F-A5B1-06654D0867A3}.ReleaseNoNet|x64.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -11,6 +11,21 @@ namespace MPTest
[TestClass()]
public class MpAlgorithmTests
{
static sbyte[] ToSignedByteArray(byte[] unsigned)
{
sbyte[] signed = new sbyte[unsigned.Length];
Buffer.BlockCopy(unsigned, 0, signed, 0, unsigned.Length);
return signed;
}
static byte[] ToUnsignedByteArray(sbyte[] signed)
{
byte[] unsigned = new byte[signed.Length];
Buffer.BlockCopy(signed, 0, unsigned, 0, signed.Length);
return unsigned;
}
private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
@ -27,9 +42,9 @@ namespace MPTest
-126, 24, 15, 65, 9, 17, 0, 123, 91, 105, -46, -99, -64, 123, -12, 80, -37, -77
};
var result = MpAlgorithm.GetKeyForPassword("u", "test");
Assert.IsTrue(expectedRes.SequenceEqual(result));
Assert.IsTrue(expectedRes.SequenceEqual(ToSignedByteArray(result)));
}
[TestMethod]
public void GenerateContentTest()
@ -63,7 +78,7 @@ namespace MPTest
{
-53, -69, -89, 48, 122, 56, 34, 13, -70, -103, 102, 90, -96, -75, 45, 68, 43, 67, 97, 60, 84, -90, 98, -95, -2, -2, 99, -60, -121, -2, -26, -45, 53, -31, 47, 0, -46, -97, 77, -41, 63, -15, -30, 60, 4, -120, 32, 122, -94, 42, 122, -103, -61, -115, 75, -123, -15, 47, 61, -100, -119, 115, 118, 82
};
Assert.IsTrue(expected.SequenceEqual(key));
Assert.IsTrue(expected.SequenceEqual(ToSignedByteArray(key)));
}
}
}

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Keepass2android.Pluginsdk;
namespace MasterKeePlugin
{
[BroadcastReceiver(Exported = true)]
[IntentFilter(new[] { Strings.ActionTriggerRequestAccess, Strings.ActionReceiveAccess, Strings.ActionRevokeAccess })]
public class AccessReceiver: PluginAccessBroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Android.Util.Log.Debug("KP2A_MasterKee", intent.Action);
base.OnReceive(context, intent);
}
public override IList<string> Scopes
{
get
{
return new List<string>
{
Strings.ScopeCurrentEntry,
Strings.ScopeQueryCredentialsForOwnPackage
};
}
}
}
}

View File

@ -0,0 +1,80 @@
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Java.Util;
using KeePassLib.Utility;
using Keepass2android.Pluginsdk;
namespace MasterKeePlugin
{
[BroadcastReceiver(Exported = true)]
[IntentFilter(new[] {Strings.ActionOpenEntry, Strings.ActionEntryActionSelected })]
public class ActionReceiver: PluginActionBroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Android.Util.Log.Debug("KP2A_MasterKee", intent.Action);
base.OnReceive(context, intent);
}
private static byte[] HashHMAC(byte[] key, byte[] message)
{
var hash = new HMACSHA256(key);
return hash.ComputeHash(message);
}
protected override void OpenEntry(OpenEntryAction oe)
{
string masterkey;
Android.Util.Log.Debug("KP2A_MasterKee", "Opening entry...");
if (oe.EntryFields.TryGetValue("MK_MasterKey", out masterkey))
{
Android.Util.Log.Debug("KP2A_MasterKee", "Entry is MK entry.");
string type;
if (!oe.EntryFields.TryGetValue("MK_Type", out type))
type = "Long Password";
int counter = 1;
string strCounter;
if (oe.EntryFields.TryGetValue("MK_Site_Counter", out strCounter))
{
int.TryParse(strCounter, out counter);
}
Android.Util.Log.Debug("KP2A_MasterKee", "Calculating password...");
string calculatedKey = MasterPassword.MpAlgorithm.GenerateContent(type,
oe.EntryFields[KeepassDefs.TitleField],
MemUtil.HexStringToByteArray(masterkey),
counter,
HashHMAC
);
Android.Util.Log.Debug("KP2A_MasterKee", "ok. Returning data.");
try
{
oe.SetEntryField(KeepassDefs.PasswordField, calculatedKey, true);
oe.SetEntryField("MK_MasterKey", "", true);
oe.SetEntryField("MK_Type", "", true);
oe.SetEntryField("MK_Site_Counter", "", true);
}
catch (Exception e)
{
Android.Util.Log.Debug("KP2A_MasterKee", e.ToString());
}
}
Android.Util.Log.Debug("KP2A_MasterKee", "Done.");
}
protected override void ActionSelected(ActionSelectedAction asa)
{
}
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace MasterKeePlugin
{
//TODO remove?
[Activity(Label = "@string/AddMkEntry")]
public class AddMasterKeeActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
}
}

View File

@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

View File

@ -0,0 +1,156 @@
using System;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Java.Lang;
using MasterKeePlugin;
using Exception = System.Exception;
using Object = Java.Lang.Object;
namespace keepass2android.Utils
{
public class LoadingDialog<TParams, TProgress, TResult> : AsyncTask<TParams, TProgress, TResult>
{
private readonly Context _context;
private readonly string _message;
private readonly bool _cancelable;
readonly Func<Object[], Object> _doInBackground;
readonly Action<Object> _onPostExecute;
private ProgressDialog mDialog;
/**
* Default is {@code 500}ms
*/
private int mDelayTime = 500;
/**
* Flag to use along with {@link #mDelayTime}
*/
private bool mFinished = false;
private Exception mLastException;
public LoadingDialog(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public LoadingDialog(Context context, string message, bool cancelable, Func<Object[], Object> doInBackground,
Action<Object> onPostExecute)
{
_context = context;
_message = message;
_cancelable = cancelable;
_doInBackground = doInBackground;
_onPostExecute = onPostExecute;
Initialize();
}
private void Initialize()
{
mDialog = new ProgressDialog(_context);
mDialog.SetMessage(_message);
mDialog.Indeterminate = true;
mDialog.SetCancelable(_cancelable);
if (_cancelable)
{
mDialog.SetCanceledOnTouchOutside(true);
mDialog.CancelEvent += (sender, args) => mDialog.Cancel();
}
}
protected override void OnPreExecute()
{
new Handler().PostDelayed(() =>
{
if (!mFinished)
{
try
{
/*
* sometime the activity has been finished before we
* show this dialog, it will raise error
*/
mDialog.Show();
}
catch (Exception t)
{
Android.Util.Log.Debug("LD", t.ToString());
}
}
}
, mDelayTime);
}
/**
* If you override this method, you must call {@code super.onCancelled()} at
* beginning of the method.
*/
protected override void OnCancelled() {
DoFinish();
base.OnCancelled();
}// onCancelled()
private void DoFinish() {
mFinished = true;
try {
/*
* Sometime the activity has been finished before we dismiss this
* dialog, it will raise error.
*/
mDialog.Dismiss();
} catch (Exception e)
{
Android.Util.Log.Debug("LD", e.ToString());
}
}// doFinish()
/**
* Sets last exception. This method is useful in case an exception raises
* inside {@link #doInBackground(Void...)}
*
* @param t
* {@link Throwable}
*/
protected void SetLastException(Exception e) {
mLastException = e;
}// setLastException()
/**
* Gets last exception.
*
* @return {@link Throwable}
*/
protected Exception GetLastException() {
return mLastException;
}// getLastException()
protected override Object DoInBackground(params Object[] @params)
{
return _doInBackground(@params);
}
protected override TResult RunInBackground(params TParams[] @params)
{
throw new NotImplementedException();
}
protected override void OnPostExecute(Object result)
{
DoFinish();
if (_onPostExecute != null)
_onPostExecute(result);
}
}
}

View File

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using Android.App;
using Android.Content;
using Android.Preferences;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Keepass2android.Pluginsdk;
namespace MasterKeePlugin
{
[Activity(Label = "MasterKee", MainLauncher = true, Icon = "@drawable/ic_launcher")]
public class MainActivity : Activity
{
private const string KEY_MK_ENTRY_ID = "KEY_MK_ENTRY_ID";
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
Button buttonSelect = FindViewById<Button>(Resource.Id.btnSelectMaster);
buttonSelect.Click += delegate {
var intent = Kp2aControl.QueryEntryIntentForOwnPackage;
try
{
StartActivityForResult(intent, 123);
}
catch (ActivityNotFoundException)
{
Toast.MakeText(this, "No Keepass2Android host app found. Please install Keepass2Android 0.9.4 or above!", ToastLength.Long).Show();
}
};
Button buttonCreateMaster = FindViewById<Button>(Resource.Id.btnSetupMaster);
buttonCreateMaster.Click += delegate
{
StartActivityForResult(new Intent(this, typeof (SetupMasterEntryActivity)), 124);
};
FindViewById(Resource.Id.btnAddEntry).Click += delegate
{
//StartActivityForResult(new Intent(this, typeof()), 125);
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
Dictionary<string, string> fields = new Dictionary<string, string>();
fields["MK_Site_Counter"] = "1";
fields["MK_Type"] = "Long Password";
fields[KeepassDefs.PasswordField] = "{MASTERKEE}";
fields["MK_MasterKey"] = "{REF:P@I:" + prefs.GetString(KEY_MK_ENTRY_ID, "") + "}";
try
{
StartActivityForResult(Kp2aControl.GetAddEntryIntent(fields, new List<string>() { "MK_MasterKey" }), 125);
}
catch (ActivityNotFoundException)
{
Toast.MakeText(this, "No Keepass2Android host app found. Please install Keepass2Android 0.9.4 or above!", ToastLength.Long).Show();
}
};
}
protected override void OnResume()
{
base.OnResume();
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
if (prefs.Contains(KEY_MK_ENTRY_ID))
{
Button buttonCreateMaster = FindViewById<Button>(Resource.Id.btnSetupMaster);
buttonCreateMaster.Visibility = ViewStates.Gone;
Button buttonSelect = FindViewById<Button>(Resource.Id.btnSelectMaster);
buttonSelect.Visibility = ViewStates.Gone;
FindViewById(Resource.Id.btnAddEntry).Visibility = ViewStates.Visible;
}
else
{
FindViewById(Resource.Id.btnAddEntry).Visibility = ViewStates.Gone;
}
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if ((requestCode == 123) && (resultCode == Result.Ok))
{
string masterEntryId = data.GetStringExtra(Strings.ExtraEntryId);
if (!String.IsNullOrEmpty(masterEntryId))
{
var prefs = PreferenceManager.GetDefaultSharedPreferences(this);
prefs.Edit().PutString(KEY_MK_ENTRY_ID, masterEntryId).Commit();
}
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9A4C5BAA-1A8A-49B4-BBC3-60D4871FB36C}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MasterKeePlugin</RootNamespace>
<AssemblyName>MasterKeePlugin</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AccessReceiver.cs" />
<Compile Include="ActionReceiver.cs" />
<Compile Include="AddMasterKeeActivity.cs" />
<Compile Include="LoadingDialog.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="MemUtil.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SetupMasterEntryActivity.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
<AndroidResource Include="Resources\layout\Setup.axml" />
<AndroidResource Include="Resources\layout\AddMkEntry.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\drawable-xxhdpi\Thumbs.db" />
<AndroidResource Include="Resources\drawable-xxxhdpi\Thumbs.db" />
<AndroidResource Include="Resources\drawable-hdpi\Thumbs.db" />
<AndroidResource Include="Resources\drawable-mdpi\Thumbs.db" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Main.axml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\Icon.png" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MasterPassword\MasterPassword.csproj">
<Project>{2f7cb5b4-ac2a-4790-b0f3-42e6c9a060d5}</Project>
<Name>MasterPassword</Name>
</ProjectReference>
<ProjectReference Include="..\PluginSdkBinding\PluginSdkBinding.csproj">
<Project>{3da3911e-36de-465e-8f15-f1991b6437e5}</Project>
<Name>PluginSdkBinding</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_menu_view.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\ic_launcher.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\ic_launcher.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\ic_launcher.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-mdpi\ic_launcher.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\ic_launcher.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\ic_launcher.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,567 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
#if !KeePassLibSD
using System.IO.Compression;
#else
using KeePassLibSD;
#endif
namespace KeePassLib.Utility
{
/// <summary>
/// Contains static buffer manipulation and string conversion routines.
/// </summary>
public static class MemUtil
{
private static readonly uint[] m_vSBox = new uint[256] {
0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,
0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4,
0x07CE9E5B, 0x31788A0C, 0xF683F6F4, 0xEA061F49,
0xFA5C2ACA, 0x4B9E494E, 0xB0AB25BA, 0x767731FC,
0x261893A7, 0x2B09F2CE, 0x046261E4, 0x41367B4B,
0x18A7F225, 0x8F923C0E, 0x5EF3A325, 0x28D0435E,
0x84C22919, 0xED66873C, 0x8CEDE444, 0x7FC47C24,
0xFCFC6BA3, 0x676F928D, 0xB4147187, 0xD8FB126E,
0x7D798D17, 0xFF82E424, 0x1712FA5B, 0xABB09DD5,
0x8156BA63, 0x84E4D969, 0xC937FB9A, 0x2F1E5BFC,
0x178ECA11, 0x0E71CD5F, 0x52AAC6F4, 0x71EEFC8F,
0x7090D749, 0x21CACA31, 0x92996378, 0x0939A8A8,
0xE9EE1934, 0xD2718616, 0xF2500543, 0xB911873C,
0xD3CB3EEC, 0x2BA0DBEB, 0xB42D0A27, 0xECE67C0F,
0x302925F0, 0x6114F839, 0xD39E6307, 0xE28970D6,
0xEB982F99, 0x941B4CDF, 0xC540E550, 0x8124FC45,
0x98B025C7, 0xE2BF90EA, 0x4F57C976, 0xCF546FE4,
0x59566DC8, 0xE3F4360D, 0xF5F9D231, 0xD6180B22,
0xB54E088A, 0xB5DFE6A6, 0x3637A36F, 0x056E9284,
0xAFF8FBC5, 0x19E01648, 0x8611F043, 0xDAE44337,
0xF61B6A1C, 0x257ACD9E, 0xDD35F507, 0xEF05CAFA,
0x05EB4A83, 0xFC25CA92, 0x0A4728E6, 0x9CF150EF,
0xAEEF67DE, 0xA9472337, 0x57C81EFE, 0x3E5E009F,
0x02CB03BB, 0x2BA85674, 0xF21DC251, 0x78C34A34,
0xABB1F5BF, 0xB95A2FBD, 0x1FB47777, 0x9A96E8AC,
0x5D2D2838, 0x55AAC92A, 0x99EE324E, 0x10F6214B,
0x58ABDFB1, 0x2008794D, 0xBEC880F0, 0xE75E5341,
0x88015C34, 0x352D8FBF, 0x622B7F6C, 0xF5C59EA2,
0x1F759D8E, 0xADE56159, 0xCC7B4C25, 0x5B8BC48C,
0xB6BD15AF, 0x3C5B5110, 0xE74A7C3D, 0xEE613161,
0x156A1C67, 0x72C06817, 0xEA0A6F69, 0x4CECF993,
0xCA9D554C, 0x8E20361F, 0x42D396B9, 0x595DE578,
0x749D7955, 0xFD1BA5FD, 0x81FC160E, 0xDB97E28C,
0x7CF148F7, 0x0B0B3CF5, 0x534DE605, 0x46421066,
0xD4B68DD1, 0x9E479CE6, 0xAE667A9D, 0xBC082082,
0xB06DD6EF, 0x20F0F23F, 0xB99E1551, 0xF47A2E3A,
0x71DA50C6, 0x67B65779, 0x2A8CB376, 0x1EA71EEE,
0x29ABCD50, 0xB6EB0C6B, 0x23C10511, 0x6F3F2144,
0x6AF23012, 0xF696BD9E, 0xB94099D8, 0xAD5A9C81,
0x7A0794FA, 0x7EDF59D6, 0x1E72E574, 0x8561913C,
0x4E4D568F, 0xEECB9928, 0x9C124D2E, 0x0848B82C,
0xF1CA395F, 0x9DAF43DC, 0xF77EC323, 0x394E9B59,
0x7E200946, 0x8B811D68, 0x16DA3305, 0xAB8DE2C3,
0xE6C53B64, 0x98C2D321, 0x88A97D81, 0xA7106419,
0x8E52F7BF, 0x8ED262AF, 0x7CCA974E, 0xF0933241,
0x040DD437, 0xE143B3D4, 0x3019F56F, 0xB741521D,
0xF1745362, 0x4C435F9F, 0xB4214D0D, 0x0B0C348B,
0x5051D189, 0x4C30447E, 0x7393D722, 0x95CEDD0B,
0xDD994E80, 0xC3D22ED9, 0x739CD900, 0x131EB9C4,
0xEF1062B2, 0x4F0DE436, 0x52920073, 0x9A7F3D80,
0x896E7B1B, 0x2C8BBE5A, 0xBD304F8A, 0xA993E22C,
0x134C41A0, 0xFA989E00, 0x39CE9726, 0xFB89FCCF,
0xE8FBAC97, 0xD4063FFC, 0x935A2B5A, 0x44C8EE83,
0xCB2BC7B6, 0x02989E92, 0x75478BEA, 0x144378D0,
0xD853C087, 0x8897A34E, 0xDD23629D, 0xBDE2A2A2,
0x581D8ECC, 0x5DA8AEE8, 0xFF8AAFD0, 0xBA2BCF6E,
0x4BD98DAC, 0xF2EDB9E4, 0xFA2DC868, 0x47E84661,
0xECEB1C7D, 0x41705CA4, 0x5982E4D4, 0xEB5204A1,
0xD196CAFB, 0x6414804D, 0x3ABD4B46, 0x8B494C26,
0xB432D52B, 0x39C5356B, 0x6EC80BF7, 0x71BE5483,
0xCEC4A509, 0xE9411D61, 0x52F341E5, 0xD2E6197B,
0x4F02826C, 0xA9E48838, 0xD1F8F247, 0xE4957FB3,
0x586CCA99, 0x9A8B6A5B, 0x4998FBEA, 0xF762BE4C,
0x90DFE33C, 0x9731511E, 0x88C6A82F, 0xDD65A4D4
};
/// <summary>
/// Convert a hexadecimal string to a byte array. The input string must be
/// even (i.e. its length is a multiple of 2).
/// </summary>
/// <param name="strHex">String containing hexadecimal characters.</param>
/// <returns>Returns a byte array. Returns <c>null</c> if the string parameter
/// was <c>null</c> or is an uneven string (i.e. if its length isn't a
/// multiple of 2).</returns>
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="strHex" />
/// is <c>null</c>.</exception>
public static byte[] HexStringToByteArray(string strHex)
{
if(strHex == null) { Debug.Assert(false); throw new ArgumentNullException("strHex"); }
int nStrLen = strHex.Length;
if((nStrLen & 1) != 0) { Debug.Assert(false); return null; }
byte[] pb = new byte[nStrLen / 2];
byte bt;
char ch;
for(int i = 0; i < nStrLen; i += 2)
{
ch = strHex[i];
if((ch >= '0') && (ch <= '9'))
bt = (byte)(ch - '0');
else if((ch >= 'a') && (ch <= 'f'))
bt = (byte)(ch - 'a' + 10);
else if((ch >= 'A') && (ch <= 'F'))
bt = (byte)(ch - 'A' + 10);
else { Debug.Assert(false); bt = 0; }
bt <<= 4;
ch = strHex[i + 1];
if((ch >= '0') && (ch <= '9'))
bt += (byte)(ch - '0');
else if((ch >= 'a') && (ch <= 'f'))
bt += (byte)(ch - 'a' + 10);
else if((ch >= 'A') && (ch <= 'F'))
bt += (byte)(ch - 'A' + 10);
else { Debug.Assert(false); }
pb[i >> 1] = bt;
}
return pb;
}
/// <summary>
/// Convert a byte array to a hexadecimal string.
/// </summary>
/// <param name="pbArray">Input byte array.</param>
/// <returns>Returns the hexadecimal string representing the byte
/// array. Returns <c>null</c>, if the input byte array was <c>null</c>. Returns
/// an empty string, if the input byte array has length 0.</returns>
public static string ByteArrayToHexString(byte[] pbArray)
{
if(pbArray == null) return null;
int nLen = pbArray.Length;
if(nLen == 0) return string.Empty;
StringBuilder sb = new StringBuilder();
byte bt, btHigh, btLow;
for(int i = 0; i < nLen; ++i)
{
bt = pbArray[i];
btHigh = bt; btHigh >>= 4;
btLow = (byte)(bt & 0x0F);
if(btHigh >= 10) sb.Append((char)('A' + btHigh - 10));
else sb.Append((char)('0' + btHigh));
if(btLow >= 10) sb.Append((char)('A' + btLow - 10));
else sb.Append((char)('0' + btLow));
}
return sb.ToString();
}
/// <summary>
/// Set all bytes in a byte array to zero.
/// </summary>
/// <param name="pbArray">Input array. All bytes of this array will be set
/// to zero.</param>
public static void ZeroByteArray(byte[] pbArray)
{
Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray");
// for(int i = 0; i < pbArray.Length; ++i)
// pbArray[i] = 0;
Array.Clear(pbArray, 0, pbArray.Length);
}
/// <summary>
/// Convert 2 bytes to a 16-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes. Array must contain at least 2 bytes.</param>
/// <returns>16-bit unsigned integer.</returns>
public static ushort BytesToUInt16(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 2));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 2) throw new ArgumentException();
return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8));
}
/// <summary>
/// Convert 4 bytes to a 32-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>32-bit unsigned integer.</returns>
public static uint BytesToUInt32(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 4));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 4) throw new ArgumentException("Input array must contain 4 bytes!");
return (uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) |
((uint)pb[3] << 24);
}
/// <summary>
/// Convert 8 bytes to a 64-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>64-bit unsigned integer.</returns>
public static ulong BytesToUInt64(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 8));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 8) throw new ArgumentException();
return (ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) |
((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) |
((ulong)pb[6] << 48) | ((ulong)pb[7] << 56);
}
/// <summary>
/// Convert a 16-bit unsigned integer to 2 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">16-bit input word.</param>
/// <returns>Two bytes representing the 16-bit value.</returns>
public static byte[] UInt16ToBytes(ushort uValue)
{
byte[] pb = new byte[2];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
}
return pb;
}
/// <summary>
/// Convert a 32-bit unsigned integer to 4 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">32-bit input word.</param>
/// <returns>Four bytes representing the 32-bit value.</returns>
public static byte[] UInt32ToBytes(uint uValue)
{
byte[] pb = new byte[4];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
pb[2] = (byte)(uValue >> 16);
pb[3] = (byte)(uValue >> 24);
}
return pb;
}
/// <summary>
/// Convert a 64-bit unsigned integer to 8 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">64-bit input word.</param>
/// <returns>Eight bytes representing the 64-bit value.</returns>
public static byte[] UInt64ToBytes(ulong uValue)
{
byte[] pb = new byte[8];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
pb[2] = (byte)(uValue >> 16);
pb[3] = (byte)(uValue >> 24);
pb[4] = (byte)(uValue >> 32);
pb[5] = (byte)(uValue >> 40);
pb[6] = (byte)(uValue >> 48);
pb[7] = (byte)(uValue >> 56);
}
return pb;
}
public static bool ArraysEqual(byte[] x, byte[] y)
{
// Return false if one of them is null (not comparable)!
if((x == null) || (y == null)) { Debug.Assert(false); return false; }
if(x.Length != y.Length) return false;
for(int i = 0; i < x.Length; ++i)
{
if(x[i] != y[i]) return false;
}
return true;
}
public static void XorArray(byte[] pbSource, int nSourceOffset,
byte[] pbBuffer, int nBufferOffset, int nLength)
{
if(pbSource == null) throw new ArgumentNullException("pbSource");
if(nSourceOffset < 0) throw new ArgumentException();
if(pbBuffer == null) throw new ArgumentNullException("pbBuffer");
if(nBufferOffset < 0) throw new ArgumentException();
if(nLength < 0) throw new ArgumentException();
if((nSourceOffset + nLength) > pbSource.Length) throw new ArgumentException();
if((nBufferOffset + nLength) > pbBuffer.Length) throw new ArgumentException();
for(int i = 0; i < nLength; ++i)
pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i];
}
/// <summary>
/// Fast hash that can be used e.g. for hash tables.
/// The algorithm might change in the future; do not store
/// the hashes for later use.
/// </summary>
public static uint Hash32(byte[] v, int iStart, int iLength)
{
uint u = 0x326F637B;
if(v == null) { Debug.Assert(false); return u; }
if(iStart < 0) { Debug.Assert(false); return u; }
if(iLength < 0) { Debug.Assert(false); return u; }
int m = iStart + iLength;
if(m > v.Length) { Debug.Assert(false); return u; }
for(int i = iStart; i < m; ++i)
{
u ^= m_vSBox[v[i]];
u *= 3;
}
return u;
}
public static void CopyStream(Stream sSource, Stream sTarget)
{
Debug.Assert((sSource != null) && (sTarget != null));
if(sSource == null) throw new ArgumentNullException("sSource");
if(sTarget == null) throw new ArgumentNullException("sTarget");
const int nBufSize = 4096;
byte[] pbBuf = new byte[nBufSize];
while(true)
{
int nRead = sSource.Read(pbBuf, 0, nBufSize);
if(nRead == 0) break;
sTarget.Write(pbBuf, 0, nRead);
}
// Do not close any of the streams
}
public static byte[] Read(Stream s, int nCount)
{
if(s == null) throw new ArgumentNullException("s");
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
byte[] pb = new byte[nCount];
int iOffset = 0;
while(nCount > 0)
{
int iRead = s.Read(pb, iOffset, nCount);
if(iRead == 0) break;
iOffset += iRead;
nCount -= iRead;
}
if(iOffset != pb.Length)
{
byte[] pbPart = new byte[iOffset];
Array.Copy(pb, pbPart, iOffset);
return pbPart;
}
return pb;
}
public static void Write(Stream s, byte[] pbData)
{
if(s == null) { Debug.Assert(false); return; }
if(pbData == null) { Debug.Assert(false); return; }
s.Write(pbData, 0, pbData.Length);
}
public static byte[] Compress(byte[] pbData)
{
if(pbData == null) throw new ArgumentNullException("pbData");
if(pbData.Length == 0) return pbData;
MemoryStream msCompressed = new MemoryStream();
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress);
MemoryStream msSource = new MemoryStream(pbData, false);
MemUtil.CopyStream(msSource, gz);
gz.Close();
msSource.Close();
byte[] pbCompressed = msCompressed.ToArray();
msCompressed.Close();
return pbCompressed;
}
public static byte[] Decompress(byte[] pbCompressed)
{
if(pbCompressed == null) throw new ArgumentNullException("pbCompressed");
if(pbCompressed.Length == 0) return pbCompressed;
MemoryStream msCompressed = new MemoryStream(pbCompressed, false);
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress);
MemoryStream msData = new MemoryStream();
MemUtil.CopyStream(gz, msData);
gz.Close();
msCompressed.Close();
byte[] pbData = msData.ToArray();
msData.Close();
return pbData;
}
public static int IndexOf<T>(T[] vHaystack, T[] vNeedle)
where T : IEquatable<T>
{
if(vHaystack == null) throw new ArgumentNullException("vHaystack");
if(vNeedle == null) throw new ArgumentNullException("vNeedle");
if(vNeedle.Length == 0) return 0;
for(int i = 0; i <= (vHaystack.Length - vNeedle.Length); ++i)
{
bool bFound = true;
for(int m = 0; m < vNeedle.Length; ++m)
{
if(!vHaystack[i + m].Equals(vNeedle[m]))
{
bFound = false;
break;
}
}
if(bFound) return i;
}
return -1;
}
public static T[] Mid<T>(T[] v, int iOffset, int iLength)
{
if(v == null) throw new ArgumentNullException("v");
if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset");
if(iLength < 0) throw new ArgumentOutOfRangeException("iLength");
if((iOffset + iLength) > v.Length) throw new ArgumentException();
T[] r = new T[iLength];
Array.Copy(v, iOffset, r, 0, iLength);
return r;
}
public static IEnumerable<T> Union<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue; // Prevent duplicates
d[ta] = true;
yield return ta;
}
foreach(T tb in b)
{
if(d.ContainsKey(tb)) continue; // Prevent duplicates
d[tb] = true;
yield return tb;
}
yield break;
}
public static IEnumerable<T> Intersect<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.Remove(ta)) // Prevent duplicates
yield return ta;
}
yield break;
}
public static IEnumerable<T> Except<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue;
d[ta] = true; // Prevent duplicates
yield return ta;
}
yield break;
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="keepass2android.plugin.masterkee" android:versionCode="1" android:versionName="1.0" android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" />
<application android:label="MasterKeePlugin" android:icon="@drawable/ic_launcher"></application>
</manifest>

View File

@ -0,0 +1,30 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("MasterKeePlugin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MasterKeePlugin")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="12dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/ExplainMkMasterEntry" />
<Button
android:id="@+id/btnSetupMaster"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SetUpMkMasterEntry" />
<Button
android:id="@+id/btnSelectMaster"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/SelectMkMasterEntry" />
<Button
android:id="@+id/btnAddEntry"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/AddMkEntry" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:text="Your name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView1" />
<EditText
android:inputType="textPersonName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/etUser" />
<TextView
android:text="Your MasterKee master password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/textView2" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/toggle_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="@drawable/ic_menu_view" />
<EditText
android:id="@+id/entry_password"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/toggle_password"
android:layout_toLeftOf="@id/toggle_password"
android:hint="@string/hint_pass"
android:inputType="textPassword"
android:singleLine="true"
android:typeface="monospace" />
<!-- Confirm Password -->
<EditText
android:id="@+id/entry_confpassword"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/entry_password"
android:hint="@string/hint_conf_pass"
android:inputType="textPassword"
android:singleLine="true"
android:typeface="monospace" />
</RelativeLayout>
<Button
android:text="@string/button_ok"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button_ok" />
</LinearLayout>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="ExplainMkMasterEntry">Your Master Password used for generating MasterKee passwords must be stored inside a special entry in your Keepass2Android database. Please create such an entry and then select it in your database (The current KP2A plugin interface requires this as a 2-step process). After creating and selecting the entry, you will be able to create new entries for sites.</string>
<string name="SelectMkMasterEntry">Select existing master entry</string>
<string name="SetUpMkMasterEntry">Create new master entry</string>
<string name="ApplicationName">MasterKeePlugin</string>
<string name="hint_conf_pass">confirm password</string>
<string name="hint_pass">password</string>
<string name="button_ok">OK</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="deriving_key">Calculating derived key... This might take a few seconds.</string>
<string name="AddMkEntry">Add MasterKee entry</string>
<string name="kp2aplugin_title">MasterKee Plugin</string>
<string name="kp2aplugin_shortdesc">Plugin to generate passwords compatible with the MasterPassword approach by Maarten Billemont giving you the ability to restore passwords even if your database is lost.</string>
<string name="kp2aplugin_author">Philipp Crocoll</string>
</resources>

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Text;
using Android.Views;
using Android.Widget;
using KeePassLib.Utility;
using Keepass2android.Pluginsdk;
using keepass2android.Utils;
using Object = Java.Lang.Object;
namespace MasterKeePlugin
{
[Activity(Label = "Setup Master Entry")]
public class SetupMasterEntryActivity : Activity
{
private bool _showPassword;
private bool TryGetPassword(out string pass)
{
TextView passView = (TextView)FindViewById(Resource.Id.entry_password);
pass = passView.Text;
if (_showPassword)
return true;
TextView passConfView = (TextView)FindViewById(Resource.Id.entry_confpassword);
String confpass = passConfView.Text;
// Verify that passwords match
if (!pass.Equals(confpass))
{
// Passwords do not match
Toast.MakeText(this, Resource.String.error_pass_match, ToastLength.Long).Show();
return false;
}
return true;
}
private void MakePasswordMaskedOrVisible()
{
TextView password = (TextView)FindViewById(Resource.Id.entry_password);
TextView confpassword = (TextView)FindViewById(Resource.Id.entry_confpassword);
if (_showPassword)
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationVisiblePassword;
confpassword.Visibility = ViewStates.Gone;
}
else
{
password.InputType = InputTypes.ClassText | InputTypes.TextVariationPassword;
confpassword.Visibility = ViewStates.Visible;
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Setup);
ImageButton btnTogglePassword = (ImageButton)FindViewById(Resource.Id.toggle_password);
btnTogglePassword.Click += (sender, e) =>
{
_showPassword = !_showPassword;
MakePasswordMaskedOrVisible();
};
FindViewById(Resource.Id.button_ok).Click += delegate(object sender, EventArgs args)
{
string password;
if (!TryGetPassword(out password))
return;
string username = FindViewById<EditText>(Resource.Id.etUser).Text;
new LoadingDialog<object, object, object>(this, GetString(Resource.String.deriving_key), false,
delegate
{
return
MemUtil.ByteArrayToHexString(
MasterPassword.MpAlgorithm.GetKeyForPassword(username, password));
},
delegate(Object res)
{
string derivedKey = (string) res;
AddMasterKeeEntry(derivedKey, username);
}
).Execute();
};
}
private void AddMasterKeeEntry(string derivedKey, string username)
{
Dictionary<string, string> fields = new Dictionary<string, string>();
fields[KeepassDefs.TitleField] = "MasterKee master entry";
fields[KeepassDefs.UserNameField] = username;
fields[KeepassDefs.UrlField] = "androidapp://" + PackageName;
fields[KeepassDefs.PasswordField] = derivedKey;
try
{
StartActivityForResult(Kp2aControl.GetAddEntryIntent(fields, new List<string>()), 123);
//TODO: get created entry id and store
Finish();
}
catch (ActivityNotFoundException)
{
Toast.MakeText(this, "No Keepass2Android host app found. Please install Keepass2Android 0.9.4 or above!", ToastLength.Long).Show();
}
}
}
}

View File

@ -8,42 +8,26 @@ using MasterPassword.Data;
namespace MasterPassword
{
public partial class MpAlgorithm
{
static readonly PList PlistData = new PList(plist);
private const int MP_N = 32768;
private const int MP_r = 8;
private const int MP_p = 2;
private const int MP_dkLen = 64;
{
static sbyte[] ToSignedByteArray(byte[] unsigned)
{
sbyte[] signed = new sbyte[unsigned.Length];
Buffer.BlockCopy(unsigned, 0, signed, 0, unsigned.Length);
return signed;
}
static byte[] ToUnsignedByteArray(sbyte[] signed)
{
byte[] unsigned = new byte[signed.Length];
Buffer.BlockCopy(signed, 0, unsigned, 0, signed.Length);
return unsigned;
}
static readonly PList PlistData = new PList(plist);
private const int MP_N = 32768;
private const int MP_r = 8;
private const int MP_p = 2;
private const int MP_dkLen = 64;
public static byte[] GetKeyForPassword(string user, string password)
{
var salt = Combine(Encoding.UTF8.GetBytes("com.lyndir.masterpassword"),
IntAsByteArray(user.Length),
Encoding.UTF8.GetBytes(user));
var ssalt = ToSignedByteArray(salt);
var spwd = ToSignedByteArray(Encoding.UTF8.GetBytes(password));
IntAsByteArray(user.Length),
Encoding.UTF8.GetBytes(user));
var key = SCrypt.ComputeDerivedKey(Encoding.UTF8.GetBytes(password),
salt,
salt,
MP_N,
MP_r,
MP_p,null, MP_dkLen);
MP_r,
MP_p, null, MP_dkLen);
sbyte[] signed = ToSignedByteArray(key);
return signed;
return key;
}
@ -66,7 +50,7 @@ namespace MasterPassword
return intBytes;
}
public static String GenerateContent(string elementType, string siteName, sbyte[] key, int counter, Func<byte[], byte[], byte[]> hmacFunc)
public static String GenerateContent(string elementType, string siteName, byte[] key, int counter, Func<byte[], byte[], byte[]> hmacFunc)
{
if (counter == 0)
{
@ -74,15 +58,15 @@ namespace MasterPassword
//TODO: what does this line do in Java?
//counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
}
byte[] nameLengthBytes = IntAsByteArray(siteName.Length);
byte[] counterBytes =IntAsByteArray(counter);
sbyte[] seed = ToSignedByteArray(hmacFunc( ToUnsignedByteArray(key), Combine( Encoding.UTF8.GetBytes("com.lyndir.masterpassword"), //
byte[] counterBytes = IntAsByteArray(counter);
byte[] seed = hmacFunc(key, Combine(Encoding.UTF8.GetBytes("com.lyndir.masterpassword"), //
nameLengthBytes, //
Encoding.UTF8.GetBytes(siteName), //
counterBytes ) ) );
counterBytes));
//logger.trc( "seed is: %s", CryptUtils.encodeBase64( seed ) );
//Preconditions.checkState( seed.length > 0 );
@ -90,14 +74,16 @@ namespace MasterPassword
//MPTemplate template = templates.getTemplateForTypeAtRollingIndex( type, templateIndex );
//MPTemplate template = null;
var templatesLongPwd = PlistData["MPElementGeneratedEntity"]["Long Password"];
string template = templatesLongPwd[templateIndex%templatesLongPwd.Count];
var generatedEntities = PlistData["MPElementGeneratedEntity"];
//TODO catch wrong elementType!
var templatesLongPwd = generatedEntities[elementType];
string template = templatesLongPwd[templateIndex % templatesLongPwd.Count];
//logger.trc( "type: %s, template: %s", type, template );
StringBuilder password = new StringBuilder( template.Length );
for (int i = 0; i < template.Length; ++i) {
StringBuilder password = new StringBuilder(template.Length);
for (int i = 0; i < template.Length; ++i)
{
int characterIndex = seed[i + 1] & 0xFF; // Mask the integer's sign.
char c = template[i];
@ -116,5 +102,5 @@ namespace MasterPassword
}
}
}
}

View File

@ -100,6 +100,9 @@
<SubType>AndroidResource</SubType>
</AndroidResource>
<AndroidResource Include="Resources\Layout\sftp_credentials.axml" />
<AndroidResource Include="Resources\Layout\Setup.axml">
<SubType>AndroidResource</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\Layout\Main.axml" />

View File

@ -1,32 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.net-->
<resources>
<string name="about_feedback">Feedback</string>
<string name="about_homepage">Homepage</string>
<string name="AboutText">Keepass2Android is a password manager providing read/write access to KeePass 2.x databases on Android.</string>
<string name="CreditsText">The User Interface is based on a port of KeepassDroid developed by Brian Pellin. Code for database operations is based on KeePass by Dominik Reichl. The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.</string>
<string name="CreditsTextSFTP">SFTP support is implemented using the JSch library under BSD licence, created by JCraft, Inc.</string>
<string name="accept">Accept</string>
<string name="about_feedback">Feedback</string>
<string name="about_homepage">Homepage</string>
<string name="AboutText">Keepass2Android is a password manager providing read/write access to KeePass 2.x databases on Android.</string>
<string name="CreditsText">The User Interface is based on a port of KeepassDroid developed by Brian Pellin. Code for database operations is based on KeePass by Dominik Reichl. The Android robot is reproduced or modified from work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License.</string>
<string name="CreditsTextSFTP">SFTP support is implemented using the JSch library under BSD licence, created by JCraft, Inc.</string>
<string name="accept">Accept</string>
<string name="deny">Deny</string>
<string name="add_entry">Add entry</string>
<string name="add_url_entry">Create entry for URL</string>
<string name="add_group">Add group</string>
<string name="add_group_title">Add Group</string>
<string name="edit_group_title">Edit Group</string>
<string name="algorithm">Algorithm</string>
<string name="algorithm_colon">Algorithm</string>
<string name="app_name">Keepass2Android</string>
<string name="short_app_name">KP2A</string>
<string name="app_name_nonet">Keepass2Android Offline</string>
<string name="short_app_name_nonet">KP2A Offline</string>
<string name="app_timeout">Application timeout</string>
<string name="app_timeout_summary">Time before locking database when the application is inactive.</string>
<string name="kill_app_label">Kill application process</string>
<string name="show_kill_app">Close-Button</string>
<string name="show_kill_app_summary">Show a button in password screen to kill the application process (for paranoid users)</string>
<string name="application">Application</string>
<string name="application_settings">Application settings</string>
<string name="add_entry">Add entry</string>
<string name="add_url_entry">Create entry for URL</string>
<string name="add_group">Add group</string>
<string name="add_group_title">Add Group</string>
<string name="edit_group_title">Edit Group</string>
<string name="algorithm">Algorithm</string>
<string name="algorithm_colon">Algorithm</string>
<string name="app_name">Keepass2Android</string>
<string name="short_app_name">KP2A</string>
<string name="app_name_nonet">Keepass2Android Offline</string>
<string name="short_app_name_nonet">KP2A Offline</string>
<string name="app_timeout">Application timeout</string>
<string name="app_timeout_summary">Time before locking database when the application is inactive.</string>
<string name="kill_app_label">Kill application process</string>
<string name="show_kill_app">Close-Button</string>
<string name="show_kill_app_summary">Show a button in password screen to kill the application process (for paranoid users)</string>
<string name="application">Application</string>
<string name="application_settings">Application settings</string>
<string name="security_prefs">Security</string>
<string name="display_prefs">Display</string>
<string name="password_access_prefs">Password entry access</string>
@ -35,155 +34,154 @@
<string name="keyboard_prefs">Keyboard</string>
<string name="export_prefs">Export database...</string>
<string name="brackets">Brackets</string>
<string name="cancel">Cancel</string>
<string name="ClearClipboard">Clipboard cleared.</string>
<string name="clipboard_timeout">Clipboard timeout</string>
<string name="clipboard_timeout_summary">Time before clearing clipboard after copying username or password</string>
<string name="copy_username">Select to copy username to clipboard</string>
<string name="copy_password">Select to copy password to clipboard</string>
<string name="available_through_keyboard">Entry is available through KP2A Keyboard</string>
<string name="not_possible_im_picker">Could not open dialog to select input method. Please activate keyboard manually.</string>
<string name="please_activate_keyboard">Please enable the Keepass2Android keyboard in your system settings.</string>
<string name="creating_db_key">Creating database key…</string>
<string name="current_group">Current Group</string>
<string name="current_group_root">Current Group: Root</string>
<string name="database">Database</string>
<string name="digits">Digits</string>
<string name="disclaimer_formal">Keepass2Android comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
<string name="ellipsis">\u2026</string>
<string name="enter_filename">Enter database filename</string>
<string name="entry_accessed">Accessed</string>
<string name="entry_cancel">Cancel</string>
<string name="entry_comment">Comments</string>
<string name="entry_tags">Tags</string>
<string name="entry_override_url">Override URL</string>
<string name="entry_confpassword">Confirm password</string>
<string name="entry_created">Created</string>
<string name="entry_expires">Expires</string>
<string name="entry_keyfile">Key file (optional)</string>
<string name="entry_modified">Modified</string>
<string name="entry_password">Password</string>
<string name="entry_save">Save</string>
<string name="entry_title">Name</string>
<string name="entry_url">URL</string>
<string name="entry_user_name">User Name</string>
<string name="entry_extra_strings">Extra string fields</string>
<string name="entry_binaries">File attachments</string>
<string name="error_can_not_handle_uri">Keepass2Android cannot handle this uri.</string>
<string name="error_could_not_create_group">Error creating group.</string>
<string name="error_could_not_create_parent">Could not create parent directory.</string>
<string name="error_database_exists">This file already exists.</string>
<string name="error_database_settings">Failed to determine database settings.</string>
<string name="error_failed_to_launch_link">Failed to launch link.</string>
<string name="error_filename_required">A filename is required.</string>
<string name="error_file_not_create">Could not create file</string>
<string name="error_invalid_db">Invalid database.</string>
<string name="error_invalid_path">Invalid path.</string>
<string name="error_no_name">A name is required.</string>
<string name="error_nopass">A password or a keyfile is required.</string>
<string name="error_pass_gen_type">At least one password generation type must be selected</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="error_rounds_not_number">Rounds must be a number.</string>
<string name="error_title_required">A title is required.</string>
<string name="error_wrong_length">Enter a positive integer on length field</string>
<string name="FileNotFound">File not found.</string>
<string name="file_browser">File Browser</string>
<string name="generate_password">Generate Password</string>
<string name="group">Group</string>
<string name="hint_comment">comment</string>
<string name="hint_conf_pass">confirm password</string>
<string name="hint_generated_password">generated password</string>
<string name="hint_group_name">Group name</string>
<string name="hint_keyfile">key file</string>
<string name="hint_length">length</string>
<string name="hint_pass">password</string>
<string name="hint_login_pass">Password</string>
<string name="hint_title">name</string>
<string name="hint_url">url</string>
<string name="hint_override_url">override url</string>
<string name="hint_tags">tag1, tag2</string>
<string name="hint_username">username</string>
<string name="InvalidPassword">Invalid password or key file.</string>
<string name="invalid_algorithm">Invalid algorithm.</string>
<string name="invalid_db_sig">Database format not recognized.</string>
<string name="keyfile_does_not_exist">Key file does not exist.</string>
<string name="keyfile_is_empty">Key file is empty.</string>
<string name="length">Length</string>
<string name="list_size_title">Group list size</string>
<string name="list_size_summary">Text size in the group list</string>
<string name="loading_database">Loading database…</string>
<string name="lowercase">Lower-case</string>
<string name="MaskedPassword">*****</string>
<string name="maskpass_title">Mask password</string>
<string name="maskpass_summary">Hide passwords by default</string>
<string name="menu_about">About</string>
<string name="menu_change_key">Change Master Key</string>
<string name="menu_copy_pass">Copy Password</string>
<string name="menu_copy_user">Copy User</string>
<string name="menu_create">Create</string>
<string name="menu_app_settings">Settings</string>
<string name="menu_db_settings">Database settings</string>
<string name="menu_delete">Delete</string>
<string name="menu_move">Move to another group</string>
<string name="menu_donate">Donate a beer...</string>
<string name="menu_edit">Edit</string>
<string name="menu_hide_password">Hide Password</string>
<string name="menu_lock">Lock Database</string>
<string name="menu_open">Open</string>
<string name="menu_rename">Rename</string>
<string name="menu_search">Search</string>
<string name="menu_search_advanced">Advanced Search</string>
<string name="menu_url">Go to URL</string>
<string name="cancel">Cancel</string>
<string name="ClearClipboard">Clipboard cleared.</string>
<string name="clipboard_timeout">Clipboard timeout</string>
<string name="clipboard_timeout_summary">Time before clearing clipboard after copying username or password</string>
<string name="copy_username">Select to copy username to clipboard</string>
<string name="copy_password">Select to copy password to clipboard</string>
<string name="available_through_keyboard">Entry is available through KP2A Keyboard</string>
<string name="not_possible_im_picker">Could not open dialog to select input method. Please activate keyboard manually.</string>
<string name="please_activate_keyboard">Please enable the Keepass2Android keyboard in your system settings.</string>
<string name="creating_db_key">Creating database key…</string>
<string name="current_group">Current Group</string>
<string name="current_group_root">Current Group: Root</string>
<string name="database">Database</string>
<string name="digits">Digits</string>
<string name="disclaimer_formal">Keepass2Android comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
<string name="ellipsis">\u2026</string>
<string name="enter_filename">Enter database filename</string>
<string name="entry_accessed">Accessed</string>
<string name="entry_cancel">Cancel</string>
<string name="entry_comment">Comments</string>
<string name="entry_tags">Tags</string>
<string name="entry_override_url">Override URL</string>
<string name="entry_confpassword">Confirm password</string>
<string name="entry_created">Created</string>
<string name="entry_expires">Expires</string>
<string name="entry_keyfile">Key file (optional)</string>
<string name="entry_modified">Modified</string>
<string name="entry_password">Password</string>
<string name="entry_save">Save</string>
<string name="entry_title">Name</string>
<string name="entry_url">URL</string>
<string name="entry_user_name">User Name</string>
<string name="entry_extra_strings">Extra string fields</string>
<string name="entry_binaries">File attachments</string>
<string name="error_can_not_handle_uri">Keepass2Android cannot handle this uri.</string>
<string name="error_could_not_create_group">Error creating group.</string>
<string name="error_could_not_create_parent">Could not create parent directory.</string>
<string name="error_database_exists">This file already exists.</string>
<string name="error_database_settings">Failed to determine database settings.</string>
<string name="error_failed_to_launch_link">Failed to launch link.</string>
<string name="error_filename_required">A filename is required.</string>
<string name="error_file_not_create">Could not create file</string>
<string name="error_invalid_db">Invalid database.</string>
<string name="error_invalid_path">Invalid path.</string>
<string name="error_no_name">A name is required.</string>
<string name="error_nopass">A password or a keyfile is required.</string>
<string name="error_pass_gen_type">At least one password generation type must be selected</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="error_rounds_not_number">Rounds must be a number.</string>
<string name="error_title_required">A title is required.</string>
<string name="error_wrong_length">Enter a positive integer on length field</string>
<string name="FileNotFound">File not found.</string>
<string name="file_browser">File Browser</string>
<string name="generate_password">Generate Password</string>
<string name="group">Group</string>
<string name="hint_comment">comment</string>
<string name="hint_conf_pass">confirm password</string>
<string name="hint_generated_password">generated password</string>
<string name="hint_group_name">Group name</string>
<string name="hint_keyfile">key file</string>
<string name="hint_length">length</string>
<string name="hint_pass">password</string>
<string name="hint_login_pass">Password</string>
<string name="hint_title">name</string>
<string name="hint_url">url</string>
<string name="hint_override_url">override url</string>
<string name="hint_tags">tag1, tag2</string>
<string name="hint_username">username</string>
<string name="InvalidPassword">Invalid password or key file.</string>
<string name="invalid_algorithm">Invalid algorithm.</string>
<string name="invalid_db_sig">Database format not recognized.</string>
<string name="keyfile_does_not_exist">Key file does not exist.</string>
<string name="keyfile_is_empty">Key file is empty.</string>
<string name="length">Length</string>
<string name="list_size_title">Group list size</string>
<string name="list_size_summary">Text size in the group list</string>
<string name="loading_database">Loading database…</string>
<string name="lowercase">Lower-case</string>
<string name="MaskedPassword">*****</string>
<string name="maskpass_title">Mask password</string>
<string name="maskpass_summary">Hide passwords by default</string>
<string name="menu_about">About</string>
<string name="menu_change_key">Change Master Key</string>
<string name="menu_copy_pass">Copy Password</string>
<string name="menu_copy_user">Copy User</string>
<string name="menu_create">Create</string>
<string name="menu_app_settings">Settings</string>
<string name="menu_db_settings">Database settings</string>
<string name="menu_delete">Delete</string>
<string name="menu_move">Move to another group</string>
<string name="menu_donate">Donate a beer...</string>
<string name="menu_edit">Edit</string>
<string name="menu_hide_password">Hide Password</string>
<string name="menu_lock">Lock Database</string>
<string name="menu_open">Open</string>
<string name="menu_rename">Rename</string>
<string name="menu_search">Search</string>
<string name="menu_search_advanced">Advanced Search</string>
<string name="menu_url">Go to URL</string>
<string name="menu_change_db">Change database…</string>
<string name="minus">Minus</string>
<string name="never">Never</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="no_keys">No entries in the database or group.</string>
<string name="no_results">No search results</string>
<string name="no_url_handler">No handler for this url.</string>
<string name="open_recent">Open recent database (click to open)</string>
<string name="omitbackup_title">Don\'t search backup and recycle bin entries</string>
<string name="omitbackup_summary">Omit \'Backup\' and Recycle Bin group from search results</string>
<string name="pass_filename">KeePass database filename</string>
<string name="password_title">Enter database password</string>
<string name="master_key_type">Select master key type:</string>
<string name="progress_create">Creating new database…</string>
<string name="create_database">Create database</string>
<string name="progress_title">Working…</string>
<string name="remember_keyfile_summary">Remembers the location of keyfiles</string>
<string name="remember_keyfile_title">Save keyfile</string>
<string name="remove_from_filelist">Remove</string>
<string name="rijndael">Rijndael (AES)</string>
<string name="root">Root</string>
<string name="rounds">Encryption Rounds</string>
<string name="rounds_explaination">Higher encryption rounds provide additional protection against brute force attacks, but can really slow down loading and saving.</string>
<string name="rounds_hint">rounds</string>
<string name="database_name">Database name</string>
<string name="default_username">Default user name for new entries</string>
<string name="saving_database">Saving database…</string>
<string name="minus">Minus</string>
<string name="never">Never</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="no_keys">No entries in the database or group.</string>
<string name="no_results">No search results</string>
<string name="no_url_handler">No handler for this url.</string>
<string name="open_recent">Open recent database (click to open)</string>
<string name="omitbackup_title">Don\'t search backup and recycle bin entries</string>
<string name="omitbackup_summary">Omit \'Backup\' and Recycle Bin group from search results</string>
<string name="pass_filename">KeePass database filename</string>
<string name="password_title">Enter database password</string>
<string name="master_key_type">Select master key type:</string>
<string name="progress_create">Creating new database…</string>
<string name="create_database">Create database</string>
<string name="progress_title">Working…</string>
<string name="remember_keyfile_summary">Remembers the location of keyfiles</string>
<string name="remember_keyfile_title">Save keyfile</string>
<string name="remove_from_filelist">Remove</string>
<string name="rijndael">Rijndael (AES)</string>
<string name="root">Root</string>
<string name="rounds">Encryption Rounds</string>
<string name="rounds_explaination">Higher encryption rounds provide additional protection against brute force attacks, but can really slow down loading and saving.</string>
<string name="rounds_hint">rounds</string>
<string name="database_name">Database name</string>
<string name="default_username">Default user name for new entries</string>
<string name="saving_database">Saving database…</string>
<string name="exporting_database">Exporting database…</string>
<string name="export_database_successful">Database exported successfully!</string>
<string name="space">Space</string>
<string name="search_label">Search</string>
<string name="show_password">Show password</string>
<string name="sort_name">Sort by name</string>
<string name="sort_db">Sort by creation date</string>
<string name="special">Special</string>
<string name="search_hint">Find what</string>
<string name="search_results">Search results</string>
<string name="search_in">Search in</string>
<string name="select_other_entry">Select another entry</string>
<string name="select_group_then_add">Open the desired group, then press "%1$s"!</string>
<string name="search_label">Search</string>
<string name="show_password">Show password</string>
<string name="sort_name">Sort by name</string>
<string name="sort_db">Sort by creation date</string>
<string name="special">Special</string>
<string name="search_hint">Find what</string>
<string name="search_results">Search results</string>
<string name="search_in">Search in</string>
<string name="select_other_entry">Select another entry</string>
<string name="select_group_then_add">Open the desired group, then press "%1$s"!</string>
<string name="insert_element_here">Insert here</string>
<string name="twofish">Twofish</string>
<string name="underline">Underline</string>
<string name="unsupported_db_version">Unsupported database version.</string>
<string name="uppercase">Upper-case</string>
<string name="warning_read_only">Your sd card is currently read-only. You may not be able to save changes to your database.</string>
<string name="warning_unmounted">Your sd card is not currently mounted on your device. You will not be able to load or create your database.</string>
<string name="version_label">Version</string>
<string name="twofish">Twofish</string>
<string name="underline">Underline</string>
<string name="unsupported_db_version">Unsupported database version.</string>
<string name="uppercase">Upper-case</string>
<string name="warning_read_only">Your sd card is currently read-only. You may not be able to save changes to your database.</string>
<string name="warning_unmounted">Your sd card is not currently mounted on your device. You will not be able to load or create your database.</string>
<string name="version_label">Version</string>
<string name="version_history">Version history</string>
<string name="author">Keepass2Android is developed by Philipp Crocoll.</string>
<string name="further_authors">Thanks to code contributions by %1$s.</string>
@ -192,109 +190,97 @@
<string name="credit_keyboard">The KP2A keyboard is based on the Gingerbread keyboard by the Android Open Source Project and uses the Plugin Manager code from Hacker\'s Keyboard by Klaus Weidner.</string>
<string name="please_note">Please note</string>
<string name="contributors">Contributors</string>
<string name="regular_expression">Regular expression</string>
<string name="TanExpiresOnUse_title">Tan expires on use</string>
<string name="TanExpiresOnUse_summary">Mark TAN entries expired when using them</string>
<string name="ShowUsernameInList_title">Display username in list</string>
<string name="ShowUsernameInList_summary">Display usernames below entry titles. Useful for multiple accounts or TANs.</string>
<string name="regular_expression">Regular expression</string>
<string name="TanExpiresOnUse_title">Tan expires on use</string>
<string name="TanExpiresOnUse_summary">Mark TAN entries expired when using them</string>
<string name="ShowUsernameInList_title">Display username in list</string>
<string name="ShowUsernameInList_summary">Display usernames below entry titles. Useful for multiple accounts or TANs.</string>
<string name="RememberRecentFiles_title">Remember databases</string>
<string name="RememberRecentFiles_summary">Remember recently opened databases and show them in the Open database screen.</string>
<string name="kp2a_findUrl">Keepass2Android: Find password</string>
<string name="excludeExpiredEntries">Exclude expired entries</string>
<string name="search_options">Options</string>
<string name="caseSensitive">Case sensitive</string>
<string name="start_open_file">Open file...</string>
<string name="start_create">Create new database...</string>
<string name="start_open_url">Open URL...</string>
<string name="start_create_import">Import file to new database...</string>
<string name="enter_filename_details_url">The complete URL must be specified including protocol like http://.</string>
<string name="enter_filename_details_create_import">File to import will be selected in the next step.</string>
<string name="enable_quickunlock">Enable QuickUnlock</string>
<string name="QuickUnlock_label">Enter last %1$d characters of your password:</string>
<string name="QuickUnlock_button">QuickUnlock!</string>
<string name="QuickUnlock_lockButton">Close database</string>
<string name="QuickUnlockDefaultEnabled_title">Enable QuickUnlock by default</string>
<string name="QuickUnlockDefaultEnabled_summary">Defines whether QuickUnlock is enabled by default or not.</string>
<string name="QuickUnlockIconHidden_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden_summary">QuickUnlock unfortunately does not work without displaying a notification icon. Select this option to use a transparent icon.</string>
<string name="QuickUnlockIconHidden16_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden16_summary">QuickUnlock requires a notification to work properly. Select this option to display a notification without an icon.</string>
<string name="QuickUnlockLength_title">Length of QuickUnlock key</string>
<string name="QuickUnlockLength_summary">Maximum number of characters used as QuickUnlock password.</string>
<string name="QuickUnlock_fail">QuickUnlock failed: incorrect password!</string>
<string name="BinaryDirectory_title">File attachments directory</string>
<string name="BinaryDirectory_summary">Directory where file attachments are saved to.</string>
<string name="SaveAttachmentDialog_title">Save attachment</string>
<string name="SaveAttachmentDialog_text">Please select where to save the attachment.</string>
<string name="SaveAttachmentDialog_save">Save to SD card</string>
<string name="SaveAttachmentDialog_open">Save to cache and open</string>
<string name="SaveAttachment_doneMessage">Saved file to %1$s.</string>
<string name="SaveAttachment_Failed">Could not save attachment to %1$s.</string>
<string name="excludeExpiredEntries">Exclude expired entries</string>
<string name="search_options">Options</string>
<string name="caseSensitive">Case sensitive</string>
<string name="start_open_file">Open file...</string>
<string name="start_create">Create new database...</string>
<string name="start_open_url">Open URL...</string>
<string name="start_create_import">Import file to new database...</string>
<string name="enter_filename_details_url">The complete URL must be specified including protocol like http://.</string>
<string name="enter_filename_details_create_import">File to import will be selected in the next step.</string>
<string name="enable_quickunlock">Enable QuickUnlock</string>
<string name="QuickUnlock_label">Enter last %1$d characters of your password:</string>
<string name="QuickUnlock_button">QuickUnlock!</string>
<string name="QuickUnlock_lockButton">Close database</string>
<string name="QuickUnlockDefaultEnabled_title">Enable QuickUnlock by default</string>
<string name="QuickUnlockDefaultEnabled_summary">Defines whether QuickUnlock is enabled by default or not.</string>
<string name="QuickUnlockIconHidden_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden_summary">QuickUnlock unfortunately does not work without displaying a notification icon. Select this option to use a transparent icon.</string>
<string name="QuickUnlockIconHidden16_title">Hide QuickUnlock icon</string>
<string name="QuickUnlockIconHidden16_summary">QuickUnlock requires a notification to work properly. Select this option to display a notification without an icon.</string>
<string name="QuickUnlockLength_title">Length of QuickUnlock key</string>
<string name="QuickUnlockLength_summary">Maximum number of characters used as QuickUnlock password.</string>
<string name="QuickUnlock_fail">QuickUnlock failed: incorrect password!</string>
<string name="BinaryDirectory_title">File attachments directory</string>
<string name="BinaryDirectory_summary">Directory where file attachments are saved to.</string>
<string name="SaveAttachmentDialog_title">Save attachment</string>
<string name="SaveAttachmentDialog_text">Please select where to save the attachment.</string>
<string name="SaveAttachmentDialog_save">Save to SD card</string>
<string name="SaveAttachmentDialog_open">Save to cache and open</string>
<string name="SaveAttachment_doneMessage">Saved file to %1$s.</string>
<string name="SaveAttachment_Failed">Could not save attachment to %1$s.</string>
<string name="AddUrlToEntryDialog_title">Remember search text?</string>
<string name="AddUrlToEntryDialog_text">Would you like to store the search text "%1$s" in the selected entry in order to find it automatically next time?</string>
<string name="error_invalid_expiry_date">Invalid date/time format for expiry date!</string>
<string name="error_string_key">A field name is required for each string.</string>
<string name="field_name">Field Name</string>
<string name="field_value">Field value</string>
<string name="protection">Protected field</string>
<string name="add_binary">Add file attachment...</string>
<string name="add_extra_string">Add additional string</string>
<string name="error_string_key">A field name is required for each string.</string>
<string name="field_name">Field Name</string>
<string name="field_value">Field value</string>
<string name="protection">Protected field</string>
<string name="add_binary">Add file attachment...</string>
<string name="add_extra_string">Add additional string</string>
<string name="delete_extra_string">Delete additional string</string>
<string name="database_loaded_quickunlock_enabled">%1$s: Locked. QuickUnlock enabled.</string>
<string name="database_loaded_unlocked">%1$s: Unlocked.</string>
<string name="credentials_dialog_title">Enter server credentials</string>
<string name="UseFileTransactions_title">File transactions</string>
<string name="UseFileTransactions_summary">Use file transactions for writing databases</string>
<string name="credentials_dialog_title">Enter server credentials</string>
<string name="UseFileTransactions_title">File transactions</string>
<string name="UseFileTransactions_summary">Use file transactions for writing databases</string>
<string name="LockWhenScreenOff_title">Lock when screen off</string>
<string name="LockWhenScreenOff_summary">Lock the database when screen is switched off.</string>
<string name="LockWhenScreenOff_summary">Lock the database when screen is switched off.</string>
<string name="UseOfflineCache_title">Database caching</string>
<string name="UseOfflineCache_summary">Keep a copy of remote database files in the application cache directory. This allows to use remote databases even when offline.</string>
<string name="AcceptAllServerCertificates_title">SSL certificates</string>
<string name="AcceptAllServerCertificates_summary">Define the behavior when certificate validation fails. Note: you can install certificates on your device if validation fails!</string>
<string name="ClearOfflineCache_title">Clear cache?</string>
<string name="ClearOfflineCache_question">This will delete all cached database files. Any changes you made while being offline which have not yet been synchronized will be lost! Continue?</string>
<string name="CheckForFileChangesOnSave_title">Check for modifications</string>
<string name="CheckForFileChangesOnSave_summary">Check whether the file was modified externally before saving changes.</string>
<string name="ShowCopyToClipboardNotification_title">Clipboard notifications</string>
<string name="ShowCopyToClipboardNotification_summary">Make username and password accessible through the notification bar and clipboard. Beware of password sniffers!</string>
<string name="ShowKp2aKeyboardNotification_title">KP2A keyboard notification</string>
<string name="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard (recommended).</string>
<string name="OpenKp2aKeyboardAutomatically_title">Switch keyboard</string>
<string name="OpenKp2aKeyboardAutomatically_summary">Open keyboard selection dialog when entry is available through KP2A keyboard after search from the browser.</string>
<string name="CheckForFileChangesOnSave_title">Check for modifications</string>
<string name="CheckForFileChangesOnSave_summary">Check whether the file was modified externally before saving changes.</string>
<string name="ShowCopyToClipboardNotification_title">Clipboard notifications</string>
<string name="ShowCopyToClipboardNotification_summary">Make username and password accessible through the notification bar and clipboard. Beware of password sniffers!</string>
<string name="ShowKp2aKeyboardNotification_title">KP2A keyboard notification</string>
<string name="ShowKp2aKeyboardNotification_summary">Make full entry accessible through the KP2A keyboard (recommended).</string>
<string name="OpenKp2aKeyboardAutomatically_title">Switch keyboard</string>
<string name="OpenKp2aKeyboardAutomatically_summary">Open keyboard selection dialog when entry is available through KP2A keyboard after search from the browser.</string>
<string name="kp2a_switch_rooted">Auto-switch on rooted devices</string>
<string name="kp2a_switch_rooted_summary">On rooted devices, it is possible to automatically switch to the Keepass2Android keyboard (after search for an entry or by clicking the KP2A keyboard notification) and to switch back to the previous keyboard without showing the Input method picker. This also requires to install the Secure Settings app. See the KP2A documentation for more information!</string>
<string name="kp2a_switch_rooted_summary">On rooted devices, it is possible to automatically switch to the Keepass2Android keyboard (after search for an entry or by clicking the KP2A keyboard notification) and to switch back to the previous keyboard without showing the Input method picker. This also requires to install the Secure Settings app. See the KP2A documentation for more information!</string>
<string name="ShowUnlockedNotification_title">Notification icon while unlocked</string>
<string name="ShowUnlockedNotification_summary">Show a notification icon while the database is unlocked.</string>
<string name="PreloadDatabaseEnabled_title">Pre-load database file</string>
<string name="PreloadDatabaseEnabled_summary">Start background loading or downloading of the database file during password entry.</string>
<string name="AskOverwriteBinary">Do you want to overwrite the existing binary with the same name?</string>
<string name="AskOverwriteBinary_title">Overwrite existing binary?</string>
<string name="AskOverwriteBinary_yes">Overwrite</string>
<string name="AskOverwriteBinary_no">Rename</string>
<string name="AttachFailed">Failed to add file attachment.</string>
<string name="RecycleBin">Recycle Bin</string>
<string name="AskDeletePermanentlyEntry">Do you want to delete this entry permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyGroup">Do you want to delete this group permanently? Press No to recycle.</string>
<string name="AskDeletePermanently_title">Delete permanently?</string>
<string name="AskReloadFile_title">Reload file?</string>
<string name="AskReloadFile">The file which is currently open was changed by another program. Do you want to reload it?</string>
<string name="AskDiscardChanges">Do you really want to discard the changes made? (The Save button is at the top of the form.)</string>
<string name="AskDiscardChanges_title">Discard changes?</string>
<string name="suggest_improvements">Suggest or vote for improvements</string>
<string name="rate_app">Rate this app</string>
<string name="translate_app">Translate KP2A</string>
<string name="AskOverwriteBinary_title">Overwrite existing binary?</string>
<string name="AskOverwriteBinary_yes">Overwrite</string>
<string name="AskOverwriteBinary_no">Rename</string>
<string name="AttachFailed">Failed to add file attachment.</string>
<string name="RecycleBin">Recycle Bin</string>
<string name="AskDeletePermanentlyEntry">Do you want to delete this entry permanently? Press No to recycle.</string>
<string name="AskDeletePermanentlyGroup">Do you want to delete this group permanently? Press No to recycle.</string>
<string name="AskDeletePermanently_title">Delete permanently?</string>
<string name="AskReloadFile_title">Reload file?</string>
<string name="AskReloadFile">The file which is currently open was changed by another program. Do you want to reload it?</string>
<string name="AskDiscardChanges">Do you really want to discard the changes made? (The Save button is at the top of the form.)</string>
<string name="AskDiscardChanges_title">Discard changes?</string>
<string name="suggest_improvements">Suggest or vote for improvements</string>
<string name="rate_app">Rate this app</string>
<string name="translate_app">Translate KP2A</string>
<string name="AddingEntry">Adding entry…</string>
<string name="AddingGroup">Adding group…</string>
<string name="DeletingEntry">Deleting entry…</string>
@ -310,7 +296,6 @@
<string name="SynchronizingDatabase">Merging changes…</string>
<string name="YesSynchronize">Yes, merge</string>
<string name="NoOverwrite">No, overwrite</string>
<string name="SynchronizingCachedDatabase">Synchronizing cached database…</string>
<string name="DownloadingRemoteFile">Downloading remote file…</string>
<string name="UploadingFile">Uploading file…</string>
@ -318,7 +303,6 @@
<string name="FilesInSync">Files are in sync.</string>
<string name="SynchronizedDatabaseSuccessfully">Database synchronized successfully!</string>
<string name="CheckingDatabaseForChanges">Checking database for changes…</string>
<string name="CouldNotSaveToRemote">Could not save to remote: %1$s. Save again or use the Synchronize menu when remote connection is available again.</string>
<string name="CouldNotLoadFromRemote">Could not open from remote: %1$s. Loaded file from local cache. You can still make changes in the database and synchronize them later.</string>
<string name="UpdatedRemoteFileOnLoad">Updated remote file.</string>
@ -326,35 +310,24 @@
<string name="LoadedFromRemoteInSync">Remote file and cache are synchronized.</string>
<string name="UpdatedCachedFileOnLoad">Updated local cache copy of %1$s.</string>
<string name="RemoteDatabaseUnchanged">No changes detected.</string>
<string name="ResolvedCacheConflictByUsingRemoteOtpAux">Updated cached OTP auxiliary file: Remote counter was higher.</string>
<string name="ResolvedCacheConflictByUsingLocalOtpAux">Updated remote OTP auxiliary file: Local counter was higher.</string>
<string name="SynchronizingOtpAuxFile">Synchronizing OTP auxiliary file…</string>
<string name="database_file">database file</string>
<string name="otp_aux_file">OTP auxiliary file</string>
<string name="ErrorOcurred">An error occured:</string>
<string name="synchronize_database_menu">Synchronize database…</string>
<string name="CannotMoveGroupHere">Cannot move group to this group.</string>
<string name="donate_question">Today, it\'s Oktoberfest! If you like Keepass2Android: wouldn\'t today be a good day to buy me a beer?</string>
<string name="donate_bday_question">May 10th? It\'s my birthday! If you like this app, why not send me some birthday greetings along with a little birthday gift? This would really make me happy! :-)</string>
<string name="donate_missedbday_question">Oh, you missed my birthday on May 10th! If you like this app, why not send me some birthday greetings and a little birthday gift? It is not yet too late to make me happy! :-)</string>
<string name="ok_donate">Tell me more!</string>
<string name="no_thanks">No, I don\'t like it that much</string>
<string name="hint_sftp_host">host (ex: 192.168.0.1)</string>
<string name="hint_sftp_port">port</string>
<string name="initial_directory">Initial directory (optional):</string>
<string name="enter_sftp_login_title">Enter SFTP login data:</string>
<string name="select_storage_type">Select the storage type:</string>
<string name="filestoragename_file">Local file</string>
<string name="filestoragename_androidget">Get from third-party app</string>
<string name="filestoragename_androidsend">Send to third-party app</string>
@ -367,25 +340,19 @@
<string name="filestoragename_gdrive">Google Drive</string>
<string name="filestoragename_skydrive">OneDrive</string>
<string name="filestoragename_sftp">SFTP (SSH File Transfer)</string>
<string name="filestorage_setup_title">File access initialization</string>
<string name="database_location">Database location</string>
<string name="help_database_location">You can store your database locally on your Android device or in the cloud (non-Offline version only). Keepass2Android makes the database available even if you are offline. As the database is securely encrypted with AES 256 bit encryption, nobody will be able to access your passwords except you. We recommend to select Dropbox: It\'s accessible on all your devices and even provides backups of previous file versions.</string>
<string name="hint_database_location">Select where you want to store the database:</string>
<string name="button_change_location">Change location</string>
<string name="master_password">Master password</string>
<string name="help_master_password">Your database is encrypted with the password you enter here. Choose a strong password in order to keep the database safe! Tip: Make up a sentence or two and use the first letters of the words as password. Include punctuation marks.</string>
<string name="hint_master_password">Select a master password to protect your database:</string>
<string name="key_file">Key file</string>
<string name="help_key_file">A key file is basically a password stored in a file. Key files are typically stronger than master passwords, because the key can be a lot more complicated; however it\'s also harder to keep them secret. If you store your database in the cloud, don\'t store the key file there as well! This would make it completely useless! Important: Do not change the contents of the key file after creating the database!</string>
<string name="hint_key_file">Choose if you want to use a key file in addition to your master password:</string>
<string name="use_key_file">Use key file</string>
<string name="error_adding_keyfile">Error while adding the keyfile!</string>
<string name="init_otp">Load OTP auxiliary file…</string>
<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>
@ -400,12 +367,9 @@
<string name="OtpKeyError">Failed to create OTP key! Make sure you have entered the correct OTPs.</string>
<string name="ErrorUpdatingOtpAuxFile">Error updating OTP auxiliary file!</string>
<string name="SavingOtpAuxFile">Saving auxiliary OTP file…</string>
<string name="loading">Loading…</string>
<string name="enable_plugin_title">Enable plug-in?</string>
<string name="enable_plugin_question">Keepass2Android detected a plug-in with name: %1$s from package name: %2$s. Do you want to enable this plug-in? It will have access to the data stored in your Keepass databases.</string>
<string name="plugins">Plug-ins</string>
<string name="plugin_packagename">Package name:</string>
<string name="plugin_description">Description (not verified):</string>
@ -413,22 +377,16 @@
<string name="plugin_enabled">enabled</string>
<string name="plugin_disabled">disabled</string>
<string name="plugins_text">Click plug-in to enable/disable</string>
<string name="get_regular_version">Get more storage types</string>
<string name="CertificateWarning">Warning: Server certificate validation failed: %1$s. Install appropriate root certificate on your device or see settings!</string>
<string name="CertificateFailure">Error: Server certificate validation failed! Install appropriate root certificate on your device or see settings!</string>
<string name="export_fileformats_title">Select file format</string>
<string name="ChangeLog_title">Change log</string>
<string name="ChangeLog_0_9_3_r5">
<b>Version 0.9.3 r5</b>\n
* Incorporated fixes from Xamarin: Keepass2Android now compatible with ART on Android 4.4.2. Finally!\n
* Bug fixes: bugs in synchronization (refresh display, correct check for changes on http), bugs on Android 2.x devices, bugs in Google Drive and OneDrive storage implementations, clear clipboard on close database, bug opening attachments, display problems with keyboard\n
</string>
<string name="ChangeLog_0_9_3">
<b>Version 0.9.3</b>\n
* New keyboard with many improvements. See settings to customize.\n
@ -437,7 +395,6 @@
* Added workaround for bug in ART (Android 4.4.2)\n
* Bug fixes\n
</string>
<string name="ChangeLog_0_9_2">
<b>Version 0.9.2</b>\n
* Added OTP support (compatible with OtpKeyProv plugin)\n
@ -448,16 +405,13 @@
* Improved SSL certificate validation\n
* Bug fixes\n
</string>
<string name="ChangeLog_0_9_1">
<b>Version 0.9.1</b>\n
* Integrated SkyDrive support (Keepass2Android regular edition only)\n
* Fixed problems with Google Drive integration\n
* Added NTLM support
</string>
<string name="ChangeLog_0_9">
<string name="ChangeLog_0_9">
<b>Version 0.9</b>\n
* Integrated Dropbox and Google Drive support (read/write databases; Keepass2Android regular edition only)\n
* Integrated custom file browser (based on android-filechooser by HBA)\n
@ -465,8 +419,6 @@
* Included custom font DejaVu Sans Mono for displaying passwords\n
* Bug fixes
</string>
<string name="ChangeLog_0_8_6">
<b>Version 0.8.6</b>\n
* Support for Twofish cipher\n
@ -475,7 +427,6 @@
* QuickUnlock icon can be made transparent (see settings)\n
* Bug fixes
</string>
<string name="ChangeLog_0_8_5">
<b>Version 0.8.5</b>\n
* Remote files are stored in the local application cache to allow offline usage (including editing and later synchronization). See settings. \n
@ -485,7 +436,7 @@
* Entries can be added to root group\n
* Bug fixes (resolving reference fields, problems with keyboard on Italian an Chinese devices)
</string>
<string name="ChangeLog_0_8_4">
<string name="ChangeLog_0_8_4">
<b>Version 0.8.4</b>\n
* External database changes are detected and merged when saving\n
* Improved loading performance\n
@ -496,7 +447,8 @@
Thanks to Alex Vallat for his code contributions!\n
Thanks to Niki Hüttner (www.close-cut.de) for the new logo!\n
</string>
<string name="ChangeLog_0_8_3"><b>Version 0.8.3</b>\n
<string name="ChangeLog_0_8_3">
<b>Version 0.8.3</b>\n
* Username/TAN index displayed in entry list (see settings)\n
* Entries can be created if search from browser doesn\'t return results\n
* KP2A keyboard provides possibility to search for credentials for current app\n
@ -505,27 +457,32 @@
* Placeholders in entry fields are replaced before copying (most placeholders supported)\n
* minor bug fixes
</string>
<string name="ChangeLog_0_8_2"><b>Version 0.8.2</b>\n
<string name="ChangeLog_0_8_2">
<b>Version 0.8.2</b>\n
* Support for Digest Authentication in WebDAV\n
* Bugfixes (OI File manager, Open URL)
</string>
<string name="ChangeLog_0_8_1"><b>Version 0.8.1</b>\n
<string name="ChangeLog_0_8_1">
<b>Version 0.8.1</b>\n
* KP2A Offline and "Online" can be installed both again\n
* Added new translations (thanks to all contributors!)
</string>
<string name="ChangeLog_0_8"><b>Version 0.8</b>\n
<string name="ChangeLog_0_8">
<b>Version 0.8</b>\n
* Improved user interface especially for Android 4.x devices\n
* Allow using deliberate file managers for selecting existing files\n
* Added safer way for opening attachments (through cache directory)\n
* fixed bugs in Edit activity\n
* probably introduced new bugs :-)
</string>
<string name="ChangeLog_keptDonate">Extended possibility to donate a beer or something else</string>
<string name="ChangeLog_0_7"><b>Version 0.7</b>\n
<string name="ChangeLog_keptDonate">Extended possibility to donate a beer or something else</string>
<string name="ChangeLog_0_7">
<b>Version 0.7</b>\n
* Increased loading speed: key transformations now 10x faster!\n
* Added Keepass2Android soft-keyboard: Switch to this keyboard for entering credentials. Shields you from clipboard-based password sniffers (disable old clipboard notifications in the options)\n
* Added option to donate a beer or something else (see menu)</string>
<string name="ChangeLog"><b>Version 0.6.2</b>\n
<string name="ChangeLog">
<b>Version 0.6.2</b>\n
* Google Drive/Dropbox/... integration: Use the official Google Drive or Dropbox App and open any .kdbx-file. This will now bring up KP2A.\n
* Improved Search Dialog \n
* Improved search results for Share URL with subdomains\n
@ -539,39 +496,36 @@
<b>Version 0.6</b>\n
Initial public release
</string>
<string-array name="clipboard_timeout_options">
<item>30 seconds</item>
<item>1 minute</item>
<item>5 minutes</item>
<item>10 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 hour</item>
<item>Never</item>
</string-array>
<string-array name="clipboard_timeout_options">
<item>30 seconds</item>
<item>1 minute</item>
<item>5 minutes</item>
<item>10 minutes</item>
<item>15 minutes</item>
<item>30 minutes</item>
<item>1 hour</item>
<item>Never</item>
</string-array>
<string-array name="export_fileformat_options">
<item>Keepass 2 database (.kdbx)</item>
<item>Keepass 2 XML (unencrypted) (.xml)</item>
<item>Keepass CSV (unencrypted) (.csv)</item>
</string-array>
<string-array name="list_size_options">
<item>Small</item>
<item>Medium</item>
<item>Large</item>
</string-array>
<string-array name="list_size_options">
<item>Small</item>
<item>Medium</item>
<item>Large</item>
</string-array>
<string-array name="design_options">
<item>Holo Light</item>
<item>Holo Dark</item>
</string-array>
<string name="design_title">Design</string>
<string-array name="cred_remember_modes">
<item>Do not remember username and password</item>
<item>Remember username only</item>
<item>Remember username and password</item>
</string-array>
<item>Do not remember username and password</item>
<item>Remember username only</item>
<item>Remember username and password</item>
</string-array>
<string-array name="password_modes">
<item>Password only</item>
<item>Password + Key file</item>
@ -583,5 +537,5 @@ Initial public release
<item>Warn when validation fails</item>
<item>Do not accept invalid certificates</item>
</string-array>
</resources>
<string name="button_ok">Button</string>
</resources>

View File

@ -590,9 +590,14 @@ public class GoogleDriveFileStorage extends JavaFileStorageBase {
credential.setSelectedAccountName(accountName);
return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential)
.setApplicationName("Keepass2Android")
.setApplicationName(getApplicationName())
.build();
}
protected String getApplicationName()
{
return "Keepass2Android";
}
private Drive getDriveService(String accountName)
{

View File

@ -116,9 +116,10 @@ public class AccessManager
Log.d(_tag, "hostPackage is empty!");
return null;
}
Log.d(_tag, "trying to find prefs for "+hostPackage);
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
String scopesString = prefs.getString(PREF_KEY_SCOPE, "");
Log.d(_tag, "scopes: "+ scopesString);
Log.d(_tag, "available scopes: "+ scopesString);
ArrayList<String> currentScope = stringToStringArray(scopesString);
if (isSubset(scopes, currentScope))
{
@ -147,6 +148,7 @@ public class AccessManager
String accessToken) {
SharedPreferences prefs = getPrefsForHost(ctx, hostPackage);
Log.d(_tag, "removing AccessToken.");
if (prefs.getString(PREF_KEY_TOKEN, "").equals(accessToken))
{
Editor edit = prefs.edit();

View File

@ -6,6 +6,7 @@ import android.R.anim;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
* Broadcast flow between Host and Plugin
@ -30,10 +31,13 @@ import android.content.Intent;
*
*/
public abstract class PluginAccessBroadcastReceiver extends BroadcastReceiver {
private static final String _tag = "Kp2aPluginSDK";
@Override
public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
android.util.Log.d("KP2A.pluginsdk", "received broadcast with action="+action);
android.util.Log.d(_tag, "received broadcast with action="+action);
if (action == null)
return;
if (action.equals(Strings.ACTION_TRIGGER_REQUEST_ACCESS))
@ -84,7 +88,7 @@ public abstract class PluginAccessBroadcastReceiver extends BroadcastReceiver {
}
rpi.putStringArrayListExtra(Strings.EXTRA_SCOPES, getScopes());
Log.d(_tag, "requesting access for "+getScopes().size()+" tokens.");
ctx.sendBroadcast(rpi);
}

View File

@ -31,11 +31,13 @@ namespace keepass2android
{
_valueView.Visibility = ViewStates.Gone;
_keyView.Visibility = ViewStates.Gone;
_container.Visibility = ViewStates.Gone;
}
else
{
_valueView.Visibility = ViewStates.Visible;
_keyView.Visibility = ViewStates.Visible;
_container.Visibility = ViewStates.Visible;
_valueView.Text = value;
}
}

View File

@ -908,7 +908,9 @@
<AndroidResource Include="Resources\drawable\ic_launcher_gray_bday.png" />
</ItemGroup>
<ItemGroup>
<TransformFile Include="Properties\AndroidManifest.xml" />
<TransformFile Include="Properties\AndroidManifest.xml">
<SubType>Designer</SubType>
</TransformFile>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\collections_new_label_holodark.png" />