1.01 pre1:

added preferences to switch encryption+kdf and to edit kdf parameters (for AES and Argon2)
This commit is contained in:
Philipp Crocoll 2016-09-08 04:41:41 +02:00
parent e4c17e2e27
commit 9b9f069949
12 changed files with 390 additions and 69 deletions

View File

@ -46,7 +46,6 @@ namespace KeePassLib.Cryptography.Cipher
cp = new CipherPool();
cp.AddCipher(new StandardAesEngine());
cp.AddCipher(new ChaCha20Engine());
m_poolGlobal = cp;
}
@ -161,5 +160,12 @@ namespace KeePassLib.Cryptography.Cipher
return m_vCiphers[nIndex];
}
}
public IEnumerable<ICipherEngine> Engines
{
get {
return m_vCiphers;
}
}
}
}

View File

@ -122,6 +122,7 @@ namespace KeePassLib.Cryptography.KeyDerivation
// Try to use the native library first
if (NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds))
{
//no need to hash, this is already done in the native library.
byte[] pbKey = new byte[32];
Array.Copy(pbNewKey, pbKey, pbNewKey.Length);

View File

@ -26,6 +26,7 @@ namespace keepass2android
AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(ctx, Android.Resource.Style.ThemeHoloLightDialog));
builder.SetTitle(ctx.GetString(Resource.String.ChangeLog_title));
List<string> changeLog = new List<string>{
ctx.GetString(Resource.String.ChangeLog_1_01_preview),
ctx.GetString(Resource.String.ChangeLog_1_0_0e),
ctx.GetString(Resource.String.ChangeLog_1_0_0),
ctx.GetString(Resource.String.ChangeLog_0_9_9c),

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="81"
android:versionName="1.0.0-e"
android:versionCode="82"
android:versionName="1.01-pre1"
package="keepass2android.keepass2android"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />

View File

@ -26,7 +26,6 @@
android:layout_width="fill_parent"
android:inputType="number"/>
<TextView android:id="@+id/rounds_explaination"
android:text="@string/rounds_explaination"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/rounds"/>

View File

@ -53,6 +53,8 @@
<string name="show_kill_app_key">show_kill_app_key</string>
<string name="clipboard_timeout_key">clip_timeout_key</string>
<string name="db_key">db</string>
<string name="kdf_screen_key">kdf_screen</string>
<string name="kdf_key">kdf_key</string>
<string name="rounds_key">rounds</string>
<string name="master_pwd_key">change_master_pwd</string>
<string name="keyfile_key">keyfile</string>

View File

@ -64,6 +64,9 @@
<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>
@ -138,6 +141,8 @@
<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_param_not_number">Parameter 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>
@ -216,9 +221,17 @@
<string name="remove_from_filelist">Remove</string>
<string name="rijndael">Rijndael (AES)</string>
<string name="root">Root</string>
<string name="KeyDerivFunc">Key derivation function</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="argon2memory">Memory for Argon 2 (bytes)</string>
<string name="argon2parallelism">Parallelism for Argon 2</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>
@ -662,6 +675,12 @@
* Bug fix: Previous release contained two input methods (one crashing)\n
</string>
<string name="ChangeLog_1_01_preview">
Version 1.01-pre1\n
* NOTE: this is a preview, ONLY use for testing!\n
* added preview-support for the new KDBX-4-format (see http://keepass.info/help/kb/kdbx_4.html) including Argon2 key derivation and ChaCha20 encryption. Argon2 is currently only implemented in managed code. Expect a slow transformation process.\n
</string>
<string name="ChangeLog_1_0_0e">
Version 1.0.0e\n
* fix for Fingerprint Unlock on older Samsung devices with Android 6\n

View File

@ -31,10 +31,26 @@
android:title="@string/database_name"
android:persistent="false"
android:key="@string/database_name_key"/>
<Preference
<ListPreference
android:key="@string/algorithm_key"
android:title="@string/algorithm"
android:enabled="false"/>
android:dialogTitle="@string/algorithm"/>
<PreferenceScreen
android:key="@string/kdf_screen_key"
android:title="@string/KeyDerivFunc" >
<keepass2android.ToolbarPreference
android:key="@string/kdf_screen_key"
android:title="@string/KeyDerivFunc" />
<ListPreference
android:key="@string/kdf_key"
android:title="@string/KeyDerivFunc"
android:dialogTitle="@string/KeyDerivFunc"/>
<keepass2android.settings.RoundsPreference
android:key="@string/rounds_key"
android:persistent="false"
@ -43,6 +59,31 @@
android:positiveButtonText="@string/entry_save"
android:negativeButtonText="@string/entry_cancel"/>
<keepass2android.settings.Argon2RoundsPreference
android:key="argon2rounds"
android:persistent="false"
android:title="@string/rounds"
android:dialogLayout="@layout/database_settings"
android:positiveButtonText="@string/entry_save"
android:negativeButtonText="@string/entry_cancel"/>
<keepass2android.settings.Argon2MemoryPreference
android:key="argon2memory"
android:persistent="false"
android:title="@string/argon2memory"
android:dialogLayout="@layout/database_settings"
android:positiveButtonText="@string/entry_save"
android:negativeButtonText="@string/entry_cancel"/>
<keepass2android.settings.Argon2ParallelismPreference
android:key="argon2parallelism"
android:persistent="false"
android:title="@string/argon2parallelism"
android:dialogLayout="@layout/database_settings"
android:positiveButtonText="@string/entry_save"
android:negativeButtonText="@string/entry_cancel"/>
</PreferenceScreen>
<EditTextPreference
android:title="@string/default_username"
android:persistent="false"
@ -85,6 +126,7 @@
</PreferenceScreen>
<PreferenceScreen
android:key="@string/app_key"
android:title="@string/application"

View File

@ -26,7 +26,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<DefineConstants>DEBUG;_EXCLUDE_TWOFISH;_EXCLUDE_KEYBOARD;_EXCLUDE_FILECHOOSER;_EXCLUDE_JAVAFILESTORAGE;INCLUDE_KEYTRANSFORM</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
@ -182,6 +182,7 @@
<Compile Include="search\SearchProvider.cs" />
<Compile Include="SelectStorageLocationActivity.cs" />
<Compile Include="services\OngoingNotificationsService.cs" />
<Compile Include="settings\Argon2Preference.cs" />
<Compile Include="settings\DatabaseSettingsActivity.cs" />
<Compile Include="intents\Intents.cs" />
<Compile Include="timeout\TimeoutHelper.cs" />
@ -590,7 +591,9 @@
<AndroidResource Include="Resources\layout\about.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\database_settings.xml" />
<AndroidResource Include="Resources\layout\database_settings.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\layout\entry_edit.xml">
<SubType>Designer</SubType>
</AndroidResource>

View File

@ -0,0 +1,101 @@
using Android.Content;
using Android.Util;
using KeePassLib.Cryptography.KeyDerivation;
namespace keepass2android.settings
{
public class Argon2RoundsPreference: KdfNumberParamPreference
{
public Argon2RoundsPreference(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public Argon2RoundsPreference(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
public override ulong ParamValue
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
}
return kdfparams.GetUInt64(Argon2Kdf.ParamIterations, 0);
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamIterations, value);
}
}
}
public class Argon2ParallelismPreference : KdfNumberParamPreference
{
public Argon2ParallelismPreference(Context context, IAttributeSet attrs)
: base(context, attrs)
{
}
public Argon2ParallelismPreference(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
}
public override ulong ParamValue
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
}
return kdfparams.GetUInt32(Argon2Kdf.ParamParallelism, 0);
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt32(Argon2Kdf.ParamParallelism, (uint) value);
}
}
}
public class Argon2MemoryPreference : KdfNumberParamPreference
{
public Argon2MemoryPreference(Context context, IAttributeSet attrs)
: base(context, attrs)
{
}
public Argon2MemoryPreference(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
}
public override ulong ParamValue
{
get
{
var kdfparams = App.Kp2a.GetDb().KpDatabase.KdfParameters;
var kdf = KdfPool.Get(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid);
if (!(kdf is Argon2Kdf))
{
new Argon2Kdf().GetDefaultParameters();
}
return kdfparams.GetUInt64(Argon2Kdf.ParamMemory, 0);
}
set
{
App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(Argon2Kdf.ParamMemory, value);
}
}
}
}

