From 8512bae997392a8124aedd956bba8bd4fcac2c2b Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Tue, 20 Nov 2018 06:08:30 +0100 Subject: [PATCH] make sure we always save database as KDBX4 when using ChallengeXCKey (for compatibility with KeepassXC), closes #596 --- src/KeePassLib2Android/Keys/IUserKey.cs | 10 +++++--- src/KeePassLib2Android/Keys/KcpCustomKey.cs | 7 +++++- src/KeePassLib2Android/Keys/KcpKeyFile.cs | 7 +++++- src/KeePassLib2Android/Keys/KcpPassword.cs | 7 +++++- src/KeePassLib2Android/Keys/KcpUserAccount.cs | 7 +++++- .../Serialization/KdbxFile.cs | 25 +++++++++++-------- src/keepass2android/ChallengeXCKey.cs | 6 +++++ 7 files changed, 51 insertions(+), 18 deletions(-) diff --git a/src/KeePassLib2Android/Keys/IUserKey.cs b/src/KeePassLib2Android/Keys/IUserKey.cs index d4739bb2..3f7af817 100644 --- a/src/KeePassLib2Android/Keys/IUserKey.cs +++ b/src/KeePassLib2Android/Keys/IUserKey.cs @@ -38,9 +38,11 @@ namespace KeePassLib.Keys get; } - // /// - // /// Clear the key and securely erase all security-critical information. - // /// - // void Clear(); + // /// + // /// Clear the key and securely erase all security-critical information. + // /// + // void Clear(); + + uint GetMinKdbxVersion(); } } diff --git a/src/KeePassLib2Android/Keys/KcpCustomKey.cs b/src/KeePassLib2Android/Keys/KcpCustomKey.cs index 9f5deb96..fc26e24a 100644 --- a/src/KeePassLib2Android/Keys/KcpCustomKey.cs +++ b/src/KeePassLib2Android/Keys/KcpCustomKey.cs @@ -45,7 +45,12 @@ namespace KeePassLib.Keys get { return m_pbKey; } } - public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash) + public uint GetMinKdbxVersion() + { + return 0; + } + + public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash) { Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); diff --git a/src/KeePassLib2Android/Keys/KcpKeyFile.cs b/src/KeePassLib2Android/Keys/KcpKeyFile.cs index 68abb84a..e5ef2b07 100644 --- a/src/KeePassLib2Android/Keys/KcpKeyFile.cs +++ b/src/KeePassLib2Android/Keys/KcpKeyFile.cs @@ -64,7 +64,12 @@ namespace KeePassLib.Keys get { return m_pbKeyData; } } - public IOConnectionInfo Ioc + public uint GetMinKdbxVersion() + { + return 0; + } + + public IOConnectionInfo Ioc { get { return m_ioc; } } diff --git a/src/KeePassLib2Android/Keys/KcpPassword.cs b/src/KeePassLib2Android/Keys/KcpPassword.cs index f1627784..ac0be666 100644 --- a/src/KeePassLib2Android/Keys/KcpPassword.cs +++ b/src/KeePassLib2Android/Keys/KcpPassword.cs @@ -53,7 +53,12 @@ namespace KeePassLib.Keys get { return m_pbKeyData; } } - public KcpPassword(byte[] pbPasswordUtf8) + public uint GetMinKdbxVersion() + { + return 0; + } + + public KcpPassword(byte[] pbPasswordUtf8) { SetKey(pbPasswordUtf8); } diff --git a/src/KeePassLib2Android/Keys/KcpUserAccount.cs b/src/KeePassLib2Android/Keys/KcpUserAccount.cs index 39079b80..529af0aa 100644 --- a/src/KeePassLib2Android/Keys/KcpUserAccount.cs +++ b/src/KeePassLib2Android/Keys/KcpUserAccount.cs @@ -60,7 +60,12 @@ namespace KeePassLib.Keys get { return m_pbKeyData; } } - /// + public uint GetMinKdbxVersion() + { + return 0; + } + + /// /// Construct a user account key. /// public KcpUserAccount() diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.cs b/src/KeePassLib2Android/Serialization/KdbxFile.cs index e61e2632..4a4e3a33 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.cs @@ -23,6 +23,7 @@ using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; +using System.Linq; using System.Security; using System.Text; using System.Xml; @@ -126,8 +127,8 @@ namespace KeePassLib.Serialization /// private const uint FileVersion32 = 0x00040000; - internal const uint FileVersion32_4 = 0x00040000; // First of 4.x series - internal const uint FileVersion32_3 = 0x00030001; // Old format 3.1 + public const uint FileVersion32_4 = 0x00040000; // First of 4.x series + public const uint FileVersion32_3 = 0x00030001; // Old format 3.1 private const uint FileVersionCriticalMask = 0xFFFF0000; @@ -372,16 +373,19 @@ namespace KeePassLib.Serialization { if(m_uForceVersion != 0) return m_uForceVersion; - // See also KeePassKdb2x3.Export (KDBX 3.1 export module) - - AesKdf kdfAes = new AesKdf(); + // See also KeePassKdb2x3.Export (KDBX 3.1 export module) + uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max(); + + AesKdf kdfAes = new AesKdf(); if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) - return FileVersion32; + return Math.Max(FileVersion32, minVersionForKeys); if(m_pwDatabase.PublicCustomData.Count > 0) - return FileVersion32; + return Math.Max(FileVersion32, minVersionForKeys); - bool bCustomData = false; + + + bool bCustomData = false; GroupHandler gh = delegate(PwGroup pg) { if(pg == null) { Debug.Assert(false); return true; } @@ -396,9 +400,10 @@ namespace KeePassLib.Serialization }; gh(m_pwDatabase.RootGroup); m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); - if(bCustomData) return FileVersion32; + if(bCustomData) + return Math.Max(FileVersion32, minVersionForKeys); - return FileVersion32_3; // KDBX 3.1 is sufficient + return Math.Max(FileVersion32_3, minVersionForKeys); ; // KDBX 3.1 is sufficient } private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey, diff --git a/src/keepass2android/ChallengeXCKey.cs b/src/keepass2android/ChallengeXCKey.cs index 72a469ea..8303cfe5 100644 --- a/src/keepass2android/ChallengeXCKey.cs +++ b/src/keepass2android/ChallengeXCKey.cs @@ -2,6 +2,7 @@ using Java.Lang; using KeePassLib.Cryptography; using KeePassLib.Keys; using KeePassLib.Security; +using KeePassLib.Serialization; using Exception = System.Exception; namespace keepass2android @@ -62,6 +63,11 @@ namespace keepass2android } } + public uint GetMinKdbxVersion() + { + return KdbxFile.FileVersion32_4; + } + private byte[] _kdfSeed; public ChallengeXCKey(LockingActivity activity, int requestCode)