View File

@ -39,6 +39,8 @@ using KeePassLib.Serialization;
using KeePassLib.Utility;
using keepass2android.Io;
using keepass2android.Utils;
using KeePassLib;
using KeePassLib.Cryptography.KeyDerivation;
namespace keepass2android
{
@ -313,6 +315,7 @@ namespace keepass2android
}
private KeyboardSwitchPrefManager _switchPrefManager;
private Preference aesRounds, argon2parallelism, argon2rounds, argon2memory;
void OnRememberKeyFileHistoryChanged(object sender, Preference.PreferenceChangeEventArgs eventArgs)
{
@ -344,19 +347,38 @@ namespace keepass2android
Database db = App.Kp2a.GetDb();
if (db.Loaded)
{
/*Preference rounds = FindPreference(GetString(Resource.String.rounds_key));
rounds.PreferenceChange += (sender, e) => SetRounds(db, e.Preference);
rounds.Enabled = db.CanWrite;
SetRounds(db, rounds);
*/
ListPreference kdfPref = (ListPreference) FindPreference(GetString(Resource.String.kdf_key));
kdfPref.SetEntries(KdfPool.Engines.Select(eng => eng.Name).ToArray());
string[] kdfValues = KdfPool.Engines.Select(eng => eng.Uuid.ToHexString()).ToArray();
kdfPref.SetEntryValues(kdfValues);
kdfPref.SetValueIndex(kdfValues.Select((v, i) => new {kdf = v, index = i}).First(el => el.kdf == db.KpDatabase.KdfParameters.KdfUuid.ToHexString()).index);
kdfPref.PreferenceChange += OnKdfChange;
aesRounds = FindPreference(GetString(Resource.String.rounds_key));
argon2rounds = FindPreference("argon2rounds");
argon2memory = FindPreference("argon2memory");
argon2parallelism = FindPreference("argon2parallelism");
aesRounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2rounds.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2memory.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
argon2parallelism.PreferenceChange += (sender, e) => UpdateKdfSummary(e.Preference);
UpdateKdfScreen();
PrepareDefaultUsername(db);
PrepareDatabaseName(db);
PrepareMasterPassword();
PrepareTemplates(db);
Preference algorithm = FindPreference(GetString(Resource.String.algorithm_key));
SetAlgorithm(db, algorithm);
ListPreference algorithmPref = (ListPreference)FindPreference(GetString(Resource.String.algorithm_key));
algorithmPref.SetEntries(CipherPool.GlobalPool.Engines.Select(eng => eng.DisplayName).ToArray());
string[] algoValues = CipherPool.GlobalPool.Engines.Select(eng => eng.CipherUuid.ToHexString()).ToArray();
algorithmPref.SetEntryValues(algoValues);
algorithmPref.SetValueIndex(algoValues.Select((v, i) => new { kdf = v, index = i }).First(el => el.kdf == db.KpDatabase.DataCipherUuid.ToHexString()).index);
algorithmPref.PreferenceChange += AlgorithmPrefChange;
algorithmPref.Summary =
CipherPool.GlobalPool.GetCipher(App.Kp2a.GetDb().KpDatabase.DataCipherUuid).DisplayName;
UpdateImportDbPref();
UpdateImportKeyfilePref();
}
@ -423,6 +445,98 @@ namespace keepass2android
}
private void AlgorithmPrefChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{
var db = App.Kp2a.GetDb();
var previousCipher = db.KpDatabase.DataCipherUuid;
db.KpDatabase.DataCipherUuid = new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue));
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish((success, message) =>
{
if (!success)
{
db.KpDatabase.DataCipherUuid = previousCipher;
Toast.MakeText(Activity, message, ToastLength.Long).Show();
return;
}
preferenceChangeEventArgs.Preference.Summary =
CipherPool.GlobalPool.GetCipher(db.KpDatabase.DataCipherUuid).DisplayName;
}));
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, save);
pt.Run();
}
private void UpdateKdfScreen()
{
var db = App.Kp2a.GetDb();
var kdf = KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid);
var kdfpref = FindPreference(GetString(Resource.String.kdf_key));
kdfpref.Summary = kdf.Name;
var kdfscreen = ((PreferenceScreen)FindPreference(GetString(Resource.String.kdf_screen_key)));
if (kdf is AesKdf)
{
if (kdfscreen.FindPreference(GetString(Resource.String.rounds_key)) == null)
kdfscreen.AddPreference(aesRounds);
kdfscreen.RemovePreference(argon2rounds);
kdfscreen.RemovePreference(argon2memory);
kdfscreen.RemovePreference(argon2parallelism);
aesRounds.Enabled = db.CanWrite;
UpdateKdfSummary(aesRounds);
}
else
{
kdfscreen.RemovePreference(aesRounds);
if (kdfscreen.FindPreference("argon2rounds") == null)
{
kdfscreen.AddPreference(argon2rounds);
kdfscreen.AddPreference(argon2memory);
kdfscreen.AddPreference(argon2parallelism);
}
UpdateKdfSummary(argon2rounds);
UpdateKdfSummary(argon2memory);
UpdateKdfSummary(argon2parallelism);
}
}
private void OnKdfChange(object sender, Preference.PreferenceChangeEventArgs preferenceChangeEventArgs)
{
var db = App.Kp2a.GetDb();
var previousKdfParams = db.KpDatabase.KdfParameters;
Kp2aLog.Log("previous kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString() );
db.KpDatabase.KdfParameters =
KdfPool.Get(
new PwUuid(MemUtil.HexStringToByteArray((string)preferenceChangeEventArgs.NewValue)))
.GetDefaultParameters();
Kp2aLog.Log("--new kdf: " + KdfPool.Get(db.KpDatabase.KdfParameters.KdfUuid) + " " + db.KpDatabase.KdfParameters.KdfUuid.ToHexString());
SaveDb save = new SaveDb(Activity, App.Kp2a, new ActionOnFinish((success, message) =>
{
if (!success)
{
db.KpDatabase.KdfParameters = previousKdfParams;
Toast.MakeText(Activity, message, ToastLength.Long).Show();
return;
}
UpdateKdfScreen();
}));
ProgressTask pt = new ProgressTask(App.Kp2a, Activity, save);
pt.Run();
}
private void UpdateKdfSummary(Preference preference)
{
preference.Summary = ((keepass2android.settings.KdfNumberParamPreference)preference).ParamValue.ToString();
}
private void PrepareNoDonationReminderPreference(Activity ctx, PreferenceScreen screen, Preference preference)
@ -797,11 +911,7 @@ namespace keepass2android
return targetIoc;
}
/*
private void SetRounds(Database db, Preference rounds)
{
rounds.Summary = db.KpDatabase.KeyEncryptionRounds.ToString(CultureInfo.InvariantCulture);
}*/
private void SetAlgorithm(Database db, Preference algorithm)
{

View File

@ -27,80 +27,68 @@ using KeePassLib.Cryptography.KeyDerivation;
namespace keepass2android.settings
{
/// <summary>
/// Represents the setting for the number of key transformation rounds. Changing this requires to save the database.
/// </summary>
public class RoundsPreference : DialogPreference {
public abstract class KdfNumberParamPreference: DialogPreference {
internal TextView RoundsView;
internal TextView edittext;
protected override View OnCreateDialogView() {
View view = base.OnCreateDialogView();
RoundsView = (TextView) view.FindViewById(Resource.Id.rounds);
edittext = (TextView) view.FindViewById(Resource.Id.rounds);
ulong numRounds = KeyEncryptionRounds;
RoundsView.Text = numRounds.ToString(CultureInfo.InvariantCulture);
ulong numRounds = ParamValue;
edittext.Text = numRounds.ToString(CultureInfo.InvariantCulture);
view.FindViewById<TextView>(Resource.Id.rounds_explaination).Text = ExplanationString;
return view;
}
public ulong KeyEncryptionRounds
public virtual string ExplanationString
{
get
{
AesKdf kdf = new AesKdf();
if (!kdf.Uuid.Equals(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid))
return (uint) PwDefs.DefaultKeyEncryptionRounds;
else
{
ulong uRounds = App.Kp2a.GetDb().KpDatabase.KdfParameters.GetUInt64(
AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds);
uRounds = Math.Min(uRounds, 0xFFFFFFFEUL);
return (uint) uRounds;
}
}
set { App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); }
get { return ""; }
}
public RoundsPreference(Context context, IAttributeSet attrs):base(context, attrs) {
public abstract ulong ParamValue { get; set; }
public KdfNumberParamPreference(Context context, IAttributeSet attrs):base(context, attrs) {
}
public RoundsPreference(Context context, IAttributeSet attrs, int defStyle): base(context, attrs, defStyle) {
public KdfNumberParamPreference(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
}
protected override void OnDialogClosed(bool positiveResult) {
base.OnDialogClosed(positiveResult);
if ( positiveResult ) {
ulong rounds;
ulong paramValue;
String strRounds = RoundsView.Text;
if (!(ulong.TryParse(strRounds,out rounds)))
String strRounds = edittext.Text;
if (!(ulong.TryParse(strRounds,out paramValue)))
{
Toast.MakeText(Context, Resource.String.error_rounds_not_number, ToastLength.Long).Show();
Toast.MakeText(Context, Resource.String.error_param_not_number, ToastLength.Long).Show();
return;
}
if ( rounds < 1 ) {
rounds = 1;
if ( paramValue < 1 ) {
paramValue = 1;
}
Database db = App.Kp2a.GetDb();
ulong oldRounds = KeyEncryptionRounds;
ulong oldValue = ParamValue;
if (oldRounds == rounds)
if (oldValue == paramValue)
{
return;
}
KeyEncryptionRounds = rounds;
ParamValue = paramValue;
Handler handler = new Handler();
SaveDb save = new SaveDb(Context, App.Kp2a, new AfterSave(Context, handler, oldRounds, this));
SaveDb save = new SaveDb(Context, App.Kp2a, new KdfNumberParamPreference.AfterSave(Context, handler, oldValue, this));
ProgressTask pt = new ProgressTask(App.Kp2a, Context, save);
pt.Run();
@ -111,9 +99,9 @@ namespace keepass2android.settings
private class AfterSave : OnFinish {
private readonly ulong _oldRounds;
private readonly Context _ctx;
private readonly RoundsPreference _pref;
private readonly KdfNumberParamPreference _pref;
public AfterSave(Context ctx, Handler handler, ulong oldRounds, RoundsPreference pref):base(handler) {
public AfterSave(Context ctx, Handler handler, ulong oldRounds, KdfNumberParamPreference pref):base(handler) {
_pref = pref;
_ctx = ctx;
@ -139,5 +127,54 @@ namespace keepass2android.settings
}
/// <summary>
/// Represents the setting for the number of key transformation rounds. Changing this requires to save the database.
/// </summary>
public class RoundsPreference : KdfNumberParamPreference {
private readonly Context _context;
public ulong KeyEncryptionRounds
{
get
{
AesKdf kdf = new AesKdf();
if (!kdf.Uuid.Equals(App.Kp2a.GetDb().KpDatabase.KdfParameters.KdfUuid))
return (uint) PwDefs.DefaultKeyEncryptionRounds;
else
{
ulong uRounds = App.Kp2a.GetDb().KpDatabase.KdfParameters.GetUInt64(
AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds);
uRounds = Math.Min(uRounds, 0xFFFFFFFEUL);
return (uint) uRounds;
}
}
set { App.Kp2a.GetDb().KpDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, value); }
}
public RoundsPreference(Context context, IAttributeSet attrs):base(context, attrs)
{
_context = context;
}
public RoundsPreference(Context context, IAttributeSet attrs, int defStyle): base(context, attrs, defStyle)
{
_context = context;
}
public override string ExplanationString
{
get { return _context.GetString(Resource.String.rounds_explaination); }
}
public override ulong ParamValue
{
get { return KeyEncryptionRounds; }
set { KeyEncryptionRounds = value; }
}
}
}