From aa810038236d79d9e4e510270d84190566dc43f8 Mon Sep 17 00:00:00 2001 From: Philipp Crocoll Date: Wed, 13 Nov 2013 03:28:18 +0100 Subject: [PATCH] update to 2.24 --- .../Collections/PwObjectList.cs | 10 +- .../Collections/PwObjectPool.cs | 16 +- .../Cryptography/Cipher/CipherPool.cs | 9 +- .../Cryptography/Cipher/StandardAesEngine.cs | 43 +- .../Cryptography/CryptoRandom.cs | 24 +- .../Cryptography/HashingStreamEx.cs | 8 +- .../Cryptography/HmacOtp.cs | 8 +- .../CustomPwGeneratorPool.cs | 6 +- .../Cryptography/PopularPasswords.cs | 568 ++----------- .../Cryptography/QualityEstimation.cs | 767 ++++++++++++++++-- .../Cryptography/SelfTest.cs | 90 +- src/KeePassLib2Android/Keys/CompositeKey.cs | 47 +- src/KeePassLib2Android/Keys/KcpKeyFile.cs | 46 +- src/KeePassLib2Android/Keys/KcpUserAccount.cs | 6 +- src/KeePassLib2Android/Native/NativeLib.cs | 116 ++- .../Native/NativeMethods.cs | 12 +- .../Properties/AssemblyInfo.cs | 8 +- src/KeePassLib2Android/PwCustomIcon.cs | 6 +- src/KeePassLib2Android/PwDatabase.cs | 115 ++- src/KeePassLib2Android/PwDefs.cs | 37 +- src/KeePassLib2Android/PwEntry.cs | 20 +- src/KeePassLib2Android/PwEnums.cs | 62 +- src/KeePassLib2Android/PwGroup.cs | 60 +- src/KeePassLib2Android/PwUuid.cs | 128 +-- .../Resources/KLRes.Generated.cs | 13 + .../Serialization/BinaryReaderEx.cs | 6 +- .../Serialization/FileLock.cs | 4 +- .../Serialization/FileTransactionEx.cs | 18 +- .../Serialization/HashedBlockStream.cs | 8 +- .../Serialization/IOConnection.cs | 86 +- .../Serialization/IOConnectionInfo.cs | 37 +- .../Serialization/KdbxFile.Read.Streamed.cs | 24 +- .../Serialization/KdbxFile.Read.cs | 18 +- .../Serialization/KdbxFile.Write.cs | 26 +- .../Serialization/KdbxFile.cs | 21 +- .../Translation/KPControlCustomization.cs | 14 +- .../Translation/KPFormCustomization.cs | 4 +- .../Translation/KPStringTable.cs | 4 +- .../Translation/KPTranslation.cs | 4 +- src/KeePassLib2Android/Utility/AppLogEx.cs | 6 +- src/KeePassLib2Android/Utility/GfxUtil.cs | 11 +- src/KeePassLib2Android/Utility/MemUtil.cs | 167 +++- .../Utility/MessageService.cs | 28 +- src/KeePassLib2Android/Utility/StrUtil.cs | 342 ++++++-- src/KeePassLib2Android/Utility/TimeUtil.cs | 43 +- src/KeePassLib2Android/Utility/UrlUtil.cs | 152 +++- 46 files changed, 2278 insertions(+), 970 deletions(-) diff --git a/src/KeePassLib2Android/Collections/PwObjectList.cs b/src/KeePassLib2Android/Collections/PwObjectList.cs index afd6fcd8..4f324a5a 100644 --- a/src/KeePassLib2Android/Collections/PwObjectList.cs +++ b/src/KeePassLib2Android/Collections/PwObjectList.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -133,6 +133,14 @@ namespace KeePassLib.Collections } } + public void Insert(uint uIndex, T pwObject) + { + Debug.Assert(pwObject != null); + if(pwObject == null) throw new ArgumentNullException("pwObject"); + + m_vObjects.Insert((int)uIndex, pwObject); + } + /// /// Get an object of the list. /// diff --git a/src/KeePassLib2Android/Collections/PwObjectPool.cs b/src/KeePassLib2Android/Collections/PwObjectPool.cs index 90c980b8..df37f524 100644 --- a/src/KeePassLib2Android/Collections/PwObjectPool.cs +++ b/src/KeePassLib2Android/Collections/PwObjectPool.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -33,8 +33,8 @@ namespace KeePassLib.Collections { public sealed class PwObjectPool { - private SortedDictionary m_dict = - new SortedDictionary(); + private SortedDictionary m_dict = + new SortedDictionary(); public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries) { @@ -42,16 +42,16 @@ namespace KeePassLib.Collections PwObjectPool p = new PwObjectPool(); - if(!bEntries) p.m_dict[new PwUuidComparable(pgRoot.Uuid)] = pgRoot; + if(!bEntries) p.m_dict[pgRoot.Uuid] = pgRoot; GroupHandler gh = delegate(PwGroup pg) { - p.m_dict[new PwUuidComparable(pg.Uuid)] = pg; + p.m_dict[pg.Uuid] = pg; return true; }; EntryHandler eh = delegate(PwEntry pe) { - p.m_dict[new PwUuidComparable(pe.Uuid)] = pe; + p.m_dict[pe.Uuid] = pe; return true; }; @@ -63,13 +63,13 @@ namespace KeePassLib.Collections public IStructureItem Get(PwUuid pwUuid) { IStructureItem pItem; - m_dict.TryGetValue(new PwUuidComparable(pwUuid), out pItem); + m_dict.TryGetValue(pwUuid, out pItem); return pItem; } public bool ContainsOnlyType(Type t) { - foreach(KeyValuePair kvp in m_dict) + foreach(KeyValuePair kvp in m_dict) { if(kvp.Value.GetType() != t) return false; } diff --git a/src/KeePassLib2Android/Cryptography/Cipher/CipherPool.cs b/src/KeePassLib2Android/Cryptography/Cipher/CipherPool.cs index 0367151c..cda14f64 100644 --- a/src/KeePassLib2Android/Cryptography/Cipher/CipherPool.cs +++ b/src/KeePassLib2Android/Cryptography/Cipher/CipherPool.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -23,7 +23,6 @@ using System.Text; using System.IO; using System.Diagnostics; using System.Security; -using System.Security.Cryptography; namespace KeePassLib.Cryptography.Cipher { @@ -70,7 +69,7 @@ namespace KeePassLib.Cryptography.Cipher // Return if a cipher with that ID is registered already. for(int i = 0; i < m_vCiphers.Count; ++i) - if(m_vCiphers[i].CipherUuid.EqualsValue(csEngine.CipherUuid)) + if(m_vCiphers[i].CipherUuid.Equals(csEngine.CipherUuid)) return; m_vCiphers.Add(csEngine); @@ -86,7 +85,7 @@ namespace KeePassLib.Cryptography.Cipher { foreach(ICipherEngine iEngine in m_vCiphers) { - if(iEngine.CipherUuid.EqualsValue(uuidCipher)) + if(iEngine.CipherUuid.Equals(uuidCipher)) return iEngine; } @@ -104,7 +103,7 @@ namespace KeePassLib.Cryptography.Cipher { for(int i = 0; i < m_vCiphers.Count; ++i) { - if(m_vCiphers[i].CipherUuid.EqualsValue(uuidCipher)) + if(m_vCiphers[i].CipherUuid.Equals(uuidCipher)) return i; } diff --git a/src/KeePassLib2Android/Cryptography/Cipher/StandardAesEngine.cs b/src/KeePassLib2Android/Cryptography/Cipher/StandardAesEngine.cs index 0bf442b7..b0b9b7b7 100644 --- a/src/KeePassLib2Android/Cryptography/Cipher/StandardAesEngine.cs +++ b/src/KeePassLib2Android/Cryptography/Cipher/StandardAesEngine.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -22,9 +22,19 @@ using System.Collections.Generic; using System.Text; using System.IO; using System.Security; -using System.Security.Cryptography; using System.Diagnostics; +#if !KeePassRT +using System.Security.Cryptography; +#else +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Modes; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Crypto.Parameters; +#endif + using KeePassLib.Resources; namespace KeePassLib.Cryptography.Cipher @@ -34,8 +44,10 @@ namespace KeePassLib.Cryptography.Cipher /// public sealed class StandardAesEngine : ICipherEngine { +#if !KeePassRT private const CipherMode m_rCipherMode = CipherMode.CBC; private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7; +#endif private static PwUuid m_uuidAes = null; @@ -99,23 +111,23 @@ namespace KeePassLib.Cryptography.Cipher { StandardAesEngine.ValidateArguments(s, bEncrypt, pbKey, pbIV); - RijndaelManaged r = new RijndaelManaged(); + byte[] pbLocalIV = new byte[16]; + Array.Copy(pbIV, pbLocalIV, 16); + byte[] pbLocalKey = new byte[32]; + Array.Copy(pbKey, pbLocalKey, 32); + +#if !KeePassRT + RijndaelManaged r = new RijndaelManaged(); if(r.BlockSize != 128) // AES block size { Debug.Assert(false); r.BlockSize = 128; } - byte[] pbLocalIV = new byte[16]; - Array.Copy(pbIV, pbLocalIV, 16); r.IV = pbLocalIV; - - byte[] pbLocalKey = new byte[32]; - Array.Copy(pbKey, pbLocalKey, 32); r.KeySize = 256; r.Key = pbLocalKey; - r.Mode = m_rCipherMode; r.Padding = m_rCipherPadding; @@ -125,6 +137,19 @@ namespace KeePassLib.Cryptography.Cipher return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write : CryptoStreamMode.Read); +#else + AesEngine aes = new AesEngine(); + CbcBlockCipher cbc = new CbcBlockCipher(aes); + PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(cbc, + new Pkcs7Padding()); + KeyParameter kp = new KeyParameter(pbLocalKey); + ParametersWithIV prmIV = new ParametersWithIV(kp, pbLocalIV); + bc.Init(bEncrypt, prmIV); + + IBufferedCipher cpRead = (bEncrypt ? null : bc); + IBufferedCipher cpWrite = (bEncrypt ? bc : null); + return new CipherStream(s, cpRead, cpWrite); +#endif } public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV) diff --git a/src/KeePassLib2Android/Cryptography/CryptoRandom.cs b/src/KeePassLib2Android/Cryptography/CryptoRandom.cs index 1cd1523e..4910b23c 100644 --- a/src/KeePassLib2Android/Cryptography/CryptoRandom.cs +++ b/src/KeePassLib2Android/Cryptography/CryptoRandom.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -137,12 +137,18 @@ namespace KeePassLib.Cryptography pb = TimeUtil.PackTime(DateTime.Now); ms.Write(pb, 0, pb.Length); -#if !KeePassLibSD - Point pt = Cursor.Position; - pb = MemUtil.UInt32ToBytes((uint)pt.X); - ms.Write(pb, 0, pb.Length); - pb = MemUtil.UInt32ToBytes((uint)pt.Y); - ms.Write(pb, 0, pb.Length); +#if (!KeePassLibSD && !KeePassRT) + // In try-catch for systems without GUI; + // https://sourceforge.net/p/keepass/discussion/329221/thread/20335b73/ + try + { + Point pt = Cursor.Position; + pb = MemUtil.UInt32ToBytes((uint)pt.X); + ms.Write(pb, 0, pb.Length); + pb = MemUtil.UInt32ToBytes((uint)pt.Y); + ms.Write(pb, 0, pb.Length); + } + catch(Exception) { } #endif pb = MemUtil.UInt32ToBytes((uint)rWeak.Next()); @@ -151,7 +157,7 @@ namespace KeePassLib.Cryptography pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); ms.Write(pb, 0, pb.Length); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) try { pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount); @@ -266,7 +272,7 @@ namespace KeePassLib.Cryptography long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy); #else Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy); diff --git a/src/KeePassLib2Android/Cryptography/HashingStreamEx.cs b/src/KeePassLib2Android/Cryptography/HashingStreamEx.cs index f900b15e..b96d4e6c 100644 --- a/src/KeePassLib2Android/Cryptography/HashingStreamEx.cs +++ b/src/KeePassLib2Android/Cryptography/HashingStreamEx.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -102,8 +102,14 @@ namespace KeePassLib.Cryptography m_sBaseStream.Flush(); } +#if KeePassRT + protected override void Dispose(bool disposing) + { + if(!disposing) return; +#else public override void Close() { +#endif if(m_hash != null) { try diff --git a/src/KeePassLib2Android/Cryptography/HmacOtp.cs b/src/KeePassLib2Android/Cryptography/HmacOtp.cs index 42409280..17b4d58e 100644 --- a/src/KeePassLib2Android/Cryptography/HmacOtp.cs +++ b/src/KeePassLib2Android/Cryptography/HmacOtp.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -21,10 +21,11 @@ using System; using System.Collections.Generic; using System.Text; using System.Security.Cryptography; +using System.Globalization; using KeePassLib.Utility; -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) namespace KeePassLib.Cryptography { /// @@ -58,7 +59,8 @@ namespace KeePassLib.Cryptography uOtp = ((uOtp * 10) + CalculateChecksum(uOtp, uCodeDigits)); uint uDigits = (bAddChecksum ? (uCodeDigits + 1) : uCodeDigits); - return uOtp.ToString().PadLeft((int)uDigits, '0'); + return uOtp.ToString(NumberFormatInfo.InvariantInfo).PadLeft( + (int)uDigits, '0'); } private static readonly uint[] vDoubleDigits = new uint[]{ 0, 2, 4, 6, 8, diff --git a/src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs b/src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs index c3cf9c1e..504e9bc3 100644 --- a/src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs +++ b/src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -66,7 +66,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator foreach(CustomPwGenerator pwg in m_vGens) { - if(uuid.EqualsValue(pwg.Uuid)) return pwg; + if(uuid.Equals(pwg.Uuid)) return pwg; } return null; @@ -90,7 +90,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator for(int i = 0; i < m_vGens.Count; ++i) { - if(uuid.EqualsValue(m_vGens[i].Uuid)) return i; + if(uuid.Equals(m_vGens[i].Uuid)) return i; } return -1; diff --git a/src/KeePassLib2Android/Cryptography/PopularPasswords.cs b/src/KeePassLib2Android/Cryptography/PopularPasswords.cs index 7e4a70f1..ca80a200 100644 --- a/src/KeePassLib2Android/Cryptography/PopularPasswords.cs +++ b/src/KeePassLib2Android/Cryptography/PopularPasswords.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -20,521 +20,115 @@ using System; using System.Collections.Generic; using System.Text; -using System.IO; -using System.Security.Cryptography; -using System.Globalization; using System.Diagnostics; using KeePassLib.Utility; -#if !KeePassLibSD namespace KeePassLib.Cryptography { - /// - /// Bloom filter-based popular password checking. - /// public static class PopularPasswords { - private const int PpcTableSize = 8192 * 8; // Bits, multiple of 64 + private static Dictionary> m_dicts = + new Dictionary>(); - // Bits set: 32433 of 65536 - // Hash functions: 32 - // Phi (bits unset ratio) estimation: 0.505455388896019 - // Exact Phi: 0.505111694335938 - // False positives ratio: 1.67583063859565E-10 - private static readonly ulong[] PpcTable = { - 0x60383D3A85560B9BUL, 0x2578CE9D37C6AEB7UL, 0xF509A5743FD03228UL, - 0x19B7455E8933EE56UL, 0x5EA419ADCFD9C20EUL, 0xEA618EFC0B37A162UL, - 0xE0FD4D1FFF1CE415UL, 0x7A649E0301BB6060UL, 0x80D9CD9F9EEB603DUL, - 0x47D6010D0D6E6CDEUL, 0x2552708C589EB554UL, 0x073F1A3DB3267502UL, - 0x3313FEC2A2FEA475UL, 0x4593665C44934FEBUL, 0x410A301A23660395UL, - 0x6AD06DA533FF5659UL, 0x423DAF86F3E41F4AUL, 0x82F035A971C6FD18UL, - 0xB5E9139F28C93223UL, 0x1D07C3F4160585CAUL, 0x24B01EDB6B23E2C5UL, - 0xD52F25B724F936C9UL, 0x8018392517836928UL, 0x3AA4C0F8E181EDA2UL, - 0x8D93683EF7D52529UL, 0x6164BB6208114460UL, 0x737A04D8FEF3D88FUL, - 0x3400097098D5C2CBUL, 0x3C2B9ABE5C455B2EUL, 0x3A3819973AB32DA2UL, - 0x38ACB428510AF40BUL, 0x83320D5114B74771UL, 0xC25BEC333B90DCD1UL, - 0x0E9F412FBA3813D1UL, 0x047E31E3098EB2B8UL, 0xBB686AC643F1741FUL, - 0x0BE22E9C0EF0E8F2UL, 0x65AA9504E5F40D31UL, 0xE018DF5D64C62AC7UL, - 0x17020E9A7EFA12EDUL, 0xFC12A7C16006DE82UL, 0x8DE4747E3745346DUL, - 0x31D8C051A43CECAFUL, 0xBE9AFBEF127C1B12UL, 0xAEE94B4B808BBEE2UL, - 0x3A0099CA32835B41UL, 0x59EB3173468D8C49UL, 0x6F89DB1E6DAAE9E1UL, - 0x4C1ADAA837E968E4UL, 0x6E3593A56C682769UL, 0x022AD591689B5B82UL, - 0x4AC33861ED978032UL, 0xF6F476E4E6A1318DUL, 0x2DA690A11AA05A23UL, - 0x916FC56378C29D77UL, 0xAB3238BE22294659UL, 0x2D73A29019B28C77UL, - 0xAAF26C12EC9C3C42UL, 0x058A278A24B334F9UL, 0x033BD18FB8D9BACDUL, - 0x8B3833596008B07CUL, 0x280B6D093333E5E5UL, 0x2128DBE126CA3E1EUL, - 0xCCF09769382472D8UL, 0x0CB6E495BD90CED6UL, 0x1303A37577C01C5AUL, - 0xC8BBF4734FC34C53UL, 0x1B38B72B10F86CD5UL, 0x5098E2D6C1892E51UL, - 0x2DD8065B79DB5380UL, 0x5B9A1A6D6A2292B7UL, 0xC70F751604D0497CUL, - 0x911E08D7363B5213UL, 0x9F2E245273308D2EUL, 0x64D354827957F50EUL, - 0x09856750F560342CUL, 0xDE091F26603F0E70UL, 0xDDE6B4E76173E3B1UL, - 0xC1584AE1B26FA08EUL, 0x1EA29887837838D2UL, 0x6D7643FC67B15C54UL, - 0x921E60571ED103EAUL, 0x63EB1EB33E7AFFF1UL, 0x80BA4D1F95BFD615UL, - 0xEC8A1D4FC1A6B8E0UL, 0x2C46861B6DB17D1AUL, 0x01F05D06927E443BUL, - 0x6172EC2EABEAD454UL, 0x21B8726C6F7C4102UL, 0x3C016CD9945C72ECUL, - 0x708F77B2C0E8B665UL, 0xFC35BE2BB88974DAUL, 0x805897A33702BD61UL, - 0x9A93367A6041226CUL, 0xFDAB188B6158F6BEUL, 0x5F21014A065E918CUL, - 0xF4381DD77772D19CUL, 0xC664B6358AA85011UL, 0xF2639D7B3E2307E6UL, - 0x3FA000D4A5A9C37AUL, 0x8F45D116ED8DC70FUL, 0x8CB8758E45C140D0UL, - 0x49832B46D716236DUL, 0xCC8E4961A93065B8UL, 0x8A996533EDACEB0EUL, - 0x15B35155EC56FAC1UL, 0xE7E0C6C05A9F1885UL, 0x05914F9A1D1C79F9UL, - 0x730000A30B6725F0UL, 0xC95E671F8E543780UL, 0x47D68382400AF94EUL, - 0x1A27F2734FE2249AUL, 0x828079C332D9C0ABUL, 0x2E9BC798EA09170EUL, - 0x6B7CDAC829018C91UL, 0x7B89604901736993UL, 0xABE4EB26F47608F0UL, - 0x70D5FDC88A0FF1B1UL, 0x5A1F0BAB9AB8A158UL, 0xDC89AE0A735C51A4UL, - 0x36C1EA01E9C89B84UL, 0x3A9757AF204096DBUL, 0x1D56C8328540F963UL, - 0x910A8694692472FAUL, 0x697192C9DF145604UL, 0xB20F7A4438712AA2UL, - 0xE8C99185243F4896UL, 0xFBC8970EDBC39CA7UL, 0x33485403868C3761UL, - 0xAFA97DDEDB1D6AD8UL, 0x54A1A6F24476A3BBUL, 0xFE4E078B184BDB7FUL, - 0x5ED1543919754CD8UL, 0x86F8C775160FC08CUL, 0x9B4098F57019040DUL, - 0x039518BBE841327BUL, 0x111D0D420A3F5F6AUL, 0x0666067346AF34ACUL, - 0xD43F1D14EB239B9BUL, 0xA6BB91FEB5618F5BUL, 0xA2B5218B202409ADUL, - 0xC004FA688C3AC25EUL, 0xF0E2D9EA2935E1DCUL, 0x380B31CFA2F2AF43UL, - 0x50E050AE426250EAUL, 0x628ED94D1AA8F55BUL, 0xF8EB0654F0166311UL, - 0x1F8858D26DDA5CC5UL, 0x931425D11CB1EFEBUL, 0xF661D461DC1A05D3UL, - 0x7B75ED7EC6936DA8UL, 0x8713C59690985202UL, 0xF61D6F93F07C0E85UL, - 0xFD1771F6711D6F4FUL, 0x5835A67E1B11419FUL, 0x33EF08ABD56A1050UL, - 0x55B5D0043FA2C01CUL, 0x53316ED963B92D9DUL, 0x6A8C93744E521EDBUL, - 0x083E948062EB9543UL, 0x1C15289B3189AFB1UL, 0xA6A0A5053AE2212DUL, - 0x6573AF7F01FAFF3BUL, 0x58B6F034CFCFE843UL, 0xEB2837CA5AEA6AEDUL, - 0x633E7897097AC328UL, 0x7FA91789B6CCEE82UL, 0xBEE2402F4E7D65EEUL, - 0x616A103EC8FB0DBEUL, 0x65991F9FB25E13FCUL, 0x54EA8A3FADEC1F4BUL, - 0x6D497C5ACDEA0E7AUL, 0x5865045E8CA18527UL, 0xA406C09215ABD61FUL, - 0x68F81F5745FC9875UL, 0xE496D850CEFF3FA9UL, 0xD225C88D63212CB1UL, - 0x37676390525116D2UL, 0x415614AB14188A7DUL, 0xABE58EBC1F6DDC63UL, - 0xDE10312B2C25D28CUL, 0x86C86D7A0B847635UL, 0x408B511D584DC3DCUL, - 0x6711FCC14B303FEDUL, 0x1284DF9CC6972023UL, 0xC3CE0B33141BFA8FUL, - 0x0F3F58367D4A1819UL, 0x9313F83058FBE6D0UL, 0x6FCA5EF39B8E2F47UL, - 0xA90F5C95D887756DUL, 0x96C4E2AD85D5AF6EUL, 0x0ED68A81F526F0A0UL, - 0x53E4472DB4255A35UL, 0xAC581015134D58A6UL, 0x12C000D85C644FC7UL, - 0x124D489B2C0FE6E4UL, 0x8FF83531C6F5D61AUL, 0x132BD6488304F73BUL, - 0x110E99BC59604CB9UL, 0xC28186ACBC940C9BUL, 0x2094C07F48141230UL, - 0x65FB9881A5053589UL, 0x940A3E6D72F09D69UL, 0x972A922CB14BA66EUL, - 0x8D07E59C6DDD4327UL, 0xCB67F993F820157CUL, 0x65B7A54E5FB2ED6CUL, - 0xC235828849576653UL, 0xA695F85479467538UL, 0x9E2BA885E63C4243UL, - 0xDE64A6A5EF84C222UL, 0xC2AB9AF302080621UL, 0x88DBA09B87FA0734UL, - 0xDF002765B44D02E1UL, 0xD50D8D90587CD820UL, 0x1B68B70ED179EFE1UL, - 0xD6E77F8EC26AE95CUL, 0xEE57EB7C45051872UL, 0x4D2B445F36A7F9FDUL, - 0x5502ABB8BB14D7F1UL, 0xAF2C0DF0406FA901UL, 0x6522833444BF4A83UL, - 0xD7CB2E3FC691BE8DUL, 0x4F36F70D2E80D19AUL, 0xF6945FE911D4923BUL, - 0xE3C6FE1EA47399C1UL, 0xF09EA1B2F837702CUL, 0x5122537CF97B5CB5UL, - 0x0C8202B70E9BF154UL, 0x68B554AB58EB5E68UL, 0x7BF9B8052C9BEADEUL, - 0x33612BFCD303810DUL, 0x03E38CF67B37DC53UL, 0x2BFDFF8691F37D5CUL, - 0x4AB483D1CB1D07F6UL, 0xF071A58640639A5CUL, 0x9D6B98169B745CE1UL, - 0x5F42D3E870FDCD93UL, 0x4EDF04404F258238UL, 0x2EAB6E10D65C9BB3UL, - 0x5BB71411EF78DAD2UL, 0x0DE8128636A5D689UL, 0x18FDD1F484DC9365UL, - 0x9896B8896941DA5BUL, 0x8BEF8E3BA4448E5FUL, 0x963A1E977CB1D2CAUL, - 0x02BCF5F068D52851UL, 0x0CD783F09BFBE381UL, 0x350DA833D8C5DB47UL, - 0x8D444C914D795C43UL, 0x8A00B4DFC44D9476UL, 0x4B36CBEC089E55FDUL, - 0xD9D2FA1B0AC66211UL, 0x6C7FC30FA31A8B60UL, 0x9EF4504CC985AD6BUL, - 0x8F2E7E5E0C00EE73UL, 0x819131CFEEBEA069UL, 0xB1E406A863E7A1B4UL, - 0x501F072FF1F2AB67UL, 0xDE578BFC5ADBC264UL, 0xCDD66A09C8E13881UL, - 0x4D443460CE52957FUL, 0x3B198C267976ECFAUL, 0x6B98323D8BD26522UL, - 0x80161F6A489E4BF8UL, 0xE03A8AFCC7AE6872UL, 0x2484BD95A305AB27UL, - 0x6ADDAA46BF25DD0EUL, 0xA429D8B00100477CUL, 0x55AEDB88A074BF2CUL, - 0x63D9F9021AB8F5F3UL, 0x37858538A10C265CUL, 0xEF54C2CE9D063149UL, - 0xFA5CE5AF33E2C136UL, 0xE601A559D0C391D7UL, 0x7C4ED29BBF57DC7EUL, - 0x8FD0D4146DE9E900UL, 0xB58ABFA6CE6C0733UL, 0xF8D7F7743B33EAFFUL, - 0x453FA782F454643CUL, 0xD01752C21AF21E66UL, 0xA50BB7913EAF05DFUL, - 0x966D5B140B2F4189UL, 0x956F5638AFF3D148UL, 0x93FAA838420E8AB3UL, - 0x715E26043071EABDUL, 0x01E7B458B5FD3A41UL, 0x5CFA99C4CC0492AAUL, - 0x761FD391C3623044UL, 0xD39E44E9DB96B5BCUL, 0x8806C544F0534A07UL, - 0x9B225CAFE97EAAC1UL, 0xEAE5E18583492767UL, 0x6B4E51E4C297F096UL, - 0xFC512662EF47E41DUL, 0xB6AC60427DB46F8BUL, 0x8F137F3DB4429C9DUL, - 0x04C65FBEAE9FD8D0UL, 0xEB72305958AE5022UL, 0xAA93AA14BCA2961EUL, - 0x6C7547F9456CA37AUL, 0xEE6094871615BA34UL, 0x489BC8EDE0940402UL, - 0x1108AEFAAD892229UL, 0x673B8B1CF6BED23EUL, 0xFDB781A75FD94DEAUL, - 0x11D9E0F5D914A7BEUL, 0x02830D07F018143DUL, 0x9B3163B8188FD2BAUL, - 0x32C1BEC97D06117EUL, 0x697268B761240CFFUL, 0xBD89CE3037C2E7A9UL, - 0xF21C158125B19600UL, 0x632CB1931601B70AUL, 0x7BB3FB131338085CUL, - 0xA9C06689B8138384UL, 0x161CCBF83EBDC2A1UL, 0x2CF83C01A80B7935UL, - 0x9E51FE393B8E2FF0UL, 0xFE96E52B1606C1A7UL, 0x5E20DFB87F81ACCEUL, - 0xF95DB9602CDAE467UL, 0xDEA155CD35555FEBUL, 0xF0669B810F70CDC6UL, - 0xD36C2FBEB6A449ACUL, 0xCE500C6621C0A445UL, 0x41308909E366460AUL, - 0xAC4D8178DA0CEC24UL, 0xC69049179ED09F7DUL, 0x36B608A0BA2FD848UL, - 0xDF511894DD9568B4UL, 0xB3BFDF78EC861A6CUL, 0xCD50F39D19848153UL, - 0xD2C1BC57E78A408CUL, 0x1E6613EFBB11B5EBUL, 0xF58E30D2D90F73D3UL, - 0xCCB5E2F5E168D742UL, 0xEE97259469BDB672UL, 0x6784D35AF65935A8UL, - 0x71032765ADED1FE8UL, 0x4BBF2FE54D9B72E3UL, 0x5A1BB7831E876A05UL, - 0x12A8FC949EE91686UL, 0x8296F8FA83BD112CUL, 0xAAA7E3BFF64D34D5UL, - 0x0301655E1794EE4BUL, 0x1E547C011BBF30E1UL, 0x39D74FEC536F31D6UL, - 0x3C31A7478B1815BAUL, 0x525C774F82D5836EUL, 0xECF7186DC612FD8CUL, - 0x96B7C4EDD1F3536FUL, 0x7E8C21F19C08541CUL, 0xEE92DB0CF91E4B09UL, - 0xF666190D1591AE5DUL, 0x5E9B45102C895361UL, 0x9A95597AAE5C905DUL, - 0x6E1272E5BB93F93FUL, 0x0E39E612402BFCF8UL, 0x576C9E8CA2A3B35EUL, - 0x7E2E629996D0C35FUL, 0xC95DFF54E3524FCCUL, 0x260F9DEBDEB0E5CBUL, - 0x577B6C6640BAF1ABUL, 0xCA76677779CA358EUL, 0x9E2714BEBCFDB144UL, - 0xD660595CE30FD3EEUL, 0x72DE172D55A5706EUL, 0xB4C84D564489D420UL, - 0x160AA2B9399D5A9DUL, 0x2906ECE619DAC4D2UL, 0x12CE8E8E68A4C317UL, - 0x6BE2DFE89901CAA1UL, 0xEE1D68158102EB77UL, 0x64EB75E45BDA1AC5UL, - 0xEFECF9F98720B55DUL, 0x41CDF813931315BFUL, 0x5F1E4F50CF98FFD4UL, - 0xE69E09EED12E173BUL, 0x89A3707F0396FF65UL, 0x81E36B9DF4FFB492UL, - 0x58C32E883D4DE6DDUL, 0x2D4725C2A5F0B469UL, 0x6B2B9C27CC421CACUL, - 0x3C30F2AD966800C7UL, 0xFF74938BB76B8A7CUL, 0x52B5C99114FD93FAUL, - 0x51647EDCA6C104DAUL, 0xEB47684CF796DF4EUL, 0x376D74A5AB14BD71UL, - 0xF0871FEF8E9DAA3EUL, 0x1D65B134B2E045B6UL, 0x9DC8C0D8623BBA48UL, - 0xAD6FC3C59DBDADF4UL, 0x66F6EBA55488B569UL, 0xB00D53E0E2D38F0AUL, - 0x43A4212CEAD34593UL, 0x44724185FF7019FFUL, 0x50F46061432B3635UL, - 0x880AA4C24E6B320BUL, 0xCAFCB3409A0DB43FUL, 0xA7F1A13DEF47514BUL, - 0x3DC8A385A698220CUL, 0xFA17F82E30B85580UL, 0x430E7F0E88655F47UL, - 0x45A1566013837B47UL, 0x84B2306D2292804EUL, 0xE7A3AF21D074E419UL, - 0x09D08E2C5E569D4DUL, 0x84228F8908383FA2UL, 0xC34079610C8D3E82UL, - 0x66C96426C54A5453UL, 0xD41F164117D32C93UL, 0x7829A66BF1FEC186UL, - 0x4BB6846694BDFC18UL, 0x857D1C1C01352C01UL, 0xAB8E68BA85402A45UL, - 0x74B3C4F101FE76C8UL, 0x6CF482CFAFB29FFEUL, 0x28B174A18F4DC3D1UL, - 0x833C3425B2AA3755UL, 0x8AA58A32747F4432UL, 0xFE7B9FB4BCE3CD58UL, - 0xB0836B2C16FA5553UL, 0x1D08EE6861BF3F23UL, 0x0FAE41E914562DF3UL, - 0xB10A2E041937FC57UL, 0xDA60BB363415BF4CUL, 0xEEC67DBAB4CF4F0AUL, - 0x9A6ED59FCC923B5CUL, 0x9A913C01A8EC7A83UL, 0xAD4779F2F9C7721FUL, - 0x2BF0B7D105BE7459UL, 0x189EFA9AD5195EC6UL, 0xB5C9A2DD64B2A903UL, - 0x5BCD642B2C2FD32CUL, 0xFED3FBF78CB0891FUL, 0x1ED958EE3C36DD3FUL, - 0x030F5DE9CA65E97CUL, 0xBB5BCF8C931B85FEUL, 0xFD128759EA1D8061UL, - 0x2C0238AC416BE6BCUL, 0xBB018584EEACFA27UL, 0xCEA7288C1964DE15UL, - 0x7EA5C3840F29AA4DUL, 0x5DA841BA609E4A50UL, 0xE53AF84845985EB1UL, - 0x93264DA9487183E4UL, 0xC3A4E367AF6D8D15UL, 0xDD4EB6450577BAF8UL, - 0x2AA3093EE2C658ACUL, 0x3D036EC45055C580UL, 0xDDEDB34341C5B7DFUL, - 0x524FFBDC4A1FAC90UL, 0x1B9D63DE13D82907UL, 0x69F9BAF0E868B640UL, - 0xFC1A453A9253013CUL, 0x08B900DECAA77377UL, 0xFF24C72324153C59UL, - 0x6182C1285C507A9BUL, 0x4E6680A54A03CCC8UL, 0x7165680200B67F1FUL, - 0xC3290B26A07DCE5BUL, 0x2AD16584AA5BECE9UL, 0x5F10DF677C91B05EUL, - 0x4BE1B0E2334B198AUL, 0xEA2466E4F4E4406DUL, 0x6ECAA92FF91E6F1DUL, - 0x0267738EFA75CADDUL, 0x4282ED10A0EBFCF2UL, 0xD3F84CE8E1685271UL, - 0xB667ED35716CA215UL, 0x97B4623D70DB7FA8UL, 0xB7BA3AA5E6C2E7CBUL, - 0x8942B2F97118255BUL, 0x009050F842FB52ADUL, 0x114F5511999F5BD5UL, - 0x70C1CAAF1E83F00AUL, 0xAC8EE25D462BB1AAUL, 0x63EEF42AD4E1BED9UL, - 0x58DFBB3D22D3D1A5UL, 0x82B0027C0C63D816UL, 0x48D038F08F3D848BUL, - 0xCE262D5F9A12610EUL, 0xA54BF51C21BD0167UL, 0xF3645F6FB948397DUL, - 0x9188AE58532DA501UL, 0xEC90B0E1479DB767UL, 0x37F4886B83724F80UL, - 0x232B8FF20ACD95AFUL, 0x88A228285D6BCDF0UL, 0x321FB91600259AEEUL, - 0xA1F875F161D18E5EUL, 0x5B6087CDA21AEA0CUL, 0x0156923ED1A3D5F1UL, - 0xC2892C8A6133B5D3UL, 0x015CA4DF0EA6354DUL, 0x5E25EB261B69A7D4UL, - 0xAAA8CF0C012EFBA7UL, 0xCF3466248C37868BUL, 0x0D744514BD1D82C0UL, - 0xB00FF1431EDDF490UL, 0xC79B86A0E3A8AB08UL, 0xFC361529BC9F1252UL, - 0x869285653FB82865UL, 0x9F1C7A17546339ABUL, 0xE31AA66DBD5C4760UL, - 0x51B9D2A765E0FC31UL, 0x31F39528C4CD13D8UL, 0x16C6C35B0D3A341DUL, - 0x90296B1B0F28E2CDUL, 0x36338472A8DB5830UL, 0xA648E6D44DF14F87UL, - 0x93E231E65EB1823FUL, 0x95AA7B9D08E2B627UL, 0x7932D149374700C7UL, - 0x09EFE0A8BF245193UL, 0x742AA63BCEAFD6D8UL, 0x82D4BC5FEDF158B7UL, - 0x02CDEA673CFF150DUL, 0xD8D7B5813B602D15UL, 0xA5A7B670EF15A5EDUL, - 0x4C08E580A1D46AF2UL, 0xC3CA9B905D035647UL, 0x6A39ABB02F6F1B83UL, - 0xD2EC2169F4D02436UL, 0x8E6AEA4DF8515AF2UL, 0x7B3DD4A8693CA2DAUL, - 0xC2ABF17A50AEC383UL, 0xD4FB84F8B6D4F709UL, 0x2839A3EAA2E4C8A7UL, - 0x5D5FD278FE10E1E9UL, 0x5610DDF74125D5A7UL, 0xA484B0B83461DCEAUL, - 0xA511920C0A502369UL, 0xC53F30C6A5394CA4UL, 0x528799285D304DD4UL, - 0xF6D7914CB252BB48UL, 0x892129CB52E65D15UL, 0x15A81B70519ACE6FUL, - 0x5CFBFFD7A2A1C630UL, 0x3B900509C82DF46DUL, 0x19C3CE05D66D5FFCUL, - 0x937D521A4A4799A0UL, 0xD0AE34A6EAD7207DUL, 0x3258A69F1D1A1B38UL, - 0xB173E3255723CC02UL, 0xD7E48FEF7F414F1BUL, 0xDCEBA75F5C761ABEUL, - 0x6DA10C618DEA0D17UL, 0x423FA8B05954FBD1UL, 0x7E73C2E7D923F3C9UL, - 0xC22E21C927C684D1UL, 0x756BAA758764685FUL, 0x8C90B4C4E741D880UL, - 0x1B658C9F4B41D846UL, 0x5D80C14094366707UL, 0xB55FED3E03C00F2DUL, - 0x9B69EB7964C69C83UL, 0x356ED81C9494DADDUL, 0x7599AFF0B2A339D6UL, - 0xA5EBFD25C9B5816BUL, 0xA481DC1C8995E1EFUL, 0xE42C63DF0D402397UL, - 0x3B497B4C30873BAAUL, 0xA950B78BA8772C96UL, 0xD46308D4C76F115DUL, - 0x73714A4ACA76A857UL, 0x0DA86B958FF8CB7DUL, 0xEB61F617B90E0A75UL, - 0xD6106C9B39F51F55UL, 0xB179F73A6BD23B59UL, 0xE7F056E50104A460UL, - 0xBC5B5387634A8642UL, 0xE1678D8752996AF4UL, 0xB508F3D394664A4BUL, - 0xC88536DC4A219B0FUL, 0x39964CBB8CE367B1UL, 0xD51E211D5E9E1417UL, - 0x6821B97B496870F2UL, 0xA596257350CA0A99UL, 0x6D051EE2C49D4D1DUL, - 0xCB426AD61AA8D9B5UL, 0x5FFD3A4062B06D22UL, 0xDAD37BF2A4C594EBUL, - 0x6B9CC848E2B0C686UL, 0x19B4232F3BC622AEUL, 0x70C13C7E5950B702UL, - 0x383318CA622101ACUL, 0xD9647C028CD1C4DFUL, 0x006D123BC553B93CUL, - 0x2CA9D7D896EAE722UL, 0xF19872AC8A0BD5A8UL, 0x59838578EB9E8E5CUL, - 0xB948621EE99B27D4UL, 0x2B470E6036E0E387UL, 0xD0A7E8F0C8A32A84UL, - 0xCBF869271A8E0914UL, 0x705F76A5EA4437CFUL, 0xBAD2BF4933215152UL, - 0xE52EDE847038EA23UL, 0xB8A3EFD3D58D7607UL, 0x748472F5AD330239UL, - 0xCC079CFD428690F6UL, 0x3687450CB7534DACUL, 0x0FEF82D5CC8ACE2AUL, - 0x214653D5C552CA9AUL, 0x9FCA4E87BF6A04FDUL, 0x78D4B114D234A0D7UL, - 0x22840422BD6A5BB5UL, 0x5B9ABE0DE1B4410FUL, 0xB3B50007963FDD6BUL, - 0x53A8A46793B68E35UL, 0x8CDD8E8D188B6033UL, 0x5DD22B6E3ED49572UL, - 0xE561F5D27F5302D6UL, 0xDF89CEC3322E56CDUL, 0x87167F503D600F90UL, - 0x1698BB71C8201862UL, 0xF7BF5DFDB023108EUL, 0xA17FB15B66ACFB5FUL, - 0x2DD771987768073BUL, 0x19299D2D86E0EB29UL, 0x8B537B7F206EED29UL, - 0xE536DA153325ABFCUL, 0x30A69976796DB3B9UL, 0x8E65A2C94E2D4981UL, - 0xC301D53553BD6514UL, 0x46DF3639B9E43790UL, 0x3004CD0E5AFD0463UL, - 0x46E460B0F6ACA1A0UL, 0xCBA210E7372D9BD5UL, 0x45064274A74CA582UL, - 0xFDD57EA43CE631AEUL, 0xF2BA08FFA4A683D0UL, 0x8DA658C4DAD42999UL, - 0x7418042943E88040UL, 0x96000F72E9371FEFUL, 0xE9F1212DC8F47302UL, - 0x2AFB565ECC3553EDUL, 0xCD3D55137EFF7FD6UL, 0xD36F11059388E442UL, - 0xC4B47515DB5709DDUL, 0x5C363EFBF0BAAB67UL, 0x28C63B5A31650BBBUL, - 0x6AE54E5068061C81UL, 0xDEE62000F4E0AA21UL, 0xE8238672FE088A8BUL, - 0x9869CB6370F075B9UL, 0xBA376E2FC7DB330FUL, 0xB0F73E208487CDEEUL, - 0x359D5017BE37FE97UL, 0x684D828C7F95E2DCUL, 0x9985ECA20E46AE1FUL, - 0x8030A5137D1A21C4UL, 0xF78CDC00FC37AC39UL, 0x41CDDC8E61D9C644UL, - 0xB6F3CD1D833BAD1DUL, 0x301D0D858A23DE22UL, 0xA51FCA12AD849BC8UL, - 0x9F55E615986AB10EUL, 0x904AAA59854F2215UL, 0x12ECEA4AB40F51A7UL, - 0xB4EDF5807735E23BUL, 0x6190200F1C589478UL, 0xA3CA57F321909A5AUL, - 0x0BFAEE04B7325B63UL, 0x10C393E7FBCF826DUL, 0x4050A2CA53FDA708UL, - 0xF31114A9B462B680UL, 0x6FB9A6F121BA2006UL, 0x04550CF09389D602UL, - 0xB8C7D6D8CA8942F7UL, 0x71BB430C6436E9D1UL, 0xD9070DD5FAA0A10AUL, - 0x8FD6827757D07E5BUL, 0xD04E6C313F8FD974UL, 0x2CFDEA1187909B9AUL, - 0xC7A8E758C115F593UL, 0xA79A17663009ACC2UL, 0x8091A6B5372B141DUL, - 0xEB33B08767F5BA73UL, 0xDAC1F6823B6111C7UL, 0x697DF90C3515611BUL, - 0xCC1005F198761F48UL, 0x5067E4F5303B45A1UL, 0x04816D292A2D9AC2UL, - 0x2949C7A0874DD5E9UL, 0x25DB2547804CEE5EUL, 0x7EDC3A8946D6F229UL, - 0x00B586F67FD0C622UL, 0x3CAE5798E40324E0UL, 0x0A4F1437DE637164UL, - 0x5F59B2B715871981UL, 0x5D68FF31051E48FBUL, 0x0F2C369D73A2AA46UL, - 0xB009C6B53DD23399UL, 0xC366A81277084988UL, 0x5AF0E0CA0711E730UL, - 0x7AD831A9E9E854BAUL, 0x1DD5EDB0CA4E85AEUL, 0x54651209D259E9DDUL, - 0x3EBB1D9DAB237EADUL, 0xDA96989317AC464CUL, 0xBFCB0F8FBC52C74EUL, - 0x9597ACB9E27B692EUL, 0x6F436B1643C95B23UL, 0xB81A1253E1C3CD9DUL, - 0x7B35F37E905EC67EUL, 0x29CE62666EDA76DDUL, 0xFF2490DC1EC4014DUL, - 0x2D4FF9124DD6B5C4UL, 0xB9510FEC23E0E9D1UL, 0x8BCDBC56541ED071UL, - 0x5414E097C1B0CCB2UL, 0x82BEF8213076F5C7UL, 0xE9FC9A71BD512615UL, - 0xCF15ECC39490DF5AUL, 0x49FA9328D8EE97DBUL, 0x5F80FF0153BC2145UL, - 0xF63BA156B55BCB02UL, 0x0E3B9113109FDF36UL, 0x8FCD6528F54EDE69UL, - 0x5D6AE9C000054763UL, 0x326D873633431FBBUL, 0x380E07FFCEF7A978UL, - 0xDCAA09874A1DF230UL, 0x601494F49F6D261EUL, 0x856159486C9B60E3UL, - 0x85C7F822D07089A5UL, 0xAFFB99CF5AB836C2UL, 0x241AD414FBBB956BUL, - 0x0CFC042822831692UL, 0x382B16D049727FF2UL, 0x784F9997633C819AUL, - 0x5C40ED725F6C390AUL, 0x2CE78B7A3331BA9CUL, 0x9C80636639963B41UL, - 0x1B2D41C968355018UL, 0xD189B57691FB60E4UL, 0x3BD599A9DD85CE31UL, - 0x46FC8E2EF0B9A77CUL, 0x1A389E07D0075EA4UL, 0x1622CA52401DF2ACUL, - 0x528F3FF9B7993BFAUL, 0xF16C176CCA292DDBUL, 0x6C154010961EF542UL, - 0x04B78E92BF6C82DFUL, 0x7D9AFEA6ABB46072UL, 0x3BC573291CBFFC2EUL, - 0x277FFF096D567AF3UL, 0x1CBEB86841A6F757UL, 0xD0BCD49E76CA20A7UL, - 0x25B6024756B1FE90UL, 0xE685C04EF84881FBUL, 0xDCAB14B352FC442EUL, - 0x4FF80A521719953DUL, 0xD10425E411DBE94BUL, 0x60998D0507D6E38DUL, - 0x146AA432C981BD5EUL, 0x1729A596282AAA41UL, 0x152BE1A263BAF963UL, - 0x15278DF497D254CAUL, 0xE4B5E9891E88A5DAUL, 0x087FA3472067D0ACUL, - 0xD99C2899A0AD9158UL, 0x5040F234DC531236UL, 0x9D7E1531259EEE90UL, - 0x29AFB8B49391036EUL, 0x84B619599642D68EUL, 0xE838AAE0F249545CUL, - 0x42D524BA8BB96959UL, 0x9A5B3E817A20EE59UL, 0x584F0530EC4C566BUL, - 0xD6544FD14B47F945UL, 0x3613FB3B553A7CDEUL, 0x284E92B56831AA56UL, - 0xCEE89BA10E951A22UL, 0x476806FA1A8A44E0UL, 0xC84CEF151885C1DFUL, - 0x3DB1D5C1B0B73936UL, 0x45D2D90FDF452388UL, 0x038A7DD71BC5DD21UL, - 0x2AC90C7422C56819UL, 0x4742046638ECE0FBUL, 0x553B44360FC8495DUL, - 0xC8DBA1CF3F9A6E97UL, 0xF85919F494CAB021UL, 0x1479455C2FF236AFUL, - 0x29BCAD159F7D018DUL, 0x016DFF51CBA3BCC5UL, 0x234BF8A77F6B1CF5UL, - 0x20564C6F44F9E641UL, 0x063A550C5AA50FA8UL, 0xB063D0AAAA96DFECUL, - 0x3EC659DF42C092F8UL, 0x29D4A76A5A5F7E09UL, 0x65EFF3EE6E691D1EUL, - 0xBD1634F5721CF799UL, 0xE85BD016723B43FFUL, 0x5233E9E7AEA11022UL, - 0x8C68852EA9039B4CUL, 0x2C978ADBE885BC15UL, 0x726615ED9D497550UL, - 0x7C1E145EB8D2BD96UL, 0xC2FEFB25935A5D71UL, 0x9EE9C3E1C3DE416FUL, - 0xFFD568A03E20E0B3UL, 0xF53649AD90156F2AUL, 0x0331B91DCE54E7EDUL, - 0x67CED5A86E99392FUL, 0x16FC0A5815500B05UL, 0x030392E8D24A7C00UL, - 0x232E5E31DF32A7B5UL, 0xCC8BF22B1947DF21UL, 0x4EC2C72D9C1EEABDUL, - 0x0B1B79F45220E668UL, 0xCC3CF0EE9C4A899BUL, 0xFC260A60592EBC80UL, - 0xC1989A0382CB03EDUL, 0x35FE679A6CD800B2UL, 0x8A6B1ADE4FBB162FUL, - 0xB0FD284563625295UL, 0xCDCC1C7B2181D024UL, 0x5B8BA0C895C0BB23UL, - 0xA681FEA9ADCD43DBUL, 0x0FE30FB6876DE718UL, 0x6DDD1E27B769C494UL, - 0x83A1E58460FFE8BBUL, 0x8FAD6FD2DC90FF65UL, 0x41BB28B81201CB24UL, - 0xA148CE79B2597204UL, 0x7CB87DF97BB477A6UL, 0x9F79E6DED87DC688UL, - 0xE044D84A6C758171UL, 0x1A29E750D9EC4097UL, 0x8445FC2B80C4A0F5UL, - 0x5EFD9784AFED4ED2UL, 0x344C252BD90EB0E4UL, 0xEAD18D2E4418E5B5UL, - 0x207EF4FFC260BD24UL, 0xD2E5C3AE534EC538UL, 0x2F5A59BF3D10E7E1UL, - 0x9528E29266C2924CUL, 0x0121B6BDAB45D138UL, 0xADD0256ACBC771DDUL, - 0x7301769600C6C50DUL, 0x3E7404EA8231D497UL, 0xB39B3840B8D03117UL, - 0x56EFCEDDEF5B6634UL, 0xE6BE2C0D73B72098UL, 0x5A2841A21A5E4959UL, - 0xCFEB3586156DF6E0UL, 0xD84F58901E2D65B8UL, 0x79796786CCC59703UL, - 0x13BFA9A94DD07696UL, 0x7B63116A6B5458B6UL, 0x1406628176C932E0UL, - 0xDD7ACC4E97F91B1AUL, 0xC82B8F84A56BDBE8UL, 0x325D87D08ED8B0B0UL, - 0x3F7847B1E82002DDUL, 0x4662900D2ADAF6BFUL, 0x12AE9F58561DB1D7UL, - 0xA896E956A95CC074UL, 0xAA4FA3A2F8BA4084UL, 0x1D577E35F5DCA67FUL, - 0x796FF2D75469DEC2UL, 0xBD3F3F87E4DE894EUL, 0x3666B2262DEBFB6BUL, - 0x1E26D7AEEF976C2EUL, 0x6BC3854F867AC4A0UL, 0x743DBF8C2E95A821UL, - 0xA62A76B9AE2E645AUL, 0xB4D76561F40187C1UL, 0xD3E5F23F9FA5DB25UL, - 0x34B1F6B39E6A87E2UL, 0x7DA5C3DFF7BE72CFUL, 0xFDF46B1BE80AD4F9UL, - 0x0B21121CA9653B8AUL, 0x1199CA9D0A90F21AUL, 0x6021EA302D01E0BAUL, - 0x8101D063C05CF5D4UL, 0xE2652410DFE78F23UL, 0x84095ACF47C21A25UL, - 0xD7E29A4DB2FD3A99UL, 0x7793C0CB57959F93UL, 0x94C605308B9E5AA7UL, - 0x943DB1AC54165B8FUL, 0xC1391A544C07447CUL, 0x3FEF1A61F785D97BUL, - 0x6DFCC3152478BDE4UL, 0x312AFB0E1982933AUL, 0xB8069C2605631ED3UL, - 0x5A6076423430BED2UL, 0x34E379F09E2D4F42UL, 0x9167F5E4019573E3UL, - 0x18F81157828D2A49UL, 0xF4A8723B4955EAB8UL, 0x0BE6C0ABFEA9E8A6UL, - 0xC63ADCF2CEF25556UL, 0xC5EBD3BEAE9F364FUL, 0xA301D60CF5B6F2FCUL, - 0x8C606CA881D27A00UL, 0x826FEE13B554C18AUL, 0x8DF251716F10B776UL, - 0xB2573A33AC7D94FFUL, 0xC0E771248CB7ABB9UL, 0x753DD605DB38F4EAUL, - 0x21901664C3D92114UL, 0xA408FCB7A1892612UL, 0x3084FC64A03D6722UL, - 0xC8C9D9569AD42A34UL, 0x1FBFBAFC1694B383UL, 0x1894280CC3F94ABEUL, - 0xE14C38A7BBB54651UL, 0x23A48CC84A6EB704UL, 0xD034ADC45AABEDBDUL, - 0xC93F2C21C973C766UL, 0x66A8AEC11D743CC6UL, 0xB4F72AA52E37C145UL, - 0xB02834DF0D9266B4UL, 0xDB8E724EA1FF402FUL, 0x531E9C058112E352UL, - 0xC2F692531DB317D2UL, 0xEFC9586498D263A7UL, 0x84F2C524D2F3ADB9UL, - 0xAFAF02C27CF25D08UL, 0x385873595F9CFC09UL, 0x36DDA10D1A152B7AUL, - 0x9F9B997A0DACFB55UL, 0x10AB5EB5C4714882UL, 0x7BA4E8703E22B7EEUL, - 0x0A2BFD558607BCC8UL, 0x201D3706F74F8BA1UL, 0x3DBD573B1358F02EUL, - 0x5B37645FA93BCEBCUL, 0xC0166864BC1A7544UL, 0x45C7AA5559FC65D7UL, - 0xEFEA04AA83349B78UL, 0x607859194F9E9FD8UL, 0xA6B9AE5B53CF7710UL, - 0x73B9142ACBC50821UL, 0x8B7D67495887E65CUL, 0x39B6C4FB2B232E56UL, - 0xD212DB10E31D2A68UL, 0x629AC0A3D263DC6EUL, 0x6BC2E7FF912050BAUL, - 0xE0AD5A8FDB183F62UL, 0xF05648134F0C6F0FUL, 0x31E146F4AF980FDAUL, - 0x7FAF0078D84D62CCUL, 0xE13F044C2830D21EUL, 0x49A047AD204B4C4BUL, - 0xF3AFBE2237351A74UL, 0x32826C9217BB07EDUL, 0xD4C3AEB099319B5CUL, - 0x49CE5BD05B2B0F61UL, 0x75DD36984DCBD0A2UL, 0x84EC5D7C2F0AAC6CUL, - 0x8E59CC9B9942EDDFUL, 0x89FF85DCDF9AE895UL, 0x6F9EE0D8D9E8D414UL, - 0x10E01A59058D3904UL, 0x1DFAF567BFF55D2EUL, 0x8DD6A18C03382CD4UL, - 0xE12FD89A0CF58553UL, 0xE245DA902C0C4F5CUL, 0x8BE7566B9987520DUL, - 0x4CA1C0A4B38A3098UL, 0x81E45015BE618A72UL, 0xA80E0344FF27EFDFUL, - 0xC98DAEC6DC5005BAUL, 0xF56873F3A958AE5EUL, 0xDB88604670C794ACUL, - 0x4F68E448DDF6535FUL, 0x3443DBF1CA6031A8UL, 0x73DFA5DEEF409A41UL, - 0xA7C556941F6643B2UL, 0x424BC40D8C83D962UL, 0x6F292A325B99B726UL, - 0x6EECB1009717D65EUL, 0x899BE4CE7BB2D8EEUL, 0x25285FED3E59781DUL, - 0x14C5AEDD76E092D3UL, 0x9BB5EE10567640AEUL, 0xCD62A1D43558FD06UL, - 0x70A7B09FC5F39447UL, 0xF10064AE92EFFB99UL, 0xD55FA1A918A23082UL, - 0xD03F28AD25C73A78UL, 0x76CFFFEE094D8B0EUL, 0x4FD5A46AD5A4B4CFUL, - 0x8F3A36F9D7BF87E3UL, 0x64224315210625BEUL, 0x749A131B71B64350UL, - 0x9034FF9DAC089F48UL, 0xB58D3017E7321217UL, 0x549D818937D5CE90UL, - 0x903CE1452419E99CUL, 0xFD052F0388DB2E76UL, 0x7390051E3972480EUL, - 0x5E5F6EC3F27B3679UL, 0x3E3637D4D4EE917DUL, 0x4FE04068CA2A4309UL, - 0x98C9C17454AAE42DUL, 0x659AE0BDB113BC21UL, 0x4C0BDECB1511AF4CUL, - 0x17048BFAEAC0006DUL, 0x68F106AADAA64912UL, 0x2286234ECEB7EAF0UL, - 0x350CD42CAF697E51UL, 0x8DCDE6D1FAC19A9FUL, 0xF97E55A245A8A8A2UL, - 0xAAE86B2092DA90A3UL, 0x5123E878AA8AEF76UL, 0x022B88B9694A55F6UL, - 0xC4C1A9B1C0221985UL, 0x20056D91DD5E0FFEUL, 0xF5BF61EC225C9843UL, - 0x1A315A05BDCF4A31UL, 0x5710A21A8DF4F15FUL, 0x99BD1A0AF97AD027UL, - 0x7602C5997AD4E12CUL - }; + internal static int MaxLength + { + get + { + Debug.Assert(m_dicts.Count > 0); // Should be initialized + + int iMaxLen = 0; + foreach(int iLen in m_dicts.Keys) + { + if(iLen > iMaxLen) iMaxLen = iLen; + } + + return iMaxLen; + } + } + + internal static bool ContainsLength(int nLength) + { + Dictionary dDummy; + return m_dicts.TryGetValue(nLength, out dDummy); + } public static bool IsPopularPassword(char[] vPassword) { - Debug.Assert(PpcTable.Length == (PpcTableSize / 64)); + ulong uDummy; + return IsPopularPassword(vPassword, out uDummy); + } + public static bool IsPopularPassword(char[] vPassword, out ulong uDictSize) + { if(vPassword == null) throw new ArgumentNullException("vPassword"); - if(vPassword.Length == 0) return false; + if(vPassword.Length == 0) { uDictSize = 0; return false; } - foreach(char ch in vPassword) + string str = new string(vPassword); + + try { return IsPopularPasswordPriv(str, out uDictSize); } + catch(Exception) { Debug.Assert(false); } + + uDictSize = 0; + return false; + } + + private static bool IsPopularPasswordPriv(string str, out ulong uDictSize) + { + Debug.Assert(m_dicts.Count > 0); // Should be initialized with data + + Dictionary d; + if(!m_dicts.TryGetValue(str.Length, out d)) { - if(!IsPopularChar(ch)) return false; + uDictSize = 0; + return false; } - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vPassword); + uDictSize = (ulong)d.Count; + return d.ContainsKey(str); + } - int[] vIndices = GetTableIndices(pbUtf8, PpcTableSize); - Array.Clear(pbUtf8, 0, pbUtf8.Length); - - foreach(int iIndex in vIndices) + public static void Add(byte[] pbData, bool bGZipped) + { + try { - if(!GetTableBit(PpcTable, iIndex)) return false; - } + if(bGZipped) + pbData = MemUtil.Decompress(pbData); - return true; - } + string strData = StrUtil.Utf8.GetString(pbData, 0, pbData.Length); + if(string.IsNullOrEmpty(strData)) { Debug.Assert(false); return; } - private static bool IsPopularChar(char ch) - { - return (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) || - ((ch >= '0') && (ch <= '9')) || (ch == '_') || (ch == '!')); - } + if(!char.IsWhiteSpace(strData[strData.Length - 1])) + strData += "\n"; - private static int[] GetTableIndices(byte[] pbPasswordUtf8, int nTableSize) - { - Debug.Assert((nTableSize >= 2) && (nTableSize <= 0x10000)); - Debug.Assert((nTableSize % 64) == 0); - - SHA512Managed sha = new SHA512Managed(); - byte[] pbHash = sha.ComputeHash(pbPasswordUtf8); - - int[] vIndices = new int[pbHash.Length / 2]; - for(int i = 0; i < vIndices.Length; ++i) - vIndices[i] = ((((int)pbHash[i * 2] << 8) | - (int)pbHash[i * 2 + 1]) % nTableSize); - - return vIndices; - } - - private static bool GetTableBit(ulong[] vTable, int iBit) - { - return ((vTable[iBit >> 6] & (1UL << (iBit & 0x3F))) != 0UL); - } - -#if (DEBUG && !KeePassLibSD) - private static bool SetTableBit(ulong[] vTable, int iBit) - { - if(GetTableBit(vTable, iBit)) return false; - - vTable[iBit >> 6] = (vTable[iBit >> 6] | (1UL << (iBit & 0x3F))); - return true; - } - - public static void MakeList() - { - string strData = File.ReadAllText("MostPopularPasswords.txt", StrUtil.Utf8); - strData += " "; - CharStream cs = new CharStream(strData); - - List vPasswords = new List(); - StringBuilder sbPassword = new StringBuilder(); - while(true) - { - char ch = cs.ReadChar(); - if(ch == char.MinValue) break; - - if(char.IsWhiteSpace(ch)) + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < strData.Length; ++i) { - string strPassword = sbPassword.ToString(); - strPassword = strPassword.ToLower(); + char ch = strData[i]; - if(strPassword.Length > 3) + if(char.IsWhiteSpace(ch)) { - if(vPasswords.IndexOf(strPassword) < 0) - vPasswords.Add(strPassword); + int cc = sb.Length; + if(cc > 0) + { + string strWord = sb.ToString(); + Debug.Assert(strWord.Length == cc); + + Dictionary d; + if(!m_dicts.TryGetValue(cc, out d)) + { + d = new Dictionary(); + m_dicts[cc] = d; + } + + d[strWord] = true; + sb.Remove(0, cc); + } } - - sbPassword = new StringBuilder(); - } - else - { - Debug.Assert(!char.IsControl(ch) && !char.IsHighSurrogate(ch) && - !char.IsLowSurrogate(ch) && !char.IsSurrogate(ch)); - Debug.Assert(IsPopularChar(ch)); - sbPassword.Append(ch); + else sb.Append(char.ToLower(ch)); } } - - ulong[] vTable = new ulong[PpcTableSize / 64]; - Array.Clear(vTable, 0, vTable.Length); - - long lBitsInTable = 0; - foreach(string strPassword in vPasswords) - { - byte[] pbUtf8 = StrUtil.Utf8.GetBytes(strPassword); - int[] vIndices = GetTableIndices(pbUtf8, PpcTableSize); - - foreach(int i in vIndices) - { - if(SetTableBit(vTable, i)) ++lBitsInTable; - } - } - - StringBuilder sb = new StringBuilder(); - sb.Append("\t\t\t"); - for(int i = 0; i < vTable.Length; ++i) - { - if(i > 0) - { - if((i % 3) == 0) - { - sb.AppendLine(","); - sb.Append("\t\t\t"); - } - else sb.Append(", "); - } - - sb.Append("0x"); - sb.Append(vTable[i].ToString("X16")); - sb.Append("UL"); - } - - sb.AppendLine(); - sb.AppendLine(); - sb.AppendLine("Bits set: " + lBitsInTable.ToString() + " of " + - PpcTableSize.ToString()); - int cHashFn = GetTableIndices(StrUtil.Utf8.GetBytes("Dummy"), PpcTableSize).Length; - sb.AppendLine("Hash functions: " + cHashFn.ToString()); - double dblPhi = Math.Pow(1.0 - ((double)cHashFn / PpcTableSize), - (double)vPasswords.Count); - sb.AppendLine("Phi (bits unset ratio) estimation: " + - dblPhi.ToString(CultureInfo.InvariantCulture)); - dblPhi = ((double)(PpcTableSize - lBitsInTable) / (double)PpcTableSize); - sb.AppendLine("Exact Phi: " + dblPhi.ToString(CultureInfo.InvariantCulture)); - sb.AppendLine("False positives ratio: " + Math.Pow(1.0 - dblPhi, - (double)cHashFn).ToString(CultureInfo.InvariantCulture)); - - File.WriteAllText("Table.txt", sb.ToString()); + catch(Exception) { Debug.Assert(false); } } -#endif } } -#endif diff --git a/src/KeePassLib2Android/Cryptography/QualityEstimation.cs b/src/KeePassLib2Android/Cryptography/QualityEstimation.cs index 0d5e6297..d90b3fab 100644 --- a/src/KeePassLib2Android/Cryptography/QualityEstimation.cs +++ b/src/KeePassLib2Android/Cryptography/QualityEstimation.cs @@ -1,6 +1,6 @@ -/* +/* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -19,9 +19,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Text; +using System.Diagnostics; +using KeePassLib.Cryptography.PasswordGenerator; using KeePassLib.Utility; namespace KeePassLib.Cryptography @@ -32,13 +33,286 @@ namespace KeePassLib.Cryptography /// public static class QualityEstimation { - private enum CharSpaceBits : uint + private static class PatternID { - Control = 32, - Alpha = 26, - Number = 10, - Special = 33, - High = 112 + public const char LowerAlpha = 'L'; + public const char UpperAlpha = 'U'; + public const char Digit = 'D'; + public const char Special = 'S'; + public const char High = 'H'; + public const char Other = 'X'; + + public const char Dictionary = 'W'; + public const char Repetition = 'R'; + public const char Number = 'N'; + public const char DiffSeq = 'C'; + + public const string All = "LUDSHXWRNC"; + } + + // private static class CharDistrib + // { + // public static readonly ulong[] LowerAlpha = new ulong[26] { + // 884, 211, 262, 249, 722, 98, 172, 234, 556, 124, 201, 447, 321, + // 483, 518, 167, 18, 458, 416, 344, 231, 105, 80, 48, 238, 76 + // }; + // public static readonly ulong[] UpperAlpha = new ulong[26] { + // 605, 188, 209, 200, 460, 81, 130, 163, 357, 122, 144, 332, 260, + // 317, 330, 132, 18, 320, 315, 250, 137, 76, 60, 36, 161, 54 + // }; + // public static readonly ulong[] Digit = new ulong[10] { + // 574, 673, 524, 377, 339, 336, 312, 310, 357, 386 + // }; + // } + + private sealed class QeCharType + { + private readonly char m_chTypeID; + public char TypeID { get { return m_chTypeID; } } + + private readonly string m_strAlph; + public string Alphabet { get { return m_strAlph; } } + + private readonly int m_nChars; + public int CharCount { get { return m_nChars; } } + + private readonly char m_chFirst; + private readonly char m_chLast; + + private readonly double m_dblCharSize; + public double CharSize { get { return m_dblCharSize; } } + + public QeCharType(char chTypeID, string strAlphabet, bool bIsConsecutive) + { + if(strAlphabet == null) throw new ArgumentNullException(); + if(strAlphabet.Length == 0) throw new ArgumentException(); + + m_chTypeID = chTypeID; + m_strAlph = strAlphabet; + m_nChars = m_strAlph.Length; + m_chFirst = (bIsConsecutive ? m_strAlph[0] : char.MinValue); + m_chLast = (bIsConsecutive ? m_strAlph[m_nChars - 1] : char.MinValue); + + m_dblCharSize = Log2(m_nChars); + + Debug.Assert(((int)(m_chLast - m_chFirst) == (m_nChars - 1)) || + !bIsConsecutive); + } + + public QeCharType(char chTypeID, int nChars) // Catch-none set + { + if(nChars <= 0) throw new ArgumentOutOfRangeException(); + + m_chTypeID = chTypeID; + m_strAlph = string.Empty; + m_nChars = nChars; + m_chFirst = char.MinValue; + m_chLast = char.MinValue; + + m_dblCharSize = Log2(m_nChars); + } + + public bool Contains(char ch) + { + if(m_chLast != char.MinValue) + return ((ch >= m_chFirst) && (ch <= m_chLast)); + + Debug.Assert(m_strAlph.Length > 0); // Don't call for catch-none set + return (m_strAlph.IndexOf(ch) >= 0); + } + } + + private sealed class EntropyEncoder + { + private readonly string m_strAlph; + private Dictionary m_dHisto = new Dictionary(); + private readonly ulong m_uBaseWeight; + private readonly ulong m_uCharWeight; + private readonly ulong m_uOccExclThreshold; + + public EntropyEncoder(string strAlphabet, ulong uBaseWeight, + ulong uCharWeight, ulong uOccExclThreshold) + { + if(strAlphabet == null) throw new ArgumentNullException(); + if(strAlphabet.Length == 0) throw new ArgumentException(); + + m_strAlph = strAlphabet; + m_uBaseWeight = uBaseWeight; + m_uCharWeight = uCharWeight; + m_uOccExclThreshold = uOccExclThreshold; + +#if DEBUG + Dictionary d = new Dictionary(); + foreach(char ch in m_strAlph) { d[ch] = true; } + Debug.Assert(d.Count == m_strAlph.Length); // No duplicates +#endif + } + + public void Reset() + { + m_dHisto.Clear(); + } + + public void Write(char ch) + { + Debug.Assert(m_strAlph.IndexOf(ch) >= 0); + + ulong uOcc; + m_dHisto.TryGetValue(ch, out uOcc); + Debug.Assert(m_dHisto.ContainsKey(ch) || (uOcc == 0)); + m_dHisto[ch] = uOcc + 1; + } + + public double GetOutputSize() + { + ulong uTotalWeight = m_uBaseWeight * (ulong)m_strAlph.Length; + foreach(ulong u in m_dHisto.Values) + { + Debug.Assert(u >= 1); + if(u > m_uOccExclThreshold) + uTotalWeight += (u - m_uOccExclThreshold) * m_uCharWeight; + } + + double dSize = 0.0, dTotalWeight = (double)uTotalWeight; + foreach(ulong u in m_dHisto.Values) + { + ulong uWeight = m_uBaseWeight; + if(u > m_uOccExclThreshold) + uWeight += (u - m_uOccExclThreshold) * m_uCharWeight; + + dSize -= (double)u * Log2((double)uWeight / dTotalWeight); + } + + return dSize; + } + } + + private sealed class MultiEntropyEncoder + { + private Dictionary m_dEncs = + new Dictionary(); + + public MultiEntropyEncoder() + { + } + + public void AddEncoder(char chTypeID, EntropyEncoder ec) + { + if(ec == null) { Debug.Assert(false); return; } + + Debug.Assert(!m_dEncs.ContainsKey(chTypeID)); + m_dEncs[chTypeID] = ec; + } + + public void Reset() + { + foreach(EntropyEncoder ec in m_dEncs.Values) { ec.Reset(); } + } + + public bool Write(char chTypeID, char chData) + { + EntropyEncoder ec; + if(!m_dEncs.TryGetValue(chTypeID, out ec)) + return false; + + ec.Write(chData); + return true; + } + + public double GetOutputSize() + { + double d = 0.0; + + foreach(EntropyEncoder ec in m_dEncs.Values) + { + d += ec.GetOutputSize(); + } + + return d; + } + } + + private sealed class QePatternInstance + { + private readonly int m_iPos; + public int Position { get { return m_iPos; } } + + private readonly int m_nLen; + public int Length { get { return m_nLen; } } + + private readonly char m_chPatternID; + public char PatternID { get { return m_chPatternID; } } + + private readonly double m_dblCost; + public double Cost { get { return m_dblCost; } } + + private readonly QeCharType m_ctSingle; + public QeCharType SingleCharType { get { return m_ctSingle; } } + + public QePatternInstance(int iPosition, int nLength, char chPatternID, + double dblCost) + { + m_iPos = iPosition; + m_nLen = nLength; + m_chPatternID = chPatternID; + m_dblCost = dblCost; + m_ctSingle = null; + } + + public QePatternInstance(int iPosition, int nLength, QeCharType ctSingle) + { + m_iPos = iPosition; + m_nLen = nLength; + m_chPatternID = ctSingle.TypeID; + m_dblCost = ctSingle.CharSize; + m_ctSingle = ctSingle; + } + } + + private sealed class QePathState + { + public readonly int Position; + public readonly List Path; + + public QePathState(int iPosition, List lPath) + { + this.Position = iPosition; + this.Path = lPath; + } + } + + private static object m_objSyncInit = new object(); + private static List m_lCharTypes = null; + + private static void EnsureInitialized() + { + lock(m_objSyncInit) + { + if(m_lCharTypes == null) + { + string strSpecial = PwCharSet.PrintableAsciiSpecial; + if(strSpecial.IndexOf(' ') >= 0) { Debug.Assert(false); } + else strSpecial = strSpecial + " "; + + int nSp = strSpecial.Length; + int nHi = PwCharSet.HighAnsiChars.Length; + + m_lCharTypes = new List(); + + m_lCharTypes.Add(new QeCharType(PatternID.LowerAlpha, + PwCharSet.LowerCase, true)); + m_lCharTypes.Add(new QeCharType(PatternID.UpperAlpha, + PwCharSet.UpperCase, true)); + m_lCharTypes.Add(new QeCharType(PatternID.Digit, + PwCharSet.Digits, true)); + m_lCharTypes.Add(new QeCharType(PatternID.Special, + strSpecial, false)); + m_lCharTypes.Add(new QeCharType(PatternID.High, + PwCharSet.HighAnsiChars, false)); + m_lCharTypes.Add(new QeCharType(PatternID.Other, + 0x10000 - (2 * 26) - 10 - nSp - nHi)); + } + } } /// @@ -46,84 +320,95 @@ namespace KeePassLib.Cryptography /// /// Password to check. /// Estimated bit-strength of the password. - /// Thrown if the input - /// parameter is null. public static uint EstimatePasswordBits(char[] vPasswordChars) { - Debug.Assert(vPasswordChars != null); - if(vPasswordChars == null) throw new ArgumentNullException("vPasswordChars"); + if(vPasswordChars == null) { Debug.Assert(false); return 0; } + if(vPasswordChars.Length == 0) return 0; - bool bChLower = false, bChUpper = false, bChNumber = false; - bool bChSpecial = false, bChHigh = false, bChControl = false; - Dictionary vCharCounts = new Dictionary(); - Dictionary vDifferences = new Dictionary(); - double dblEffectiveLength = 0.0; + EnsureInitialized(); - for(int i = 0; i < vPasswordChars.Length; ++i) // Get character types + int n = vPasswordChars.Length; + List[] vPatterns = new List[n]; + for(int i = 0; i < n; ++i) { - char tch = vPasswordChars[i]; + vPatterns[i] = new List(); - if(tch < ' ') bChControl = true; - else if((tch >= 'A') && (tch <= 'Z')) bChUpper = true; - else if((tch >= 'a') && (tch <= 'z')) bChLower = true; - else if((tch >= '0') && (tch <= '9')) bChNumber = true; - else if((tch >= ' ') && (tch <= '/')) bChSpecial = true; - else if((tch >= ':') && (tch <= '@')) bChSpecial = true; - else if((tch >= '[') && (tch <= '`')) bChSpecial = true; - else if((tch >= '{') && (tch <= '~')) bChSpecial = true; - else if(tch > '~') bChHigh = true; + QePatternInstance piChar = new QePatternInstance(i, 1, + GetCharType(vPasswordChars[i])); + vPatterns[i].Add(piChar); + } - double dblDiffFactor = 1.0; - if(i >= 1) + FindRepetitions(vPasswordChars, vPatterns); + FindNumbers(vPasswordChars, vPatterns); + FindDiffSeqs(vPasswordChars, vPatterns); + FindPopularPasswords(vPasswordChars, vPatterns); + + // Encoders must not be static, because the entropy estimation + // may run concurrently in multiple threads and the encoders are + // not read-only + EntropyEncoder ecPattern = new EntropyEncoder(PatternID.All, 0, 1, 0); + MultiEntropyEncoder mcData = new MultiEntropyEncoder(); + for(int i = 0; i < (m_lCharTypes.Count - 1); ++i) + { + // Let m be the alphabet size. In order to ensure that two same + // characters cost at least as much as a single character, for + // the probability p and weight w of the character it must hold: + // -log(1/m) >= -2*log(p) + // <=> log(1/m) <= log(p^2) <=> 1/m <= p^2 <=> p >= sqrt(1/m); + // sqrt(1/m) = (1+w)/(m+w) + // <=> m+w = (1+w)*sqrt(m) <=> m+w = sqrt(m) + w*sqrt(m) + // <=> w*(1-sqrt(m)) = sqrt(m) - m <=> w = (sqrt(m)-m)/(1-sqrt(m)) + // <=> w = (sqrt(m)-m)*(1+sqrt(m))/(1-m) + // <=> w = (sqrt(m)-m+m-m*sqrt(m))/(1-m) <=> w = sqrt(m) + ulong uw = (ulong)Math.Sqrt((double)m_lCharTypes[i].CharCount); + + mcData.AddEncoder(m_lCharTypes[i].TypeID, new EntropyEncoder( + m_lCharTypes[i].Alphabet, 1, uw, 1)); + } + + double dblMinCost = (double)int.MaxValue; + int tStart = Environment.TickCount; + + Stack sRec = new Stack(); + sRec.Push(new QePathState(0, new List())); + while(sRec.Count > 0) + { + int tDiff = Environment.TickCount - tStart; + if(tDiff > 500) break; + + QePathState s = sRec.Pop(); + + if(s.Position >= n) { - int iDiff = (int)tch - (int)vPasswordChars[i - 1]; + Debug.Assert(s.Position == n); - uint uDiffCount; - if(vDifferences.TryGetValue(iDiff, out uDiffCount)) - { - ++uDiffCount; - vDifferences[iDiff] = uDiffCount; - dblDiffFactor /= (double)uDiffCount; - } - else vDifferences.Add(iDiff, 1); - } - - uint uCharCount; - if(vCharCounts.TryGetValue(tch, out uCharCount)) - { - ++uCharCount; - vCharCounts[tch] = uCharCount; - dblEffectiveLength += dblDiffFactor * (1.0 / (double)uCharCount); + double dblCost = ComputePathCost(s.Path, vPasswordChars, + ecPattern, mcData); + if(dblCost < dblMinCost) dblMinCost = dblCost; } else { - vCharCounts.Add(tch, 1); - dblEffectiveLength += dblDiffFactor; + List lSubs = vPatterns[s.Position]; + for(int i = lSubs.Count - 1; i >= 0; --i) + { + QePatternInstance pi = lSubs[i]; + Debug.Assert(pi.Position == s.Position); + Debug.Assert(pi.Length >= 1); + + List lNewPath = + new List(s.Path.Count + 1); + lNewPath.AddRange(s.Path); + lNewPath.Add(pi); + Debug.Assert(lNewPath.Capacity == (s.Path.Count + 1)); + + QePathState sNew = new QePathState(s.Position + + pi.Length, lNewPath); + sRec.Push(sNew); + } } } - uint uCharSpace = 0; - if(bChControl) uCharSpace += (uint)CharSpaceBits.Control; - if(bChUpper) uCharSpace += (uint)CharSpaceBits.Alpha; - if(bChLower) uCharSpace += (uint)CharSpaceBits.Alpha; - if(bChNumber) uCharSpace += (uint)CharSpaceBits.Number; - if(bChSpecial) uCharSpace += (uint)CharSpaceBits.Special; - if(bChHigh) uCharSpace += (uint)CharSpaceBits.High; - - if(uCharSpace == 0) return 0; - - double dblBitsPerChar = Math.Log((double)uCharSpace) / Math.Log(2.0); - double dblRating = dblBitsPerChar * dblEffectiveLength; - -#if !KeePassLibSD - char[] vLowerCopy = new char[vPasswordChars.Length]; - for(int ilc = 0; ilc < vLowerCopy.Length; ++ilc) - vLowerCopy[ilc] = char.ToLower(vPasswordChars[ilc]); - if(PopularPasswords.IsPopularPassword(vLowerCopy)) dblRating /= 8.0; - Array.Clear(vLowerCopy, 0, vLowerCopy.Length); -#endif - - return (uint)Math.Ceiling(dblRating); + return (uint)Math.Ceiling(dblMinCost); } /// @@ -141,5 +426,343 @@ namespace KeePassLib.Cryptography return uResult; } + + private static QeCharType GetCharType(char ch) + { + int nTypes = m_lCharTypes.Count; + Debug.Assert((nTypes > 0) && (m_lCharTypes[nTypes - 1].CharCount > 256)); + + for(int i = 0; i < (nTypes - 1); ++i) + { + if(m_lCharTypes[i].Contains(ch)) + return m_lCharTypes[i]; + } + + return m_lCharTypes[nTypes - 1]; + } + + private static double ComputePathCost(List l, + char[] vPassword, EntropyEncoder ecPattern, MultiEntropyEncoder mcData) + { + ecPattern.Reset(); + for(int i = 0; i < l.Count; ++i) + ecPattern.Write(l[i].PatternID); + double dblPatternCost = ecPattern.GetOutputSize(); + + mcData.Reset(); + double dblDataCost = 0.0; + foreach(QePatternInstance pi in l) + { + QeCharType tChar = pi.SingleCharType; + if(tChar != null) + { + char ch = vPassword[pi.Position]; + if(!mcData.Write(tChar.TypeID, ch)) + dblDataCost += pi.Cost; + } + else dblDataCost += pi.Cost; + } + dblDataCost += mcData.GetOutputSize(); + + return (dblPatternCost + dblDataCost); + } + + private static void FindPopularPasswords(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + + char[] vLower = new char[n]; + char[] vLeet = new char[n]; + for(int i = 0; i < n; ++i) + { + char ch = vPassword[i]; + + vLower[i] = char.ToLower(ch); + vLeet[i] = char.ToLower(DecodeLeetChar(ch)); + } + + char chErased = default(char); + Debug.Assert(chErased == char.MinValue); + + int nMaxLen = Math.Min(n, PopularPasswords.MaxLength); + for(int nSubLen = nMaxLen; nSubLen >= 3; --nSubLen) + { + if(!PopularPasswords.ContainsLength(nSubLen)) continue; + + char[] vSub = new char[nSubLen]; + + for(int i = 0; i <= (n - nSubLen); ++i) + { + if(Array.IndexOf(vLower, chErased, i, nSubLen) >= 0) + continue; + + Array.Copy(vLower, i, vSub, 0, nSubLen); + if(!EvalAddPopularPasswordPattern(vPatterns, vPassword, + i, vSub, 0.0)) + { + Array.Copy(vLeet, i, vSub, 0, nSubLen); + if(EvalAddPopularPasswordPattern(vPatterns, vPassword, + i, vSub, 1.5)) + { + Array.Clear(vLower, i, nSubLen); // Not vLeet + Debug.Assert(vLower[i] == chErased); + } + } + else + { + Array.Clear(vLower, i, nSubLen); + Debug.Assert(vLower[i] == chErased); + } + } + } + } + + private static bool EvalAddPopularPasswordPattern(List[] vPatterns, + char[] vPassword, int i, char[] vSub, double dblCostPerMod) + { + ulong uDictSize; + if(!PopularPasswords.IsPopularPassword(vSub, out uDictSize)) + return false; + + int n = vSub.Length; + int d = HammingDist(vSub, 0, vPassword, i, n); + + double dblCost = Log2((double)uDictSize); + + // dblCost += log2(n binom d) + int k = Math.Min(d, n - d); + for(int j = n; j > (n - k); --j) + dblCost += Log2(j); + for(int j = k; j >= 2; --j) + dblCost -= Log2(j); + + dblCost += dblCostPerMod * (double)d; + + vPatterns[i].Add(new QePatternInstance(i, n, PatternID.Dictionary, + dblCost)); + return true; + } + + private static char DecodeLeetChar(char chLeet) + { + if((chLeet >= '\u00C0') && (chLeet <= '\u00C6')) return 'a'; + if((chLeet >= '\u00C8') && (chLeet <= '\u00CB')) return 'e'; + if((chLeet >= '\u00CC') && (chLeet <= '\u00CF')) return 'i'; + if((chLeet >= '\u00D2') && (chLeet <= '\u00D6')) return 'o'; + if((chLeet >= '\u00D9') && (chLeet <= '\u00DC')) return 'u'; + if((chLeet >= '\u00E0') && (chLeet <= '\u00E6')) return 'a'; + if((chLeet >= '\u00E8') && (chLeet <= '\u00EB')) return 'e'; + if((chLeet >= '\u00EC') && (chLeet <= '\u00EF')) return 'i'; + if((chLeet >= '\u00F2') && (chLeet <= '\u00F6')) return 'o'; + if((chLeet >= '\u00F9') && (chLeet <= '\u00FC')) return 'u'; + + char ch; + switch(chLeet) + { + case '4': + case '@': + case '?': + case '^': + case '\u00AA': ch = 'a'; break; + case '8': + case '\u00DF': ch = 'b'; break; + case '(': + case '{': + case '[': + case '<': + case '\u00A2': + case '\u00A9': + case '\u00C7': + case '\u00E7': ch = 'c'; break; + case '\u00D0': + case '\u00F0': ch = 'd'; break; + case '3': + case '\u20AC': + case '&': + case '\u00A3': ch = 'e'; break; + case '6': + case '9': ch = 'g'; break; + case '#': ch = 'h'; break; + case '1': + case '!': + case '|': + case '\u00A1': + case '\u00A6': ch = 'i'; break; + case '\u00D1': + case '\u00F1': ch = 'n'; break; + case '0': + case '*': + case '\u00A4': // Currency + case '\u00B0': // Degree + case '\u00D8': + case '\u00F8': ch = 'o'; break; + case '\u00AE': ch = 'r'; break; + case '$': + case '5': + case '\u00A7': ch = 's'; break; + case '+': + case '7': ch = 't'; break; + case '\u00B5': ch = 'u'; break; + case '%': + case '\u00D7': ch = 'x'; break; + case '\u00A5': + case '\u00DD': + case '\u00FD': + case '\u00FF': ch = 'y'; break; + case '2': ch = 'z'; break; + default: ch = chLeet; break; + } + + return ch; + } + + private static int HammingDist(char[] v1, int iOffset1, + char[] v2, int iOffset2, int nLength) + { + int nDist = 0; + for(int i = 0; i < nLength; ++i) + { + if(v1[iOffset1 + i] != v2[iOffset2 + i]) ++nDist; + } + + return nDist; + } + + private static void FindRepetitions(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + char[] v = new char[n]; + Array.Copy(vPassword, v, n); + + char chErased = char.MaxValue; + for(int m = (n / 2); m >= 3; --m) + { + for(int x1 = 0; x1 <= (n - (2 * m)); ++x1) + { + bool bFoundRep = false; + + for(int x2 = (x1 + m); x2 <= (n - m); ++x2) + { + if(PartsEqual(v, x1, x2, m)) + { + double dblCost = Log2(x1 + 1) + Log2(m); + vPatterns[x2].Add(new QePatternInstance(x2, m, + PatternID.Repetition, dblCost)); + + ErasePart(v, x2, m, ref chErased); + bFoundRep = true; + } + } + + if(bFoundRep) ErasePart(v, x1, m, ref chErased); + } + } + } + + private static bool PartsEqual(char[] v, int x1, int x2, int nLength) + { + for(int i = 0; i < nLength; ++i) + { + if(v[x1 + i] != v[x2 + i]) return false; + } + + return true; + } + + private static void ErasePart(char[] v, int i, int n, ref char chErased) + { + for(int j = 0; j < n; ++j) + { + v[i + j] = chErased; + --chErased; + } + } + + private static void FindNumbers(char[] vPassword, + List[] vPatterns) + { + int n = vPassword.Length; + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < n; ++i) + { + char ch = vPassword[i]; + if((ch >= '0') && (ch <= '9')) sb.Append(ch); + else + { + AddNumberPattern(vPatterns, sb.ToString(), i - sb.Length); + sb.Remove(0, sb.Length); + } + } + AddNumberPattern(vPatterns, sb.ToString(), n - sb.Length); + } + + private static void AddNumberPattern(List[] vPatterns, + string strNumber, int i) + { + if(strNumber.Length <= 2) return; + + int nZeros = 0; + for(int j = 0; j < strNumber.Length; ++j) + { + if(strNumber[j] != '0') break; + ++nZeros; + } + + double dblCost = Log2(nZeros + 1); + if(nZeros < strNumber.Length) + { + string strNonZero = strNumber.Substring(nZeros); + +#if KeePassLibSD + try { dblCost += Log2(double.Parse(strNonZero)); } + catch(Exception) { Debug.Assert(false); return; } +#else + double d; + if(double.TryParse(strNonZero, out d)) + dblCost += Log2(d); + else { Debug.Assert(false); return; } +#endif + } + + vPatterns[i].Add(new QePatternInstance(i, strNumber.Length, + PatternID.Number, dblCost)); + } + + private static void FindDiffSeqs(char[] vPassword, + List[] vPatterns) + { + int d = int.MinValue, p = 0; + string str = new string(vPassword) + new string(char.MaxValue, 1); + + for(int i = 1; i < str.Length; ++i) + { + int dCur = (int)str[i] - (int)str[i - 1]; + if(dCur != d) + { + if((i - p) >= 3) // At least 3 chars involved + { + QeCharType ct = GetCharType(str[p]); + double dblCost = ct.CharSize + Log2(i - p - 1); + + vPatterns[p].Add(new QePatternInstance(p, + i - p, PatternID.DiffSeq, dblCost)); + } + + d = dCur; + p = i - 1; + } + } + } + + private static double Log2(double dblValue) + { +#if KeePassLibSD + return (Math.Log(dblValue) / Math.Log(2.0)); +#else + return Math.Log(dblValue, 2.0); +#endif + } } } diff --git a/src/KeePassLib2Android/Cryptography/SelfTest.cs b/src/KeePassLib2Android/Cryptography/SelfTest.cs index 6ebf07b9..7817a9f2 100644 --- a/src/KeePassLib2Android/Cryptography/SelfTest.cs +++ b/src/KeePassLib2Android/Cryptography/SelfTest.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -19,10 +19,11 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Security; using System.Security.Cryptography; using System.Text; +using System.Globalization; +using System.Diagnostics; using KeePassLib.Cryptography.Cipher; using KeePassLib.Keys; @@ -77,6 +78,7 @@ namespace KeePassLib.Cryptography internal static void TestFipsComplianceProblems() { +#if !KeePassRT try { new RijndaelManaged(); } catch(Exception exAes) { @@ -88,10 +90,12 @@ namespace KeePassLib.Cryptography { throw new SecurityException("SHA-256: " + exSha256.Message); } +#endif } private static void TestRijndael() { +#if !KeePassRT // Test vector (official ECB test vector #356) byte[] pbIV = new byte[16]; byte[] pbTestKey = new byte[32]; @@ -124,6 +128,7 @@ namespace KeePassLib.Cryptography if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT)) throw new SecurityException(KLRes.EncAlgorithmAes + "."); +#endif } private static void TestSalsa20() @@ -224,26 +229,27 @@ namespace KeePassLib.Cryptography if(!MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), pb)) throw new InvalidOperationException("GZip"); - pb = Encoding.ASCII.GetBytes("012345678901234567890a"); - byte[] pbN = Encoding.ASCII.GetBytes("9012"); + Encoding enc = StrUtil.Utf8; + pb = enc.GetBytes("012345678901234567890a"); + byte[] pbN = enc.GetBytes("9012"); if(MemUtil.IndexOf(pb, pbN) != 9) throw new InvalidOperationException("MemUtil-1"); - pbN = Encoding.ASCII.GetBytes("01234567890123"); + pbN = enc.GetBytes("01234567890123"); if(MemUtil.IndexOf(pb, pbN) != 0) throw new InvalidOperationException("MemUtil-2"); - pbN = Encoding.ASCII.GetBytes("a"); + pbN = enc.GetBytes("a"); if(MemUtil.IndexOf(pb, pbN) != 21) throw new InvalidOperationException("MemUtil-3"); - pbN = Encoding.ASCII.GetBytes("0a"); + pbN = enc.GetBytes("0a"); if(MemUtil.IndexOf(pb, pbN) != 20) throw new InvalidOperationException("MemUtil-4"); - pbN = Encoding.ASCII.GetBytes("1"); + pbN = enc.GetBytes("1"); if(MemUtil.IndexOf(pb, pbN) != 1) throw new InvalidOperationException("MemUtil-5"); - pbN = Encoding.ASCII.GetBytes("b"); + pbN = enc.GetBytes("b"); if(MemUtil.IndexOf(pb, pbN) >= 0) throw new InvalidOperationException("MemUtil-6"); - pbN = Encoding.ASCII.GetBytes("012b"); + pbN = enc.GetBytes("012b"); if(MemUtil.IndexOf(pb, pbN) >= 0) throw new InvalidOperationException("MemUtil-7"); #endif @@ -251,8 +257,8 @@ namespace KeePassLib.Cryptography private static void TestHmacOtp() { -#if (DEBUG && !KeePassLibSD) - byte[] pbSecret = Encoding.ASCII.GetBytes("12345678901234567890"); +#if (DEBUG && !KeePassLibSD && !KeePassRT) + byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890"); string[] vExp = new string[]{ "755224", "287082", "359152", "969429", "338314", "254676", "287922", "162583", "399871", "520489" }; @@ -268,7 +274,9 @@ namespace KeePassLib.Cryptography private static void TestProtectedObjects() { #if DEBUG - byte[] pbData = Encoding.ASCII.GetBytes("Test Test Test Test"); + Encoding enc = StrUtil.Utf8; + + byte[] pbData = enc.GetBytes("Test Test Test Test"); ProtectedBinary pb = new ProtectedBinary(true, pbData); if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-1"); @@ -277,8 +285,8 @@ namespace KeePassLib.Cryptography throw new SecurityException("ProtectedBinary-2"); if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-3"); - byte[] pbData2 = Encoding.ASCII.GetBytes("Test Test Test Test"); - byte[] pbData3 = Encoding.ASCII.GetBytes("Test Test Test Test Test"); + byte[] pbData2 = enc.GetBytes("Test Test Test Test"); + byte[] pbData3 = enc.GetBytes("Test Test Test Test Test"); ProtectedBinary pb2 = new ProtectedBinary(true, pbData2); ProtectedBinary pb3 = new ProtectedBinary(true, pbData3); if(!pb.Equals(pb2)) throw new SecurityException("ProtectedBinary-4"); @@ -301,8 +309,7 @@ namespace KeePassLib.Cryptography throw new SecurityException("ProtectedString-3"); ps = new ProtectedString(true, "Test"); - ProtectedString ps2 = new ProtectedString(true, - StrUtil.Utf8.GetBytes("Test")); + ProtectedString ps2 = new ProtectedString(true, enc.GetBytes("Test")); if(ps.IsEmpty) throw new SecurityException("ProtectedString-4"); pbData = ps.ReadUtf8(); pbData2 = ps2.ReadUtf8(); @@ -362,6 +369,48 @@ namespace KeePassLib.Cryptography throw new InvalidOperationException("StrUtil-V5"); if(StrUtil.VersionToString(0x0000000000070000UL, true) != "0.0.7") throw new InvalidOperationException("StrUtil-V6"); + + if(StrUtil.RtfEncodeChar('\u0000') != "\\u0?") + throw new InvalidOperationException("StrUtil-Rtf1"); + if(StrUtil.RtfEncodeChar('\u7FFF') != "\\u32767?") + throw new InvalidOperationException("StrUtil-Rtf2"); + if(StrUtil.RtfEncodeChar('\u8000') != "\\u-32768?") + throw new InvalidOperationException("StrUtil-Rtf3"); + if(StrUtil.RtfEncodeChar('\uFFFF') != "\\u-1?") + throw new InvalidOperationException("StrUtil-Rtf4"); + + if(!StrUtil.StringToBool(Boolean.TrueString)) + throw new InvalidOperationException("StrUtil-Bool1"); + if(StrUtil.StringToBool(Boolean.FalseString)) + throw new InvalidOperationException("StrUtil-Bool2"); + + if(StrUtil.Count("Abracadabra", "a") != 4) + throw new InvalidOperationException("StrUtil-Count1"); + if(StrUtil.Count("Bla", "U") != 0) + throw new InvalidOperationException("StrUtil-Count2"); + if(StrUtil.Count("AAAAA", "AA") != 4) + throw new InvalidOperationException("StrUtil-Count3"); + + const string sU = "data:mytype;base64,"; + if(!StrUtil.IsDataUri(sU)) + throw new InvalidOperationException("StrUtil-DataUri1"); + if(!StrUtil.IsDataUri(sU, "mytype")) + throw new InvalidOperationException("StrUtil-DataUri2"); + if(StrUtil.IsDataUri(sU, "notmytype")) + throw new InvalidOperationException("StrUtil-DataUri3"); + + uint u = 0x7FFFFFFFU; + if(u.ToString(NumberFormatInfo.InvariantInfo) != "2147483647") + throw new InvalidOperationException("StrUtil-Inv1"); + if(uint.MaxValue.ToString(NumberFormatInfo.InvariantInfo) != + "4294967295") + throw new InvalidOperationException("StrUtil-Inv2"); + if(long.MinValue.ToString(NumberFormatInfo.InvariantInfo) != + "-9223372036854775808") + throw new InvalidOperationException("StrUtil-Inv3"); + if(short.MinValue.ToString(NumberFormatInfo.InvariantInfo) != + "-32768") + throw new InvalidOperationException("StrUtil-Inv4"); #endif } @@ -396,6 +445,13 @@ namespace KeePassLib.Cryptography str = UrlUtil.MakeAbsolutePath(strBase, strRel); if(!str.Equals(strDoc)) throw new InvalidOperationException("UrlUtil-R2"); + + str = UrlUtil.GetQuotedAppPath(" \"Test\" \"%1\" "); + if(str != "Test") throw new InvalidOperationException("UrlUtil-Q1"); + str = UrlUtil.GetQuotedAppPath("C:\\Program Files\\Test.exe"); + if(str != "C:\\Program Files\\Test.exe") throw new InvalidOperationException("UrlUtil-Q2"); + str = UrlUtil.GetQuotedAppPath("Reg.exe \"Test\" \"Test 2\""); + if(str != "Reg.exe \"Test\" \"Test 2\"") throw new InvalidOperationException("UrlUtil-Q3"); #endif } } diff --git a/src/KeePassLib2Android/Keys/CompositeKey.cs b/src/KeePassLib2Android/Keys/CompositeKey.cs index 614408c1..9c0a2a38 100644 --- a/src/KeePassLib2Android/Keys/CompositeKey.cs +++ b/src/KeePassLib2Android/Keys/CompositeKey.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -24,6 +24,11 @@ using System.Diagnostics; using System.IO; using System.Security.Cryptography; +#if KeePassRT +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +#endif + using KeePassLib.Native; using KeePassLib.Resources; using KeePassLib.Security; @@ -103,6 +108,7 @@ namespace KeePassLib.Keys return m_vUserKeys.Remove(pKey); } +#if !KeePassRT /// /// Test whether the composite key contains a specific type of /// user keys (password, key file, ...). If at least one user @@ -144,6 +150,7 @@ namespace KeePassLib.Keys return null; } +#endif /// /// Creates the composite key from the supplied user key sources (password, @@ -270,6 +277,17 @@ namespace KeePassLib.Keys public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, ulong uNumRounds) { +#if KeePassRT + KeyParameter kp = new KeyParameter(pbKeySeed32); + AesEngine aes = new AesEngine(); + aes.Init(true, kp); + + for(ulong i = 0; i < uNumRounds; ++i) + { + aes.ProcessBlock(pbNewKey32, 0, pbNewKey32, 0); + aes.ProcessBlock(pbNewKey32, 16, pbNewKey32, 16); + } +#else byte[] pbIV = new byte[16]; Array.Clear(pbIV, 0, pbIV.Length); @@ -301,6 +319,7 @@ namespace KeePassLib.Keys iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0); iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16); } +#endif return true; } @@ -325,9 +344,6 @@ namespace KeePassLib.Keys if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds)) return uRounds; - byte[] pbIV = new byte[16]; - Array.Clear(pbIV, 0, pbIV.Length); - byte[] pbKey = new byte[32]; byte[] pbNewKey = new byte[32]; for(int i = 0; i < pbKey.Length; ++i) @@ -336,6 +352,14 @@ namespace KeePassLib.Keys pbNewKey[i] = (byte)i; } +#if KeePassRT + KeyParameter kp = new KeyParameter(pbKey); + AesEngine aes = new AesEngine(); + aes.Init(true, kp); +#else + byte[] pbIV = new byte[16]; + Array.Clear(pbIV, 0, pbIV.Length); + RijndaelManaged r = new RijndaelManaged(); if(r.BlockSize != 128) // AES block size { @@ -358,18 +382,21 @@ namespace KeePassLib.Keys Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!"); return PwDefs.DefaultKeyEncryptionRounds; } - - DateTime dtStart = DateTime.Now; - TimeSpan ts; - double dblReqMillis = uMilliseconds; +#endif uRounds = 0; + int tStart = Environment.TickCount; while(true) { for(ulong j = 0; j < uStep; ++j) { +#if KeePassRT + aes.ProcessBlock(pbNewKey, 0, pbNewKey, 0); + aes.ProcessBlock(pbNewKey, 16, pbNewKey, 16); +#else iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0); iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16); +#endif } uRounds += uStep; @@ -379,8 +406,8 @@ namespace KeePassLib.Keys break; } - ts = DateTime.Now - dtStart; - if(ts.TotalMilliseconds > dblReqMillis) break; + uint tElapsed = (uint)(Environment.TickCount - tStart); + if(tElapsed > uMilliseconds) break; } return uRounds; diff --git a/src/KeePassLib2Android/Keys/KcpKeyFile.cs b/src/KeePassLib2Android/Keys/KcpKeyFile.cs index 3a0a71a0..367b6091 100644 --- a/src/KeePassLib2Android/Keys/KcpKeyFile.cs +++ b/src/KeePassLib2Android/Keys/KcpKeyFile.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -26,6 +26,7 @@ using System.Security.Cryptography; using System.Diagnostics; using KeePassLib.Cryptography; +using KeePassLib.Resources; using KeePassLib.Security; using KeePassLib.Serialization; using KeePassLib.Utility; @@ -60,19 +61,47 @@ namespace KeePassLib.Keys public KcpKeyFile(string strKeyFile) { - Construct(IOConnectionInfo.FromPath(strKeyFile)); + Construct(IOConnectionInfo.FromPath(strKeyFile), false); + } + + public KcpKeyFile(string strKeyFile, bool bThrowIfDbFile) + { + Construct(IOConnectionInfo.FromPath(strKeyFile), bThrowIfDbFile); } public KcpKeyFile(IOConnectionInfo iocKeyFile) { - Construct(iocKeyFile); + Construct(iocKeyFile, false); } - private void Construct(IOConnectionInfo iocFile) + public KcpKeyFile(IOConnectionInfo iocKeyFile, bool bThrowIfDbFile) + { + Construct(iocKeyFile, bThrowIfDbFile); + } + + private void Construct(IOConnectionInfo iocFile, bool bThrowIfDbFile) { byte[] pbFileData = IOConnection.ReadFile(iocFile); if(pbFileData == null) throw new FileNotFoundException(); + if(bThrowIfDbFile && (pbFileData.Length >= 8)) + { + uint uSig1 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 0, 4)); + uint uSig2 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 4, 4)); + + if(((uSig1 == KdbxFile.FileSignature1) && + (uSig2 == KdbxFile.FileSignature2)) || + ((uSig1 == KdbxFile.FileSignaturePreRelease1) && + (uSig2 == KdbxFile.FileSignaturePreRelease2)) || + ((uSig1 == KdbxFile.FileSignatureOld1) && + (uSig2 == KdbxFile.FileSignatureOld2))) +#if KeePassLibSD + throw new Exception(KLRes.KeyFileDbSel); +#else + throw new InvalidDataException(KLRes.KeyFileDbSel); +#endif + } + byte[] pbKey = LoadXmlKeyFile(pbFileData); if(pbKey == null) pbKey = LoadKeyFile(pbFileData); @@ -124,7 +153,7 @@ namespace KeePassLib.Keys try { - string strHex = Encoding.ASCII.GetString(pbFileData, 0, 64); + string strHex = StrUtil.Utf8.GetString(pbFileData, 0, 64); if(!StrUtil.IsHexString(strHex, true)) return null; byte[] pbKey = MemUtil.HexStringToByteArray(strHex); @@ -235,7 +264,10 @@ namespace KeePassLib.Keys Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); - XmlTextWriter xtw = new XmlTextWriter(strFile, StrUtil.Utf8); + IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); + Stream sOut = IOConnection.OpenWrite(ioc); + + XmlTextWriter xtw = new XmlTextWriter(sOut, StrUtil.Utf8); xtw.WriteStartDocument(); xtw.WriteWhitespace("\r\n"); @@ -266,6 +298,8 @@ namespace KeePassLib.Keys xtw.WriteWhitespace("\r\n"); xtw.WriteEndDocument(); // End KeyFile xtw.Close(); + + sOut.Close(); } } } diff --git a/src/KeePassLib2Android/Keys/KcpUserAccount.cs b/src/KeePassLib2Android/Keys/KcpUserAccount.cs index aefb02c9..00b9f2ae 100644 --- a/src/KeePassLib2Android/Keys/KcpUserAccount.cs +++ b/src/KeePassLib2Android/Keys/KcpUserAccount.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -80,8 +80,12 @@ namespace KeePassLib.Keys private static string GetUserKeyFilePath(bool bCreate) { +#if KeePassRT + string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path; +#else string strUserDir = Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData); +#endif strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); strUserDir += PwDefs.ShortProductName; diff --git a/src/KeePassLib2Android/Native/NativeLib.cs b/src/KeePassLib2Android/Native/NativeLib.cs index 26bf031b..7041e9d9 100644 --- a/src/KeePassLib2Android/Native/NativeLib.cs +++ b/src/KeePassLib2Android/Native/NativeLib.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -20,6 +20,8 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Windows.Forms; +using System.Threading; using System.Diagnostics; using KeePassLib.Utility; @@ -87,9 +89,13 @@ namespace KeePassLib.Native { if(m_platID.HasValue) return m_platID.Value; +#if KeePassRT + m_platID = PlatformID.Win32NT; +#else m_platID = Environment.OSVersion.Platform; +#endif -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) // Mono returns PlatformID.Unix on Mac OS X, workaround this if(m_platID.Value == PlatformID.Unix) { @@ -102,7 +108,7 @@ namespace KeePassLib.Native return m_platID.Value; } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) public static string RunConsoleApp(string strAppPath, string strParams) { return RunConsoleApp(strAppPath, strParams, null); @@ -110,40 +116,98 @@ namespace KeePassLib.Native public static string RunConsoleApp(string strAppPath, string strParams, string strStdInput) + { + return RunConsoleApp(strAppPath, strParams, strStdInput, + (AppRunFlags.GetStdOutput | AppRunFlags.WaitForExit)); + } + + private delegate string RunProcessDelegate(); + + public static string RunConsoleApp(string strAppPath, string strParams, + string strStdInput, AppRunFlags f) { if(strAppPath == null) throw new ArgumentNullException("strAppPath"); if(strAppPath.Length == 0) throw new ArgumentException("strAppPath"); - try + bool bStdOut = ((f & AppRunFlags.GetStdOutput) != AppRunFlags.None); + + RunProcessDelegate fnRun = delegate() { - ProcessStartInfo psi = new ProcessStartInfo(); - - psi.CreateNoWindow = true; - psi.FileName = strAppPath; - psi.WindowStyle = ProcessWindowStyle.Hidden; - psi.UseShellExecute = false; - psi.RedirectStandardOutput = true; - - if(strStdInput != null) psi.RedirectStandardInput = true; - - if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams; - - Process p = Process.Start(psi); - - if(strStdInput != null) + try { - p.StandardInput.Write(strStdInput); - p.StandardInput.Close(); + ProcessStartInfo psi = new ProcessStartInfo(); + + psi.CreateNoWindow = true; + psi.FileName = strAppPath; + psi.WindowStyle = ProcessWindowStyle.Hidden; + psi.UseShellExecute = false; + psi.RedirectStandardOutput = bStdOut; + + if(strStdInput != null) psi.RedirectStandardInput = true; + + if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams; + + Process p = Process.Start(psi); + + if(strStdInput != null) + { + p.StandardInput.Write(strStdInput); + p.StandardInput.Close(); + } + + string strOutput = string.Empty; + if(bStdOut) strOutput = p.StandardOutput.ReadToEnd(); + + if((f & AppRunFlags.WaitForExit) != AppRunFlags.None) + p.WaitForExit(); + else if((f & AppRunFlags.GCKeepAlive) != AppRunFlags.None) + { + Thread th = new Thread(delegate() + { + try { p.WaitForExit(); } + catch(Exception) { Debug.Assert(false); } + }); + th.Start(); + } + + return strOutput; + } + catch(Exception) { Debug.Assert(false); } + + return null; + }; + + if((f & AppRunFlags.DoEvents) != AppRunFlags.None) + { + List
lDisabledForms = new List(); + if((f & AppRunFlags.DisableForms) != AppRunFlags.None) + { + foreach(Form form in Application.OpenForms) + { + if(!form.Enabled) continue; + + lDisabledForms.Add(form); + form.Enabled = false; + } } - string strOutput = p.StandardOutput.ReadToEnd(); - p.WaitForExit(); + IAsyncResult ar = fnRun.BeginInvoke(null, null); - return strOutput; + while(!ar.AsyncWaitHandle.WaitOne(0)) + { + Application.DoEvents(); + Thread.Sleep(2); + } + + string strRet = fnRun.EndInvoke(ar); + + for(int i = lDisabledForms.Count - 1; i >= 0; --i) + lDisabledForms[i].Enabled = true; + + return strRet; } - catch(Exception) { Debug.Assert(false); } - return null; + return fnRun(); } #endif diff --git a/src/KeePassLib2Android/Native/NativeMethods.cs b/src/KeePassLib2Android/Native/NativeMethods.cs index 42036622..b8d6b041 100644 --- a/src/KeePassLib2Android/Native/NativeMethods.cs +++ b/src/KeePassLib2Android/Native/NativeMethods.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -103,7 +103,7 @@ namespace KeePassLib.Native return TransformKeyBenchmark32(uTimeMs); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) [DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] internal static extern int StrCmpLogicalW(string x, string y); @@ -118,7 +118,7 @@ namespace KeePassLib.Native private static void TestNaturalComparisonsSupport() { -#if KeePassLibSD +#if (KeePassLibSD || KeePassRT) #warning No native natural comparisons supported. m_bSupportsLogicalCmp = false; #else @@ -147,7 +147,7 @@ namespace KeePassLib.Native if(m_bSupportsLogicalCmp.HasValue == false) TestNaturalComparisonsSupport(); if(m_bSupportsLogicalCmp.Value == false) return 0; -#if KeePassLibSD +#if (KeePassLibSD || KeePassRT) #warning No native natural comparisons supported. return x.CompareTo(y); #else @@ -158,6 +158,9 @@ namespace KeePassLib.Native internal static string GetUserRuntimeDir() { #if !KeePassLibSD +#if KeePassRT + string strRtDir = Windows.Storage.ApplicationData.Current.LocalFolder.Path; +#else string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); if(string.IsNullOrEmpty(strRtDir)) strRtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); @@ -166,6 +169,7 @@ namespace KeePassLib.Native Debug.Assert(false); return Path.GetTempPath(); // Not UrlUtil (otherwise cyclic) } +#endif strRtDir = UrlUtil.EnsureTerminatingSeparator(strRtDir, false); strRtDir += PwDefs.ShortProductName; diff --git a/src/KeePassLib2Android/Properties/AssemblyInfo.cs b/src/KeePassLib2Android/Properties/AssemblyInfo.cs index e55beedf..554155f1 100644 --- a/src/KeePassLib2Android/Properties/AssemblyInfo.cs +++ b/src/KeePassLib2Android/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -27,7 +27,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Dominik Reichl")] [assembly: AssemblyProduct("KeePassLib")] -[assembly: AssemblyCopyright("Copyright © 2003-2012 Dominik Reichl")] +[assembly: AssemblyCopyright("Copyright © 2003-2013 Dominik Reichl")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -38,5 +38,5 @@ using System.Runtime.InteropServices; [assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")] // Assembly version information -[assembly: AssemblyVersion("2.20.1.*")] -[assembly: AssemblyFileVersion("2.20.1.0")] +[assembly: AssemblyVersion("2.24.0.*")] +[assembly: AssemblyFileVersion("2.24.0.0")] diff --git a/src/KeePassLib2Android/PwCustomIcon.cs b/src/KeePassLib2Android/PwCustomIcon.cs index f32bc1a8..cb999f7a 100644 --- a/src/KeePassLib2Android/PwCustomIcon.cs +++ b/src/KeePassLib2Android/PwCustomIcon.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -54,8 +54,8 @@ namespace KeePassLib { Debug.Assert(pwUuid != null); if(pwUuid == null) throw new ArgumentNullException("pwUuid"); - Debug.Assert(pwUuid != PwUuid.Zero); - if(pwUuid == PwUuid.Zero) throw new ArgumentException("pwUuid == 0"); + Debug.Assert(!pwUuid.Equals(PwUuid.Zero)); + if(pwUuid.Equals(PwUuid.Zero)) throw new ArgumentException("pwUuid == 0"); Debug.Assert(pbImageDataPng != null); if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng"); diff --git a/src/KeePassLib2Android/PwDatabase.cs b/src/KeePassLib2Android/PwDatabase.cs index d3ef6570..1a1611b6 100644 --- a/src/KeePassLib2Android/PwDatabase.cs +++ b/src/KeePassLib2Android/PwDatabase.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -779,12 +779,12 @@ namespace KeePassLib bool bOrgBackup = !bEquals; if(mm != PwMergeMethod.OverwriteExisting) - bOrgBackup &= (pe.LastModificationTime > peLocal.LastModificationTime); + bOrgBackup &= (TimeUtil.CompareLastMod(pe, peLocal, true) > 0); bOrgBackup &= !pe.HasBackupOfData(peLocal, false, true); if(bOrgBackup) peLocal.CreateBackup(null); // Maintain at end bool bSrcBackup = !bEquals && (mm != PwMergeMethod.OverwriteExisting); - bSrcBackup &= (peLocal.LastModificationTime > pe.LastModificationTime); + bSrcBackup &= (TimeUtil.CompareLastMod(peLocal, pe, true) > 0); bSrcBackup &= !peLocal.HasBackupOfData(pe, false, true); if(bSrcBackup) pe.CreateBackup(null); // Maintain at end @@ -870,9 +870,12 @@ namespace KeePassLib foreach(PwDeletedObject pdo in listDelObjects) { - if(pg.Uuid.EqualsValue(pdo.Uuid)) - if(pg.LastModificationTime < pdo.DeletionTime) + if(pg.Uuid.Equals(pdo.Uuid)) + { + if(TimeUtil.Compare(pg.LastModificationTime, + pdo.DeletionTime, true) < 0) listGroupsToDelete.AddLast(pg); + } } return ((m_slStatus != null) ? m_slStatus.ContinueWork() : true); @@ -882,9 +885,12 @@ namespace KeePassLib { foreach(PwDeletedObject pdo in listDelObjects) { - if(pe.Uuid.EqualsValue(pdo.Uuid)) - if(pe.LastModificationTime < pdo.DeletionTime) + if(pe.Uuid.Equals(pdo.Uuid)) + { + if(TimeUtil.Compare(pe.LastModificationTime, + pdo.DeletionTime, true) < 0) listEntriesToDelete.AddLast(pe); + } } return ((m_slStatus != null) ? m_slStatus.ContinueWork() : true); @@ -905,7 +911,7 @@ namespace KeePassLib foreach(PwDeletedObject pdoLocal in m_vDeletedObjects) { - if(pdoNew.Uuid.EqualsValue(pdoLocal.Uuid)) + if(pdoNew.Uuid.Equals(pdoLocal.Uuid)) { bCopy = false; @@ -939,7 +945,7 @@ namespace KeePassLib PwGroup pgOrgParent = ptOrg.ParentGroup; PwGroup pgSrcParent = ptSrc.ParentGroup; - if(pgOrgParent.Uuid.EqualsValue(pgSrcParent.Uuid)) + if(pgOrgParent.Uuid.Equals(pgSrcParent.Uuid)) { pg.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ? ptSrc.LocationChanged : ptOrg.LocationChanged); @@ -959,7 +965,7 @@ namespace KeePassLib } else { - Debug.Assert(pg.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid)); + Debug.Assert(pg.ParentGroup.Uuid.Equals(pgOrgParent.Uuid)); Debug.Assert(pg.LocationChanged == ptOrg.LocationChanged); } } @@ -985,7 +991,7 @@ namespace KeePassLib PwGroup pgOrg = ptOrg.ParentGroup; PwGroup pgSrc = ptSrc.ParentGroup; - if(pgOrg.Uuid.EqualsValue(pgSrc.Uuid)) + if(pgOrg.Uuid.Equals(pgSrc.Uuid)) { pe.LocationChanged = ((ptSrc.LocationChanged > ptOrg.LocationChanged) ? ptSrc.LocationChanged : ptOrg.LocationChanged); @@ -1003,7 +1009,7 @@ namespace KeePassLib } else { - Debug.Assert(pe.ParentGroup.Uuid.EqualsValue(pgOrg.Uuid)); + Debug.Assert(pe.ParentGroup.Uuid.Equals(pgOrg.Uuid)); Debug.Assert(pe.LocationChanged == ptOrg.LocationChanged); } } @@ -1080,7 +1086,7 @@ namespace KeePassLib bool bAdded = false; foreach(PwUuid puBefore in qRelBefore) { - if(puBefore.EqualsValue(pt.Uuid)) + if(puBefore.Equals(pt.Uuid)) { qBefore.Enqueue(pt); bAdded = true; @@ -1091,7 +1097,7 @@ namespace KeePassLib foreach(PwUuid puAfter in qRelAfter) { - if(puAfter.EqualsValue(pt.Uuid)) + if(puAfter.Equals(pt.Uuid)) { qAfter.Enqueue(pt); bAdded = true; @@ -1186,7 +1192,7 @@ namespace KeePassLib { PwUuid pw = vItems[i].Uuid; - if(pw.EqualsValue(pwPivot)) bBefore = false; + if(pw.Equals(pwPivot)) bBefore = false; else if(bBefore) qBefore.Enqueue(pw); else qAfter.Enqueue(pw); } @@ -1222,8 +1228,8 @@ namespace KeePassLib PwGroup pgSrcParent = ptSrc.ParentGroup; if(pgSrcParent == null) return true; // Root might be in tree - if(!ptFirst.ParentGroup.Uuid.EqualsValue(pgOrgParent.Uuid)) return true; - if(!pgOrgParent.Uuid.EqualsValue(pgSrcParent.Uuid)) return true; + if(!ptFirst.ParentGroup.Uuid.Equals(pgOrgParent.Uuid)) return true; + if(!pgOrgParent.Uuid.Equals(pgSrcParent.Uuid)) return true; List lOrg = pgOrgParent.GetObjects(false, bEntries); List lSrc = pgSrcParent.GetObjects(false, bEntries); @@ -1235,8 +1241,8 @@ namespace KeePassLib IStructureItem pt = vItems.GetAt(u); Debug.Assert(pt.ParentGroup == ptFirst.ParentGroup); - if(!pt.Uuid.EqualsValue(lOrg[(int)u].Uuid)) return true; - if(!pt.Uuid.EqualsValue(lSrc[(int)u].Uuid)) return true; + if(!pt.Uuid.Equals(lOrg[(int)u].Uuid)) return true; + if(!pt.Uuid.Equals(lSrc[(int)u].Uuid)) return true; if(pt.LocationChanged != lOrg[(int)u].LocationChanged) return true; if(pt.LocationChanged != lSrc[(int)u].LocationChanged) return true; } @@ -1303,7 +1309,7 @@ namespace KeePassLib private void MergeEntryHistory(PwEntry pe, PwEntry peSource, PwMergeMethod mm) { - if(!pe.Uuid.EqualsValue(peSource.Uuid)) { Debug.Assert(false); return; } + if(!pe.Uuid.Equals(peSource.Uuid)) { Debug.Assert(false); return; } if(pe.History.UCount == peSource.History.UCount) { @@ -1323,27 +1329,32 @@ namespace KeePassLib if((m_slStatus != null) && !m_slStatus.ContinueWork()) return; - SortedList list = new SortedList(); + IDictionary dict = +#if KeePassLibSD + new SortedList(); +#else + new SortedDictionary(); +#endif foreach(PwEntry peOrg in pe.History) { - list[peOrg.LastModificationTime] = peOrg; + dict[peOrg.LastModificationTime] = peOrg; } foreach(PwEntry peSrc in peSource.History) { DateTime dt = peSrc.LastModificationTime; - if(list.ContainsKey(dt)) + if(dict.ContainsKey(dt)) { if(mm == PwMergeMethod.OverwriteExisting) - list[dt] = peSrc.CloneDeep(); + dict[dt] = peSrc.CloneDeep(); } - else list[dt] = peSrc.CloneDeep(); + else dict[dt] = peSrc.CloneDeep(); } pe.History.Clear(); - foreach(KeyValuePair kvpCur in list) + foreach(KeyValuePair kvpCur in dict) { - Debug.Assert(kvpCur.Value.Uuid.EqualsValue(pe.Uuid)); + Debug.Assert(kvpCur.Value.Uuid.Equals(pe.Uuid)); Debug.Assert(kvpCur.Value.History.UCount == 0); pe.History.Add(kvpCur.Value); } @@ -1385,20 +1396,34 @@ namespace KeePassLib /// Index of the icon. public int GetCustomIconIndex(PwUuid pwIconId) { - int nIndex = 0; - - foreach(PwCustomIcon pwci in m_vCustomIcons) + for(int i = 0; i < m_vCustomIcons.Count; ++i) { - if(pwci.Uuid.EqualsValue(pwIconId)) - return nIndex; - - ++nIndex; + PwCustomIcon pwci = m_vCustomIcons[i]; + if(pwci.Uuid.Equals(pwIconId)) + return i; } // Debug.Assert(false); // Do not assert return -1; } + public int GetCustomIconIndex(byte[] pbPngData) + { + if(pbPngData == null) { Debug.Assert(false); return -1; } + + for(int i = 0; i < m_vCustomIcons.Count; ++i) + { + PwCustomIcon pwci = m_vCustomIcons[i]; + byte[] pbEx = pwci.ImageDataPng; + if(pbEx == null) { Debug.Assert(false); continue; } + + if(MemUtil.ArraysEqual(pbEx, pbPngData)) + return i; + } + + return -1; + } + /// /// Get a custom icon. This function can return null, if /// no cached image of the icon is available. @@ -1422,11 +1447,11 @@ namespace KeePassLib GroupHandler gh = delegate(PwGroup pg) { PwUuid uuidThis = pg.CustomIconUuid; - if(uuidThis.EqualsValue(PwUuid.Zero)) return true; + if(uuidThis.Equals(PwUuid.Zero)) return true; foreach(PwUuid uuidDelete in vUuidsToDelete) { - if(uuidThis.EqualsValue(uuidDelete)) + if(uuidThis.Equals(uuidDelete)) { pg.CustomIconUuid = PwUuid.Zero; break; @@ -1461,11 +1486,11 @@ namespace KeePassLib private static void RemoveCustomIconUuid(PwEntry pe, List vToDelete) { PwUuid uuidThis = pe.CustomIconUuid; - if(uuidThis.EqualsValue(PwUuid.Zero)) return; + if(uuidThis.Equals(PwUuid.Zero)) return; foreach(PwUuid uuidDelete in vToDelete) { - if(uuidThis.EqualsValue(uuidDelete)) + if(uuidThis.Equals(uuidDelete)) { pe.CustomIconUuid = PwUuid.Zero; break; @@ -1485,7 +1510,7 @@ namespace KeePassLib GroupHandler gh = delegate(PwGroup pg) { foreach(PwUuid u in l) - bAllUnique &= !pg.Uuid.EqualsValue(u); + bAllUnique &= !pg.Uuid.Equals(u); l.Add(pg.Uuid); return bAllUnique; }; @@ -1493,7 +1518,7 @@ namespace KeePassLib EntryHandler eh = delegate(PwEntry pe) { foreach(PwUuid u in l) - bAllUnique &= !pe.Uuid.EqualsValue(u); + bAllUnique &= !pe.Uuid.Equals(u); l.Add(pe.Uuid); return bAllUnique; }; @@ -1591,7 +1616,7 @@ namespace KeePassLib PwEntry peB = l.GetAt(j); if(!DupEntriesEqual(peA, peB)) continue; - bool bDeleteA = (peA.LastModificationTime <= peB.LastModificationTime); + bool bDeleteA = (TimeUtil.CompareLastMod(peA, peB, true) <= 0); if(pgRecycleBin != null) { bool bAInBin = peA.IsContainedIn(pgRecycleBin); @@ -1708,11 +1733,11 @@ namespace KeePassLib GroupHandler gh = delegate(PwGroup pg) { PwUuid pwUuid = pg.CustomIconUuid; - if((pwUuid == null) || pwUuid.EqualsValue(PwUuid.Zero)) return true; + if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true; for(int i = 0; i < lToDelete.Count; ++i) { - if(lToDelete[i].EqualsValue(pwUuid)) + if(lToDelete[i].Equals(pwUuid)) { lToDelete.RemoveAt(i); break; @@ -1725,11 +1750,11 @@ namespace KeePassLib EntryHandler eh = delegate(PwEntry pe) { PwUuid pwUuid = pe.CustomIconUuid; - if((pwUuid == null) || pwUuid.EqualsValue(PwUuid.Zero)) return true; + if((pwUuid == null) || pwUuid.Equals(PwUuid.Zero)) return true; for(int i = 0; i < lToDelete.Count; ++i) { - if(lToDelete[i].EqualsValue(pwUuid)) + if(lToDelete[i].Equals(pwUuid)) { lToDelete.RemoveAt(i); break; diff --git a/src/KeePassLib2Android/PwDefs.cs b/src/KeePassLib2Android/PwDefs.cs index 229ee44c..73f1827a 100644 --- a/src/KeePassLib2Android/PwDefs.cs +++ b/src/KeePassLib2Android/PwDefs.cs @@ -1,6 +1,6 @@ -/* +/* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -25,6 +25,7 @@ using System.Diagnostics; using KeePassLib.Delegates; using KeePassLib.Interfaces; +using KeePassLib.Serialization; namespace KeePassLib { @@ -54,20 +55,20 @@ namespace KeePassLib /// e.g. 2.19 = 0x02130000. /// It is highly recommended to use FileVersion64 instead. /// - public const uint Version32 = 0x02140100; + public const uint Version32 = 0x02180000; /// /// Version, encoded as 64-bit unsigned integer /// (component-wise, 16 bits per component). /// - public const ulong FileVersion64 = 0x0002001400010000UL; + public const ulong FileVersion64 = 0x0002001800000000UL; /// /// Version, encoded as string. /// - public const string VersionString = "2.20.1"; + public const string VersionString = "2.24"; - public const string Copyright = @"Copyright © 2003-2012 Dominik Reichl"; + public const string Copyright = @"Copyright © 2003-2013 Dominik Reichl"; /// /// Product website URL. Terminated by a forward slash. @@ -317,7 +318,11 @@ namespace KeePassLib set { m_bSearchInTags = value; } } +#if KeePassRT + private StringComparison m_scType = StringComparison.OrdinalIgnoreCase; +#else private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase; +#endif /// /// String comparison type. Specifies the condition when the specified /// text matches a group/entry string. @@ -458,4 +463,24 @@ namespace KeePassLib m_bParentsTouched = bParentsTouched; } } + + public sealed class IOAccessEventArgs : EventArgs + { + private IOConnectionInfo m_ioc; + public IOConnectionInfo IOConnectionInfo { get { return m_ioc; } } + + private IOConnectionInfo m_ioc2; + public IOConnectionInfo IOConnectionInfo2 { get { return m_ioc2; } } + + private IOAccessType m_t; + public IOAccessType Type { get { return m_t; } } + + public IOAccessEventArgs(IOConnectionInfo ioc, IOConnectionInfo ioc2, + IOAccessType t) + { + m_ioc = ioc; + m_ioc2 = ioc2; + m_t = t; + } + } } diff --git a/src/KeePassLib2Android/PwEntry.cs b/src/KeePassLib2Android/PwEntry.cs index b26bec6f..76a729d6 100644 --- a/src/KeePassLib2Android/PwEntry.cs +++ b/src/KeePassLib2Android/PwEntry.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -413,7 +413,7 @@ namespace KeePassLib bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) != PwCompareOptions.None); - if(!m_uuid.EqualsValue(pe.m_uuid)) return false; + if(!m_uuid.Equals(pe.m_uuid)) return false; if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None) { if(m_pParentGroup != pe.m_pParentGroup) return false; @@ -456,7 +456,7 @@ namespace KeePassLib } if(m_pwIcon != pe.m_pwIcon) return false; - if(!m_pwCustomIconID.EqualsValue(pe.m_pwCustomIconID)) return false; + if(!m_pwCustomIconID.Equals(pe.m_pwCustomIconID)) return false; if(m_clrForeground != pe.m_clrForeground) return false; if(m_clrBackground != pe.m_clrBackground) return false; @@ -494,10 +494,12 @@ namespace KeePassLib { Debug.Assert(peTemplate != null); if(peTemplate == null) throw new ArgumentNullException("peTemplate"); - if(bOnlyIfNewer && (peTemplate.m_tLastMod < m_tLastMod)) return; + if(bOnlyIfNewer && (TimeUtil.Compare(peTemplate.m_tLastMod, m_tLastMod, + true) < 0)) + return; // Template UUID should be the same as the current one - Debug.Assert(m_uuid.EqualsValue(peTemplate.m_uuid)); + Debug.Assert(m_uuid.Equals(peTemplate.m_uuid)); m_uuid = peTemplate.m_uuid; if(bAssignLocationChanged) @@ -692,7 +694,7 @@ namespace KeePassLib for(uint u = 0; u < m_listHistory.UCount; ++u) { PwEntry pe = m_listHistory.GetAt(u); - if(pe.LastModificationTime < dtMin) + if(TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0) { idxRemove = u; dtMin = pe.LastModificationTime; @@ -868,7 +870,13 @@ namespace KeePassLib string strB = b.Strings.ReadSafe(m_strFieldName); if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB); + +#if KeePassRT + return string.Compare(strA, strB, m_bCaseInsensitive ? + StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture); +#else return string.Compare(strA, strB, m_bCaseInsensitive); +#endif } } } diff --git a/src/KeePassLib2Android/PwEnums.cs b/src/KeePassLib2Android/PwEnums.cs index 27cde682..c6dd8673 100644 --- a/src/KeePassLib2Android/PwEnums.cs +++ b/src/KeePassLib2Android/PwEnums.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -65,6 +65,8 @@ namespace KeePassLib /// public enum PwMergeMethod { + // Do not change the explicitly assigned values, otherwise + // serialization (e.g. of Ecas triggers) breaks None = 0, OverwriteExisting = 1, KeepExisting = 2, @@ -204,4 +206,62 @@ namespace KeePassLib IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod) } + + public enum IOAccessType + { + None = 0, + + /// + /// The IO connection is being opened for reading. + /// + Read = 1, + + /// + /// The IO connection is being opened for writing. + /// + Write = 2, + + /// + /// The IO connection is being opened for testing + /// whether a file/object exists. + /// + Exists = 3, + + /// + /// The IO connection is being opened for deleting a file/object. + /// + Delete = 4, + + /// + /// The IO connection is being opened for renaming/moving a file/object. + /// + Move = 5 + } + + // public enum PwLogicalOp + // { + // None = 0, + // Or = 1, + // And = 2, + // NOr = 3, + // NAnd = 4 + // } + + [Flags] + public enum AppRunFlags + { + None = 0, + GetStdOutput = 1, + WaitForExit = 2, + + // This flag prevents any handles being garbage-collected + // before the started process has terminated, without + // blocking the current thread; + // https://sourceforge.net/p/keepass/patches/84/ + GCKeepAlive = 4, + + // https://sourceforge.net/p/keepass/patches/85/ + DoEvents = 8, + DisableForms = 16 + } } diff --git a/src/KeePassLib2Android/PwGroup.cs b/src/KeePassLib2Android/PwGroup.cs index 791e0fbe..ad9afac0 100644 --- a/src/KeePassLib2Android/PwGroup.cs +++ b/src/KeePassLib2Android/PwGroup.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -398,10 +398,12 @@ namespace KeePassLib { Debug.Assert(pgTemplate != null); if(pgTemplate == null) throw new ArgumentNullException("pgTemplate"); - if(bOnlyIfNewer && (pgTemplate.m_tLastMod < m_tLastMod)) return; + if(bOnlyIfNewer && (TimeUtil.Compare(pgTemplate.m_tLastMod, m_tLastMod, + true) < 0)) + return; // Template UUID should be the same as the current one - Debug.Assert(m_uuid.EqualsValue(pgTemplate.m_uuid)); + Debug.Assert(m_uuid.Equals(pgTemplate.m_uuid)); m_uuid = pgTemplate.m_uuid; if(bAssignLocationChanged) @@ -764,9 +766,15 @@ namespace KeePassLib Regex rx = null; if(sp.RegularExpression) { +#if KeePassRT + RegexOptions ro = RegexOptions.None; +#else RegexOptions ro = RegexOptions.Compiled; +#endif if((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) || +#if !KeePassRT (sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) || +#endif (sp.ComparisonMode == StringComparison.OrdinalIgnoreCase)) { ro |= RegexOptions.IgnoreCase; @@ -938,6 +946,30 @@ namespace KeePassLib return vTags; } +#if !KeePassLibSD + public IDictionary BuildEntryTagsDict(bool bSort) + { + IDictionary d; + if(!bSort) d = new Dictionary(StrUtil.CaseIgnoreComparer); + else d = new SortedDictionary(StrUtil.CaseIgnoreComparer); + + EntryHandler eh = delegate(PwEntry pe) + { + foreach(string strTag in pe.Tags) + { + uint u; + if(d.TryGetValue(strTag, out u)) d[strTag] = u + 1; + else d[strTag] = 1; + } + + return true; + }; + + TraverseTree(TraversalMethod.PreOrder, null, eh); + return d; + } +#endif + public void FindEntriesByTag(string strTag, PwObjectList listStorage, bool bSearchRecursive) { @@ -972,7 +1004,7 @@ namespace KeePassLib public PwGroup FindGroup(PwUuid uuid, bool bSearchRecursive) { // Do not assert on PwUuid.Zero - if(m_uuid.EqualsValue(uuid)) return this; + if(m_uuid.Equals(uuid)) return this; if(bSearchRecursive) { @@ -987,7 +1019,7 @@ namespace KeePassLib { foreach(PwGroup pg in m_listGroups) { - if(pg.m_uuid.EqualsValue(uuid)) + if(pg.m_uuid.Equals(uuid)) return pg; } } @@ -1051,7 +1083,7 @@ namespace KeePassLib { foreach(PwEntry pe in m_listEntries) { - if(pe.Uuid.EqualsValue(uuid)) return pe; + if(pe.Uuid.Equals(uuid)) return pe; } if(bSearchRecursive) @@ -1151,6 +1183,7 @@ namespace KeePassLib } } +#if !KeePassLibSD /// /// Find/create a subtree of groups. /// @@ -1164,11 +1197,23 @@ namespace KeePassLib public PwGroup FindCreateSubTree(string strTree, char[] vSeparators, bool bAllowCreate) + { + if(vSeparators == null) { Debug.Assert(false); vSeparators = new char[0]; } + + string[] v = new string[vSeparators.Length]; + for(int i = 0; i < vSeparators.Length; ++i) + v[i] = new string(vSeparators[i], 1); + + return FindCreateSubTree(strTree, v, bAllowCreate); + } + + public PwGroup FindCreateSubTree(string strTree, string[] vSeparators, + bool bAllowCreate) { Debug.Assert(strTree != null); if(strTree == null) return this; if(strTree.Length == 0) return this; - string[] vGroups = strTree.Split(vSeparators); + string[] vGroups = strTree.Split(vSeparators, StringSplitOptions.None); if((vGroups == null) || (vGroups.Length == 0)) return this; PwGroup pgContainer = this; @@ -1199,6 +1244,7 @@ namespace KeePassLib return pgContainer; } +#endif /// /// Get the level of the group (i.e. the number of parent groups). diff --git a/src/KeePassLib2Android/PwUuid.cs b/src/KeePassLib2Android/PwUuid.cs index dfb0be52..186e007a 100644 --- a/src/KeePassLib2Android/PwUuid.cs +++ b/src/KeePassLib2Android/PwUuid.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -18,6 +18,7 @@ */ using System; +using System.Collections.Generic; using System.Xml; using System.Diagnostics; @@ -27,10 +28,10 @@ namespace KeePassLib { // [ImmutableObject(true)] /// - /// Represents an UUID of a password entry or group. Once created, PwUuid - /// objects aren't modifyable anymore (immutable). + /// Represents an UUID of a password entry or group. Once created, + /// PwUuid objects aren't modifyable anymore (immutable). /// - public sealed class PwUuid + public sealed class PwUuid : IComparable, IEquatable { /// /// Standard size in bytes of a UUID. @@ -40,9 +41,9 @@ namespace KeePassLib /// /// Zero UUID (all bytes are zero). /// - public static readonly PwUuid Zero = new PwUuid(); + public static readonly PwUuid Zero = new PwUuid(false); - private byte[] m_pbUuid = new byte[UuidSize]; + private byte[] m_pbUuid = null; // Never null after constructor /// /// Get the 16 UUID bytes. @@ -52,14 +53,6 @@ namespace KeePassLib get { return m_pbUuid; } } - /// - /// Construct a new UUID object. Its value is initialized to zero. - /// - private PwUuid() - { - SetZero(); - } - /// /// Construct a new UUID object. /// @@ -88,38 +81,95 @@ namespace KeePassLib /// otherwise it returns false. private void CreateNew() { + Debug.Assert(m_pbUuid == null); // Only call from constructor while(true) { m_pbUuid = Guid.NewGuid().ToByteArray(); - if((m_pbUuid == null) || (m_pbUuid.Length != UuidSize)) + if((m_pbUuid == null) || (m_pbUuid.Length != (int)UuidSize)) + { + Debug.Assert(false); throw new InvalidOperationException(); + } // Zero is a reserved value -- do not generate Zero - if(this.EqualsValue(PwUuid.Zero) == false) - break; + if(!Equals(PwUuid.Zero)) break; + Debug.Assert(false); } } - /// - /// Compare this UUID with another. - /// - /// Second UUID object. - /// Returns true if both PwUuid object contain the same - /// value, otherwise false is returned. + private void SetValue(byte[] uuidBytes) + { + Debug.Assert((uuidBytes != null) && (uuidBytes.Length == (int)UuidSize)); + if(uuidBytes == null) throw new ArgumentNullException("uuidBytes"); + if(uuidBytes.Length != (int)UuidSize) throw new ArgumentException(); + + Debug.Assert(m_pbUuid == null); // Only call from constructor + m_pbUuid = new byte[UuidSize]; + + Array.Copy(uuidBytes, m_pbUuid, (int)UuidSize); + } + + private void SetZero() + { + Debug.Assert(m_pbUuid == null); // Only call from constructor + m_pbUuid = new byte[UuidSize]; + + // Array.Clear(m_pbUuid, 0, (int)UuidSize); +#if DEBUG + List l = new List(m_pbUuid); + Debug.Assert(l.TrueForAll(bt => (bt == 0))); +#endif + } + + [Obsolete] public bool EqualsValue(PwUuid uuid) { - Debug.Assert(uuid != null); - if(uuid == null) throw new ArgumentNullException("uuid"); + return Equals(uuid); + } - for(int i = 0; i < UuidSize; ++i) + public override bool Equals(object obj) + { + return Equals(obj as PwUuid); + } + + public bool Equals(PwUuid other) + { + if(other == null) { Debug.Assert(false); return false; } + + for(int i = 0; i < (int)UuidSize; ++i) { - if(m_pbUuid[i] != uuid.m_pbUuid[i]) return false; + if(m_pbUuid[i] != other.m_pbUuid[i]) return false; } return true; } + private int m_h = 0; + public override int GetHashCode() + { + if(m_h == 0) + m_h = (int)MemUtil.Hash32(m_pbUuid, 0, m_pbUuid.Length); + return m_h; + } + + public int CompareTo(PwUuid other) + { + if(other == null) + { + Debug.Assert(false); + throw new ArgumentNullException("other"); + } + + for(int i = 0; i < (int)UuidSize; ++i) + { + if(m_pbUuid[i] < other.m_pbUuid[i]) return -1; + if(m_pbUuid[i] > other.m_pbUuid[i]) return 1; + } + + return 0; + } + /// /// Convert the UUID to its string representation. /// @@ -129,29 +179,15 @@ namespace KeePassLib return MemUtil.ByteArrayToHexString(m_pbUuid); } - /// - /// Set the UUID value. The input parameter will not be modified. - /// - /// UUID bytes. The byte array must contain - /// exactly UUIDSize bytes, otherwise the function will fail. - private void SetValue(byte[] uuidBytes) +#if DEBUG + public override string ToString() { - Debug.Assert((uuidBytes != null) && (uuidBytes.Length == UuidSize)); - if(uuidBytes == null) throw new ArgumentNullException("uuidBytes"); - if(uuidBytes.Length != UuidSize) throw new ArgumentException(); - - Array.Copy(uuidBytes, m_pbUuid, (int)UuidSize); - } - - /// - /// Set the UUID value to zero. - /// - private void SetZero() - { - Array.Clear(m_pbUuid, 0, (int)UuidSize); + return ToHexString(); } +#endif } + [Obsolete] public sealed class PwUuidComparable : IComparable { private byte[] m_pbUuid = new byte[PwUuid.UuidSize]; diff --git a/src/KeePassLib2Android/Resources/KLRes.Generated.cs b/src/KeePassLib2Android/Resources/KLRes.Generated.cs index 4aaf889f..5cfdc0ba 100644 --- a/src/KeePassLib2Android/Resources/KLRes.Generated.cs +++ b/src/KeePassLib2Android/Resources/KLRes.Generated.cs @@ -48,6 +48,7 @@ namespace KeePassLib.Resources m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint); m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding); m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint); + m_strKeyFileDbSel = TryGetEx(dictNew, "KeyFileDbSel", m_strKeyFileDbSel); m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid); m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat); m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs); @@ -78,6 +79,7 @@ namespace KeePassLib.Resources "InvalidCompositeKeyHint", "InvalidDataWhileDecoding", "KeePass1xHint", + "KeyFileDbSel", "MasterSeedLengthInvalid", "OldFormat", "TryAgainSecs", @@ -332,6 +334,17 @@ namespace KeePassLib.Resources get { return m_strKeePass1xHint; } } + private static string m_strKeyFileDbSel = + @"Database files cannot be used as key files."; + /// + /// Look up a localized string similar to + /// 'Database files cannot be used as key files.'. + /// + public static string KeyFileDbSel + { + get { return m_strKeyFileDbSel; } + } + private static string m_strMasterSeedLengthInvalid = @"The length of the master key seed is invalid!"; /// diff --git a/src/KeePassLib2Android/Serialization/BinaryReaderEx.cs b/src/KeePassLib2Android/Serialization/BinaryReaderEx.cs index 3ce22a51..12bf7623 100644 --- a/src/KeePassLib2Android/Serialization/BinaryReaderEx.cs +++ b/src/KeePassLib2Android/Serialization/BinaryReaderEx.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -29,7 +29,7 @@ namespace KeePassLib.Serialization public sealed class BinaryReaderEx { private Stream m_s; - private Encoding m_enc; + // private Encoding m_enc; // See constructor private string m_strReadExcp; public string ReadExceptionText @@ -56,7 +56,7 @@ namespace KeePassLib.Serialization if(input == null) throw new ArgumentNullException("input"); m_s = input; - m_enc = encoding; + // m_enc = encoding; // Not used yet m_strReadExcp = strReadExceptionText; } diff --git a/src/KeePassLib2Android/Serialization/FileLock.cs b/src/KeePassLib2Android/Serialization/FileLock.cs index ac20e00d..d0c5ae1e 100644 --- a/src/KeePassLib2Android/Serialization/FileLock.cs +++ b/src/KeePassLib2Android/Serialization/FileLock.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -154,7 +154,7 @@ namespace KeePassLib.Serialization byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16); string strTime = TimeUtil.SerializeUtc(DateTime.Now); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime, Environment.UserName, Environment.MachineName, Environment.UserDomainName); diff --git a/src/KeePassLib2Android/Serialization/FileTransactionEx.cs b/src/KeePassLib2Android/Serialization/FileTransactionEx.cs index 7e179963..32d85442 100644 --- a/src/KeePassLib2Android/Serialization/FileTransactionEx.cs +++ b/src/KeePassLib2Android/Serialization/FileTransactionEx.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -23,10 +23,11 @@ using System.Text; using System.IO; using System.Diagnostics; -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) using System.Security.AccessControl; #endif +using KeePassLib.Native; using KeePassLib.Utility; namespace KeePassLib.Serialization @@ -58,6 +59,13 @@ namespace KeePassLib.Serialization m_bTransacted = bTransacted; m_iocBase = iocBaseFile.CloneDeep(); + // Prevent transactions for FTP URLs under .NET 4.0 in order to + // avoid/workaround .NET bug 621450: + // https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only + if(m_iocBase.Path.StartsWith("ftp:", StrUtil.CaseIgnoreCmp) && + (Environment.Version.Major >= 4) && !NativeLib.IsUnix()) + m_bTransacted = false; + if(m_bTransacted) { m_iocTemp = m_iocBase.CloneDeep(); @@ -91,14 +99,14 @@ namespace KeePassLib.Serialization { bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) FileSecurity bkSecurity = null; bool bEfsEncrypted = false; #endif if(IOConnection.FileExists(m_iocBase)) { -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) if(m_iocBase.IsLocalFile()) { try @@ -120,7 +128,7 @@ namespace KeePassLib.Serialization IOConnection.RenameFile(m_iocTemp, m_iocBase); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) if(m_iocBase.IsLocalFile()) { try diff --git a/src/KeePassLib2Android/Serialization/HashedBlockStream.cs b/src/KeePassLib2Android/Serialization/HashedBlockStream.cs index 403b6dfd..8b640c28 100644 --- a/src/KeePassLib2Android/Serialization/HashedBlockStream.cs +++ b/src/KeePassLib2Android/Serialization/HashedBlockStream.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -129,8 +129,14 @@ namespace KeePassLib.Serialization if(m_bWriting) m_bwOutput.Flush(); } +#if KeePassRT + protected override void Dispose(bool disposing) + { + if(!disposing) return; +#else public override void Close() { +#endif if(m_sBaseStream != null) { if(m_bWriting == false) // Reading mode diff --git a/src/KeePassLib2Android/Serialization/IOConnection.cs b/src/KeePassLib2Android/Serialization/IOConnection.cs index e115ff5b..7bf2e35c 100644 --- a/src/KeePassLib2Android/Serialization/IOConnection.cs +++ b/src/KeePassLib2Android/Serialization/IOConnection.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -22,20 +22,23 @@ using System.Collections.Generic; using System.Text; using System.IO; using System.Net; -using System.Security.Cryptography.X509Certificates; using System.Diagnostics; -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) using System.Net.Cache; using System.Net.Security; #endif +#if !KeePassRT +using System.Security.Cryptography.X509Certificates; +#endif + using KeePassLib.Native; using KeePassLib.Utility; namespace KeePassLib.Serialization { -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) public sealed class IOWebClient : WebClient { protected override WebRequest GetWebRequest(Uri address) @@ -49,12 +52,19 @@ namespace KeePassLib.Serialization public static class IOConnection { -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) private static ProxyServerType m_pstProxyType = ProxyServerType.System; private static string m_strProxyAddr = string.Empty; private static string m_strProxyPort = string.Empty; private static string m_strProxyUserName = string.Empty; private static string m_strProxyPassword = string.Empty; + + private static bool m_bSslCertsAcceptInvalid = false; + internal static bool SslCertsAcceptInvalid + { + // get { return m_bSslCertsAcceptInvalid; } + set { m_bSslCertsAcceptInvalid = value; } + } #endif // Web request methods @@ -64,16 +74,18 @@ namespace KeePassLib.Serialization // Web request headers public const string WrhMoveFileTo = "MoveFileTo"; -#if !KeePassLibSD + public static event EventHandler IOAccessPre; + +#if (!KeePassLibSD && !KeePassRT) // Allow self-signed certificates, expired certificates, etc. - private static bool ValidateServerCertificate(object sender, + private static bool AcceptCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } - public static void SetProxy(ProxyServerType pst, string strAddr, + internal static void SetProxy(ProxyServerType pst, string strAddr, string strPort, string strUserName, string strPassword) { m_pstProxyType = pst; @@ -183,8 +195,11 @@ namespace KeePassLib.Serialization private static void PrepareWebAccess() { - ServicePointManager.ServerCertificateValidationCallback = - ValidateServerCertificate; + if(m_bSslCertsAcceptInvalid) + ServicePointManager.ServerCertificateValidationCallback = + IOConnection.AcceptCertificate; + else + ServicePointManager.ServerCertificateValidationCallback = null; } private static IOWebClient CreateWebClient(IOConnectionInfo ioc) @@ -219,6 +234,8 @@ namespace KeePassLib.Serialization public static Stream OpenRead(IOConnectionInfo ioc) { + RaiseIOAccessPreEvent(ioc, IOAccessType.Read); + if(StrUtil.IsDataUri(ioc.Path)) { byte[] pbData = StrUtil.DataUriToData(ioc.Path); @@ -232,6 +249,8 @@ namespace KeePassLib.Serialization #else public static Stream OpenRead(IOConnectionInfo ioc) { + RaiseIOAccessPreEvent(ioc, IOAccessType.Read); + return OpenReadLocal(ioc); } #endif @@ -242,11 +261,13 @@ namespace KeePassLib.Serialization FileShare.Read); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) public static Stream OpenWrite(IOConnectionInfo ioc) { if(ioc == null) { Debug.Assert(false); return null; } + RaiseIOAccessPreEvent(ioc, IOAccessType.Write); + if(ioc.IsLocalFile()) return OpenWriteLocal(ioc); Uri uri = new Uri(ioc.Path); @@ -263,6 +284,8 @@ namespace KeePassLib.Serialization #else public static Stream OpenWrite(IOConnectionInfo ioc) { + RaiseIOAccessPreEvent(ioc, IOAccessType.Write); + return OpenWriteLocal(ioc); } #endif @@ -282,9 +305,11 @@ namespace KeePassLib.Serialization { if(ioc == null) { Debug.Assert(false); return false; } + RaiseIOAccessPreEvent(ioc, IOAccessType.Exists); + if(ioc.IsLocalFile()) return File.Exists(ioc.Path); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) if(ioc.Path.StartsWith("ftp://", StrUtil.CaseIgnoreCmp)) { bool b = SendCommand(ioc, WebRequestMethods.Ftp.GetDateTimestamp); @@ -317,9 +342,11 @@ namespace KeePassLib.Serialization public static void DeleteFile(IOConnectionInfo ioc) { + RaiseIOAccessPreEvent(ioc, IOAccessType.Delete); + if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) WebRequest req = CreateWebRequest(ioc); if(req != null) { @@ -348,9 +375,11 @@ namespace KeePassLib.Serialization /// Target file path. public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo) { + RaiseIOAccessPreEvent(iocFrom, iocTo, IOAccessType.Move); + if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) WebRequest req = CreateWebRequest(iocFrom); if(req != null) { @@ -362,7 +391,13 @@ namespace KeePassLib.Serialization else if(req is FtpWebRequest) { req.Method = WebRequestMethods.Ftp.Rename; - ((FtpWebRequest)req).RenameTo = UrlUtil.GetFileName(iocTo.Path); + string strTo = UrlUtil.GetFileName(iocTo.Path); + + // We're affected by .NET bug 621450: + // https://connect.microsoft.com/VisualStudio/feedback/details/621450/problem-renaming-file-on-ftp-server-using-ftpwebrequest-in-net-framework-4-0-vs2010-only + // Prepending "./", "%2E/" or "Dummy/../" doesn't work. + + ((FtpWebRequest)req).RenameTo = strTo; } else if(req is FileWebRequest) { @@ -393,7 +428,7 @@ namespace KeePassLib.Serialization // DeleteFile(iocFrom); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) private static bool SendCommand(IOConnectionInfo ioc, string strMethod) { try @@ -449,5 +484,24 @@ namespace KeePassLib.Serialization return null; } + + private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc, IOAccessType t) + { + RaiseIOAccessPreEvent(ioc, null, t); + } + + private static void RaiseIOAccessPreEvent(IOConnectionInfo ioc, + IOConnectionInfo ioc2, IOAccessType t) + { + if(ioc == null) { Debug.Assert(false); return; } + // ioc2 may be null + + if(IOConnection.IOAccessPre != null) + { + IOConnectionInfo ioc2Lcl = ((ioc2 != null) ? ioc2.CloneDeep() : null); + IOAccessEventArgs e = new IOAccessEventArgs(ioc.CloneDeep(), ioc2Lcl, t); + IOConnection.IOAccessPre(null, e); + } + } } } diff --git a/src/KeePassLib2Android/Serialization/IOConnectionInfo.cs b/src/KeePassLib2Android/Serialization/IOConnectionInfo.cs index 2adc05ed..e27a905e 100644 --- a/src/KeePassLib2Android/Serialization/IOConnectionInfo.cs +++ b/src/KeePassLib2Android/Serialization/IOConnectionInfo.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -23,6 +23,7 @@ using System.Text; using System.IO; using System.Net; using System.ComponentModel; +using System.Xml.Serialization; using System.Diagnostics; using KeePassLib.Interfaces; @@ -119,6 +120,14 @@ namespace KeePassLib.Serialization set { m_ioCredSaveMode = value; } } + private bool m_bComplete = false; + [XmlIgnore] + internal bool IsComplete // Credentials etc. fully specified + { + get { return m_bComplete; } + set { m_bComplete = value; } + } + /* public IOFileFormatHint FileFormatHint { get { return m_ioHint; } @@ -146,31 +155,9 @@ namespace KeePassLib.Serialization string strUrl = iocToCompile.Path; string strUser = TransformUnreadable(iocToCompile.UserName, true); string strPassword = TransformUnreadable(iocToCompile.Password, true); - string strAll = strUrl + strUser + strPassword; - char chSep = char.MinValue; - - char[] vPrefSeps = new char[]{ '@', '#', '!', '$', '*' }; - foreach(char ch in vPrefSeps) - { - if(strAll.IndexOf(ch) < 0) - { - chSep = ch; - break; - } - } - - if(chSep == char.MinValue) - { - for(char chEnum = '!'; chEnum < char.MaxValue; ++chEnum) - { - if(strAll.IndexOf(chEnum) < 0) - { - chSep = chEnum; - break; - } - } - } + string strAll = strUrl + strUser + strPassword + "CUN"; + char chSep = StrUtil.GetUnusedChar(strAll); if(chSep == char.MinValue) throw new FormatException(); StringBuilder sb = new StringBuilder(); diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Read.Streamed.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Read.Streamed.cs index 27b85c4e..ff39cfd1 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Read.Streamed.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Read.Streamed.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -100,11 +100,12 @@ namespace KeePassLib.Serialization xrs.IgnoreProcessingInstructions = true; xrs.IgnoreWhitespace = true; +#if !KeePassRT #if !KeePassLibSD xrs.ProhibitDtd = true; #endif - xrs.ValidationType = ValidationType.None; +#endif return xrs; } @@ -560,7 +561,8 @@ namespace KeePassLib.Serialization return KdbContext.Meta; else if((ctx == KdbContext.CustomIcon) && (xr.Name == ElemCustomIconItem)) { - if((m_uuidCustomIconID != PwUuid.Zero) && (m_pbCustomIconData != null)) + if(!m_uuidCustomIconID.Equals(PwUuid.Zero) && + (m_pbCustomIconData != null)) m_pwDatabase.CustomIcons.Add(new PwCustomIcon( m_uuidCustomIconID, m_pbCustomIconData)); else { Debug.Assert(false); } @@ -587,7 +589,7 @@ namespace KeePassLib.Serialization } else if((ctx == KdbContext.Group) && (xr.Name == ElemGroup)) { - if(PwUuid.Zero.EqualsValue(m_ctxGroup.Uuid)) + if(PwUuid.Zero.Equals(m_ctxGroup.Uuid)) m_ctxGroup.Uuid = new PwUuid(true); // No assert (import) m_ctxGroups.Pop(); @@ -608,7 +610,7 @@ namespace KeePassLib.Serialization else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry)) { // Create new UUID if absent - if(PwUuid.Zero.EqualsValue(m_ctxEntry.Uuid)) + if(PwUuid.Zero.Equals(m_ctxEntry.Uuid)) m_ctxEntry.Uuid = new PwUuid(true); // No assert (import) if(m_bEntryInHistory) @@ -716,6 +718,9 @@ namespace KeePassLib.Serialization string str = ReadString(xr); int n; + if(StrUtil.TryParseIntInvariant(str, out n)) return n; + + // Backward compatibility if(StrUtil.TryParseInt(str, out n)) return n; Debug.Assert(false); @@ -727,6 +732,9 @@ namespace KeePassLib.Serialization string str = ReadString(xr); uint u; + if(StrUtil.TryParseUIntInvariant(str, out u)) return u; + + // Backward compatibility if(StrUtil.TryParseUInt(str, out u)) return u; Debug.Assert(false); @@ -738,6 +746,9 @@ namespace KeePassLib.Serialization string str = ReadString(xr); long l; + if(StrUtil.TryParseLongInvariant(str, out l)) return l; + + // Backward compatibility if(StrUtil.TryParseLong(str, out l)) return l; Debug.Assert(false); @@ -749,6 +760,9 @@ namespace KeePassLib.Serialization string str = ReadString(xr); ulong u; + if(StrUtil.TryParseULongInvariant(str, out u)) return u; + + // Backward compatibility if(StrUtil.TryParseULong(str, out u)) return u; Debug.Assert(false); diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs index 03456962..11ad3ac5 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Read.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -127,6 +127,22 @@ namespace KeePassLib.Serialization } else m_randomStream = null; // No random stream for plain-text files +#if KeePassDebug_WriteXml + // FileStream fsOut = new FileStream("Raw.xml", FileMode.Create, + // FileAccess.Write, FileShare.None); + // try + // { + // while(true) + // { + // int b = readerStream.ReadByte(); + // if(b == -1) break; + // fsOut.WriteByte((byte)b); + // } + // } + // catch(Exception) { } + // fsOut.Close(); +#endif + ReadXmlStreamed(readerStream, hashedStream); // ReadXmlDom(readerStream); diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs b/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs index ada3a9ed..5adeaeca 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.Write.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -22,12 +22,11 @@ using System.Collections.Generic; using System.Text; using System.IO; using System.Xml; -using System.Diagnostics; using System.Security; using System.Security.Cryptography; using System.Drawing; using System.Globalization; -using System.Drawing.Imaging; +using System.Diagnostics; #if !KeePassLibSD using System.IO.Compression; @@ -363,7 +362,7 @@ namespace KeePassLib.Serialization WriteObject(ElemNotes, pg.Notes, true); WriteObject(ElemIcon, (int)pg.IconId); - if(pg.CustomIconUuid != PwUuid.Zero) + if(!pg.CustomIconUuid.Equals(PwUuid.Zero)) WriteObject(ElemCustomIconID, pg.CustomIconUuid); WriteList(ElemTimes, pg); @@ -388,7 +387,7 @@ namespace KeePassLib.Serialization WriteObject(ElemUuid, pe.Uuid); WriteObject(ElemIcon, (int)pe.IconId); - if(pe.CustomIconUuid != PwUuid.Zero) + if(!pe.CustomIconUuid.Equals(PwUuid.Zero)) WriteObject(ElemCustomIconID, pe.CustomIconUuid); WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false); @@ -577,7 +576,7 @@ namespace KeePassLib.Serialization Debug.Assert(name != null); m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString()); + m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); m_xmlWriter.WriteEndElement(); } @@ -586,7 +585,7 @@ namespace KeePassLib.Serialization Debug.Assert(name != null); m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString()); + m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); m_xmlWriter.WriteEndElement(); } @@ -595,7 +594,7 @@ namespace KeePassLib.Serialization Debug.Assert(name != null); m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString()); + m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); m_xmlWriter.WriteEndElement(); } @@ -604,7 +603,7 @@ namespace KeePassLib.Serialization Debug.Assert(name != null); m_xmlWriter.WriteStartElement(name); - m_xmlWriter.WriteString(value.ToString()); + m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo)); m_xmlWriter.WriteEndElement(); } @@ -686,7 +685,8 @@ namespace KeePassLib.Serialization // page area if(char.IsSymbol(ch) || char.IsSurrogate(ch)) { - System.Globalization.UnicodeCategory cat = char.GetUnicodeCategory(ch); + System.Globalization.UnicodeCategory cat = + CharUnicodeInfo.GetUnicodeCategory(ch); // Map character to correct position in code page chMapped = (char)((int)cat * 32 + ch); } @@ -698,7 +698,11 @@ namespace KeePassLib.Serialization // in the low ANSI range (up to 255) when calling // ToLower on them with invariant culture (see // http://lists.ximian.com/pipermail/mono-patches/2002-February/086106.html ) - chMapped = char.ToLower(ch, CultureInfo.InvariantCulture); +#if !KeePassLibSD + chMapped = char.ToLowerInvariant(ch); +#else + chMapped = char.ToLower(ch); +#endif } } diff --git a/src/KeePassLib2Android/Serialization/KdbxFile.cs b/src/KeePassLib2Android/Serialization/KdbxFile.cs index b1cd287a..47107012 100644 --- a/src/KeePassLib2Android/Serialization/KdbxFile.cs +++ b/src/KeePassLib2Android/Serialization/KdbxFile.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -63,12 +63,12 @@ namespace KeePassLib.Serialization /// /// File identifier, first 32-bit value. /// - private const uint FileSignature1 = 0x9AA2D903; + internal const uint FileSignature1 = 0x9AA2D903; /// /// File identifier, second 32-bit value. /// - private const uint FileSignature2 = 0xB54BFB67; + internal const uint FileSignature2 = 0xB54BFB67; /// /// File version of files saved by the current KdbxFile class. @@ -82,11 +82,11 @@ namespace KeePassLib.Serialization private const uint FileVersionCriticalMask = 0xFFFF0000; // KeePass 1.x signature - private const uint FileSignatureOld1 = 0x9AA2D903; - private const uint FileSignatureOld2 = 0xB54BFB65; + internal const uint FileSignatureOld1 = 0x9AA2D903; + internal const uint FileSignatureOld2 = 0xB54BFB65; // KeePass 2.x pre-release (alpha and beta) signature - private const uint FileSignaturePreRelease1 = 0x9AA2D903; - private const uint FileSignaturePreRelease2 = 0xB54BFB66; + internal const uint FileSignaturePreRelease1 = 0x9AA2D903; + internal const uint FileSignaturePreRelease2 = 0xB54BFB66; private const string ElemDocNode = "KeePassFile"; private const string ElemMeta = "Meta"; @@ -324,7 +324,8 @@ namespace KeePassLib.Serialization if(BinPoolFind(pb) != null) return; // Exists already - m_dictBinPool.Add(m_dictBinPool.Count.ToString(), pb); + m_dictBinPool.Add(m_dictBinPool.Count.ToString( + NumberFormatInfo.InvariantInfo), pb); } private string BinPoolFind(ProtectedBinary pb) @@ -366,7 +367,9 @@ namespace KeePassLib.Serialization string strDesc = UrlUtil.StripExtension(strName); strPath += strDesc; - if(iTry > 1) strPath += " (" + iTry.ToString() + ")"; + if(iTry > 1) + strPath += " (" + iTry.ToString(NumberFormatInfo.InvariantInfo) + + ")"; if(!string.IsNullOrEmpty(strExt)) strPath += "." + strExt; diff --git a/src/KeePassLib2Android/Translation/KPControlCustomization.cs b/src/KeePassLib2Android/Translation/KPControlCustomization.cs index 1530f655..16565626 100644 --- a/src/KeePassLib2Android/Translation/KPControlCustomization.cs +++ b/src/KeePassLib2Android/Translation/KPControlCustomization.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -42,8 +42,8 @@ namespace KeePassLib.Translation private const string m_strControlRelative = @"%c"; - internal const NumberStyles m_nsParser = NumberStyles.AllowLeadingSign | - NumberStyles.AllowDecimalPoint; + internal const NumberStyles m_nsParser = (NumberStyles.AllowLeadingSign | + NumberStyles.AllowDecimalPoint); internal static readonly CultureInfo m_lclInv = CultureInfo.InvariantCulture; private string m_strPosX = string.Empty; @@ -112,7 +112,7 @@ namespace KeePassLib.Translation else { Debug.Assert(false); } } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) internal void ApplyTo(Control c) { Debug.Assert(c != null); if(c == null) return; @@ -267,7 +267,7 @@ namespace KeePassLib.Translation return m_strMemberName.CompareTo(kpOther.Name); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) private static readonly Type[] m_vTextControls = new Type[] { typeof(MenuStrip), typeof(PictureBox), typeof(ListView), typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser), @@ -309,8 +309,8 @@ namespace KeePassLib.Translation if(c is Form) { - WriteCpiParam(sb, c.ClientSize.Width.ToString()); - WriteCpiParam(sb, c.ClientSize.Height.ToString()); + WriteCpiParam(sb, c.ClientSize.Width.ToString(KpccLayout.m_lclInv)); + WriteCpiParam(sb, c.ClientSize.Height.ToString(KpccLayout.m_lclInv)); } else // Normal control { diff --git a/src/KeePassLib2Android/Translation/KPFormCustomization.cs b/src/KeePassLib2Android/Translation/KPFormCustomization.cs index 9c6a3442..3b0f88af 100644 --- a/src/KeePassLib2Android/Translation/KPFormCustomization.cs +++ b/src/KeePassLib2Android/Translation/KPFormCustomization.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -66,6 +66,7 @@ namespace KeePassLib.Translation } } +#if (!KeePassLibSD && !KeePassRT) private Form m_formEnglish = null; [XmlIgnore] public Form FormEnglish @@ -74,7 +75,6 @@ namespace KeePassLib.Translation set { m_formEnglish = value; } } -#if !KeePassLibSD public void ApplyTo(Form form) { Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form"); diff --git a/src/KeePassLib2Android/Translation/KPStringTable.cs b/src/KeePassLib2Android/Translation/KPStringTable.cs index b5c676fb..93f1a21e 100644 --- a/src/KeePassLib2Android/Translation/KPStringTable.cs +++ b/src/KeePassLib2Android/Translation/KPStringTable.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -66,7 +66,7 @@ namespace KeePassLib.Translation return dict; } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) public void ApplyTo(ToolStripItemCollection tsic) { if(tsic == null) throw new ArgumentNullException("tsic"); diff --git a/src/KeePassLib2Android/Translation/KPTranslation.cs b/src/KeePassLib2Android/Translation/KPTranslation.cs index 2705325d..400c7491 100644 --- a/src/KeePassLib2Android/Translation/KPTranslation.cs +++ b/src/KeePassLib2Android/Translation/KPTranslation.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -153,7 +153,7 @@ namespace KeePassLib.Translation return new Dictionary(); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) public void ApplyTo(Form form) { if(form == null) throw new ArgumentNullException("form"); diff --git a/src/KeePassLib2Android/Utility/AppLogEx.cs b/src/KeePassLib2Android/Utility/AppLogEx.cs index 7074b60d..ae16f699 100644 --- a/src/KeePassLib2Android/Utility/AppLogEx.cs +++ b/src/KeePassLib2Android/Utility/AppLogEx.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -49,7 +49,7 @@ namespace KeePassLib.Utility try { string strDirSep = string.Empty; - strDirSep += Path.DirectorySeparatorChar; + strDirSep += UrlUtil.LocalDirSepChar; string strTemp = UrlUtil.GetTempPath(); if(!strTemp.EndsWith(strDirSep)) @@ -64,7 +64,7 @@ namespace KeePassLib.Utility strTime = strTime.Replace(':', '-'); strPath += strTime + "-" + Environment.TickCount.ToString( - CultureInfo.InvariantCulture) + ".log.gz"; + NumberFormatInfo.InvariantInfo) + ".log.gz"; FileStream fsOut = new FileStream(strPath, FileMode.Create, FileAccess.Write, FileShare.None); diff --git a/src/KeePassLib2Android/Utility/GfxUtil.cs b/src/KeePassLib2Android/Utility/GfxUtil.cs index 2b487407..b0d7f391 100644 --- a/src/KeePassLib2Android/Utility/GfxUtil.cs +++ b/src/KeePassLib2Android/Utility/GfxUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -29,6 +29,14 @@ namespace KeePassLib.Utility { public static class GfxUtil { +#if KeePassRT + public static Image LoadImage(byte[] pb) + { + MemoryStream ms = new MemoryStream(pb, false); + try { return Image.FromStream(ms); } + finally { ms.Close(); } + } +#else public static Image LoadImage(byte[] pb) { if(pb == null) throw new ArgumentNullException("pb"); @@ -91,5 +99,6 @@ namespace KeePassLib.Utility return null; } +#endif } } diff --git a/src/KeePassLib2Android/Utility/MemUtil.cs b/src/KeePassLib2Android/Utility/MemUtil.cs index af7520f2..8c2e937b 100644 --- a/src/KeePassLib2Android/Utility/MemUtil.cs +++ b/src/KeePassLib2Android/Utility/MemUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -18,6 +18,7 @@ */ using System; +using System.Collections.Generic; using System.Text; using System.Security.Cryptography; using System.Diagnostics; @@ -36,6 +37,73 @@ namespace KeePassLib.Utility /// 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 + }; + /// /// Convert a hexadecimal string to a byte array. The input string must be /// even (i.e. its length is a multiple of 2). @@ -277,6 +345,31 @@ namespace KeePassLib.Utility pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i]; } + /// + /// 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. + /// + 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)); @@ -394,11 +487,81 @@ namespace KeePassLib.Utility 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(); + 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 Union(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if(a == null) throw new ArgumentNullException("a"); + if(b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + 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 Intersect(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if(a == null) throw new ArgumentNullException("a"); + if(b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + 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 Except(IEnumerable a, IEnumerable b, + IEqualityComparer cmp) + { + if(a == null) throw new ArgumentNullException("a"); + if(b == null) throw new ArgumentNullException("b"); + + Dictionary d = ((cmp != null) ? + (new Dictionary(cmp)) : (new Dictionary())); + + 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; + } } } diff --git a/src/KeePassLib2Android/Utility/MessageService.cs b/src/KeePassLib2Android/Utility/MessageService.cs index 22ee8355..549b1312 100644 --- a/src/KeePassLib2Android/Utility/MessageService.cs +++ b/src/KeePassLib2Android/Utility/MessageService.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -118,7 +118,7 @@ namespace KeePassLib.Utility Exception exObj = (obj as Exception); string strObj = (obj as string); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) StringCollection scObj = (obj as StringCollection); #endif @@ -129,7 +129,7 @@ namespace KeePassLib.Utility else if((exObj.Message != null) && (exObj.Message.Length > 0)) strAppend = exObj.Message; } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) else if(scObj != null) { StringBuilder sb = new StringBuilder(); @@ -158,7 +158,7 @@ namespace KeePassLib.Utility return sbText.ToString(); } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) internal static Form GetTopForm() { FormCollection fc = Application.OpenForms; @@ -171,7 +171,7 @@ namespace KeePassLib.Utility private static DialogResult SafeShowMessageBox(string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb) { -#if KeePassLibSD +#if (KeePassLibSD || KeePassRT) return MessageBox.Show(strText, strTitle, mb, mi, mdb); #else IWin32Window wnd = null; @@ -206,7 +206,7 @@ namespace KeePassLib.Utility #endif } -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent, string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb); @@ -321,7 +321,8 @@ namespace KeePassLib.Utility return dr; } - public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes) + public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes, + MessageBoxIcon mbi) { ++m_uCurrentMessageCount; @@ -330,24 +331,29 @@ namespace KeePassLib.Utility if(MessageService.MessageShowing != null) MessageService.MessageShowing(null, new MessageServiceEventArgs( - strTitleEx, strTextEx, MessageBoxButtons.YesNo, m_mbiQuestion)); + strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi)); DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, - MessageBoxButtons.YesNo, m_mbiQuestion, bDefaultToYes ? + MessageBoxButtons.YesNo, mbi, bDefaultToYes ? MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2); --m_uCurrentMessageCount; return (dr == DialogResult.Yes); } + public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes) + { + return AskYesNo(strText, strTitle, bDefaultToYes, m_mbiQuestion); + } + public static bool AskYesNo(string strText, string strTitle) { - return AskYesNo(strText, strTitle, true); + return AskYesNo(strText, strTitle, true, m_mbiQuestion); } public static bool AskYesNo(string strText) { - return AskYesNo(strText, null, true); + return AskYesNo(strText, null, true, m_mbiQuestion); } public static void ShowLoadWarning(string strFilePath, Exception ex) diff --git a/src/KeePassLib2Android/Utility/StrUtil.cs b/src/KeePassLib2Android/Utility/StrUtil.cs index 94e590aa..7fdb8501 100644 --- a/src/KeePassLib2Android/Utility/StrUtil.cs +++ b/src/KeePassLib2Android/Utility/StrUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -20,14 +20,16 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.Text; using System.Drawing; using System.IO; using System.Text.RegularExpressions; using System.Security.Cryptography; +using System.Globalization; +using System.Diagnostics; using KeePassLib.Collections; +using KeePassLib.Cryptography.PasswordGenerator; using KeePassLib.Native; using KeePassLib.Security; using KeePassLib.Resources; @@ -212,41 +214,47 @@ namespace KeePassLib.Utility { get { - if(m_lEncs == null) - { - m_lEncs = new List(); + if(m_lEncs != null) return m_lEncs; - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Default, -#if !KeePassLibSD - Encoding.Default.EncodingName, + List l = new List(); + + l.Add(new StrEncodingInfo(StrEncodingType.Default, +#if KeePassRT + StrUtil.Utf8.WebName, StrUtil.Utf8, 1, null)); #else - Encoding.Default.WebName, -#endif - Encoding.Default, - (uint)Encoding.Default.GetBytes("a").Length, null)); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Ascii, - "ASCII", Encoding.ASCII, 1, null)); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf7, - "Unicode (UTF-7)", Encoding.UTF7, 1, null)); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf8, - "Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16LE, - "Unicode (UTF-16 LE)", new UnicodeEncoding(false, false), - 2, new byte[] { 0xFF, 0xFE })); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf16BE, - "Unicode (UTF-16 BE)", new UnicodeEncoding(true, false), - 2, new byte[] { 0xFE, 0xFF })); #if !KeePassLibSD - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32LE, - "Unicode (UTF-32 LE)", new UTF32Encoding(false, false), - 4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 })); - m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32BE, - "Unicode (UTF-32 BE)", new UTF32Encoding(true, false), - 4, new byte[] { 0x0, 0x0, 0xFE, 0xFF })); + Encoding.Default.EncodingName, +#else + Encoding.Default.WebName, +#endif + Encoding.Default, + (uint)Encoding.Default.GetBytes("a").Length, null)); +#endif +#if !KeePassRT + l.Add(new StrEncodingInfo(StrEncodingType.Ascii, + "ASCII", Encoding.ASCII, 1, null)); + l.Add(new StrEncodingInfo(StrEncodingType.Utf7, + "Unicode (UTF-7)", Encoding.UTF7, 1, null)); +#endif + l.Add(new StrEncodingInfo(StrEncodingType.Utf8, + "Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); + l.Add(new StrEncodingInfo(StrEncodingType.Utf16LE, + "Unicode (UTF-16 LE)", new UnicodeEncoding(false, false), + 2, new byte[] { 0xFF, 0xFE })); + l.Add(new StrEncodingInfo(StrEncodingType.Utf16BE, + "Unicode (UTF-16 BE)", new UnicodeEncoding(true, false), + 2, new byte[] { 0xFE, 0xFF })); +#if (!KeePassLibSD && !KeePassRT) + l.Add(new StrEncodingInfo(StrEncodingType.Utf32LE, + "Unicode (UTF-32 LE)", new UTF32Encoding(false, false), + 4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 })); + l.Add(new StrEncodingInfo(StrEncodingType.Utf32BE, + "Unicode (UTF-32 BE)", new UTF32Encoding(true, false), + 4, new byte[] { 0x0, 0x0, 0xFE, 0xFF })); #endif - } - return m_lEncs; + m_lEncs = l; + return l; } } @@ -274,16 +282,21 @@ namespace KeePassLib.Utility // { // char ch = str[i]; // if((int)ch >= 256) - // { - // sbEncoded.Append("\\u"); - // sbEncoded.Append((int)ch); - // sbEncoded.Append('?'); - // } + // sbEncoded.Append(StrUtil.RtfEncodeChar(ch)); // else sbEncoded.Append(ch); // } // return sbEncoded.ToString(); // } + public static string RtfEncodeChar(char ch) + { + // Unicode character values must be encoded using + // 16-bit numbers (decimal); Unicode values greater + // than 32767 must be expressed as negative numbers + short sh = (short)ch; + return ("\\u" + sh.ToString(NumberFormatInfo.InvariantInfo) + "?"); + } + /// /// Convert a string into a valid HTML sequence representing that string. /// @@ -482,8 +495,10 @@ namespace KeePassLib.Utility if(excp.StackTrace != null) strText += excp.StackTrace + MessageService.NewLine; #if !KeePassLibSD +#if !KeePassRT if(excp.TargetSite != null) strText += excp.TargetSite.ToString() + MessageService.NewLine; +#endif if(excp.Data != null) { @@ -506,8 +521,10 @@ namespace KeePassLib.Utility if(excp.InnerException.StackTrace != null) strText += excp.InnerException.StackTrace + MessageService.NewLine; #if !KeePassLibSD +#if !KeePassRT if(excp.InnerException.TargetSite != null) strText += excp.InnerException.TargetSite.ToString(); +#endif if(excp.InnerException.Data != null) { @@ -538,7 +555,25 @@ namespace KeePassLib.Utility return int.TryParse(str, out n); #else try { n = int.Parse(str); return true; } - catch(Exception) { n = 0; return false; } + catch(Exception) { n = 0; } + return false; +#endif + } + + public static bool TryParseIntInvariant(string str, out int n) + { +#if !KeePassLibSD + return int.TryParse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo, out n); +#else + try + { + n = int.Parse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo); + return true; + } + catch(Exception) { n = 0; } + return false; #endif } @@ -548,7 +583,25 @@ namespace KeePassLib.Utility return uint.TryParse(str, out u); #else try { u = uint.Parse(str); return true; } - catch(Exception) { u = 0; return false; } + catch(Exception) { u = 0; } + return false; +#endif + } + + public static bool TryParseUIntInvariant(string str, out uint u) + { +#if !KeePassLibSD + return uint.TryParse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo, out u); +#else + try + { + u = uint.Parse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo); + return true; + } + catch(Exception) { u = 0; } + return false; #endif } @@ -558,7 +611,25 @@ namespace KeePassLib.Utility return long.TryParse(str, out n); #else try { n = long.Parse(str); return true; } - catch(Exception) { n = 0; return false; } + catch(Exception) { n = 0; } + return false; +#endif + } + + public static bool TryParseLongInvariant(string str, out long n) + { +#if !KeePassLibSD + return long.TryParse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo, out n); +#else + try + { + n = long.Parse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo); + return true; + } + catch(Exception) { n = 0; } + return false; #endif } @@ -568,7 +639,25 @@ namespace KeePassLib.Utility return ulong.TryParse(str, out u); #else try { u = ulong.Parse(str); return true; } - catch(Exception) { u = 0; return false; } + catch(Exception) { u = 0; } + return false; +#endif + } + + public static bool TryParseULongInvariant(string str, out ulong u) + { +#if !KeePassLibSD + return ulong.TryParse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo, out u); +#else + try + { + u = ulong.Parse(str, NumberStyles.Integer, + NumberFormatInfo.InvariantInfo); + return true; + } + catch(Exception) { u = 0; } + return false; #endif } @@ -636,19 +725,34 @@ namespace KeePassLib.Utility Debug.Assert(strText != null); // No throw if(string.IsNullOrEmpty(strText)) return strText; - char[] vChars = strText.ToCharArray(); - StringBuilder sb = new StringBuilder(strText.Length, strText.Length); - char ch; + int nLength = strText.Length; + StringBuilder sb = new StringBuilder(nLength); - for(int i = 0; i < vChars.Length; ++i) + for(int i = 0; i < nLength; ++i) { - ch = vChars[i]; + char ch = strText[i]; - if(((ch >= 0x20) && (ch <= 0xD7FF)) || - (ch == 0x9) || (ch == 0xA) || (ch == 0xD) || - ((ch >= 0xE000) && (ch <= 0xFFFD))) + if(((ch >= '\u0020') && (ch <= '\uD7FF')) || + (ch == '\u0009') || (ch == '\u000A') || (ch == '\u000D') || + ((ch >= '\uE000') && (ch <= '\uFFFD'))) sb.Append(ch); - // Range ((ch >= 0x10000) && (ch <= 0x10FFFF)) excluded + else if((ch >= '\uD800') && (ch <= '\uDBFF')) // High surrogate + { + if((i + 1) < nLength) + { + char chLow = strText[i + 1]; + if((chLow >= '\uDC00') && (chLow <= '\uDFFF')) // Low sur. + { + sb.Append(ch); + sb.Append(chLow); + ++i; + } + else { Debug.Assert(false); } // Low sur. invalid + } + else { Debug.Assert(false); } // Low sur. missing + } + + Debug.Assert((ch < '\uDC00') || (ch > '\uDFFF')); // Lonely low sur. } return sb.ToString(); @@ -669,7 +773,12 @@ namespace KeePassLib.Utility strY = strY.ToLower(); if(m_rxNaturalSplit == null) - m_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled); + m_rxNaturalSplit = new Regex(@"([0-9]+)", +#if KeePassRT + RegexOptions.None); +#else + RegexOptions.Compiled); +#endif string[] vPartsX = m_rxNaturalSplit.Split(strX); string[] vPartsY = m_rxNaturalSplit.Split(strY); @@ -724,6 +833,20 @@ namespace KeePassLib.Utility return str; } + public static string EncodeMenuText(string strText) + { + if(strText == null) throw new ArgumentNullException("strText"); + + return strText.Replace(@"&", @"&&"); + } + + public static string EncodeToolTipText(string strText) + { + if(strText == null) throw new ArgumentNullException("strText"); + + return strText.Replace(@"&", @"&&&"); + } + public static bool IsHexString(string str, bool bStrict) { if(str == null) throw new ArgumentNullException("str"); @@ -970,7 +1093,7 @@ namespace KeePassLib.Utility bMultiComp = true; } - str = us.ToString() + str; + str = us.ToString(NumberFormatInfo.InvariantInfo) + str; } uVersion >>= 16; @@ -994,7 +1117,7 @@ namespace KeePassLib.Utility byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt, DataProtectionScope.CurrentUser); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None); #else return Convert.ToBase64String(pbEnc); @@ -1030,7 +1153,7 @@ namespace KeePassLib.Utility for(int i = 0; i < vNumbers.Length; ++i) { if(i > 0) sb.Append(' '); - sb.Append(vNumbers[i]); + sb.Append(vNumbers[i].ToString(NumberFormatInfo.InvariantInfo)); } return sb.ToString(); @@ -1047,7 +1170,7 @@ namespace KeePassLib.Utility for(int i = 0; i < vParts.Length; ++i) { int n; - if(!TryParseInt(vParts[i], out n)) { Debug.Assert(false); } + if(!TryParseIntInvariant(vParts[i], out n)) { Debug.Assert(false); } v[i] = n; } @@ -1107,7 +1230,7 @@ namespace KeePassLib.Utility Array.Reverse(pb); for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65); -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) return Convert.ToBase64String(pb, Base64FormattingOptions.None); #else return Convert.ToBase64String(pb); @@ -1225,9 +1348,33 @@ namespace KeePassLib.Utility public static bool IsDataUri(string strUri) { - if(strUri == null) { Debug.Assert(false); return false; } + return IsDataUri(strUri, null); + } - return strUri.StartsWith("data:", StrUtil.CaseIgnoreCmp); + public static bool IsDataUri(string strUri, string strReqMimeType) + { + if(strUri == null) { Debug.Assert(false); return false; } + // strReqMimeType may be null + + const string strPrefix = "data:"; + if(!strUri.StartsWith(strPrefix, StrUtil.CaseIgnoreCmp)) + return false; + + int iC = strUri.IndexOf(','); + if(iC < 0) return false; + + if(!string.IsNullOrEmpty(strReqMimeType)) + { + int iS = strUri.IndexOf(';', 0, iC); + int iTerm = ((iS >= 0) ? iS : iC); + + string strMime = strUri.Substring(strPrefix.Length, + iTerm - strPrefix.Length); + if(!strMime.Equals(strReqMimeType, StrUtil.CaseIgnoreCmp)) + return false; + } + + return true; } /// @@ -1243,7 +1390,7 @@ namespace KeePassLib.Utility if(strMimeType == null) strMimeType = "application/octet-stream"; -#if !KeePassLibSD +#if (!KeePassLibSD && !KeePassRT) return ("data:" + strMimeType + ";base64," + Convert.ToBase64String( pbData, Base64FormattingOptions.None)); #else @@ -1274,13 +1421,19 @@ namespace KeePassLib.Utility MemoryStream ms = new MemoryStream(); +#if KeePassRT + Encoding enc = StrUtil.Utf8; +#else + Encoding enc = Encoding.ASCII; +#endif + string[] v = strData.Split('%'); - byte[] pb = Encoding.ASCII.GetBytes(v[0]); + byte[] pb = enc.GetBytes(v[0]); ms.Write(pb, 0, pb.Length); for(int i = 1; i < v.Length; ++i) { ms.WriteByte(Convert.ToByte(v[i].Substring(0, 2), 16)); - pb = Encoding.ASCII.GetBytes(v[i].Substring(2)); + pb = enc.GetBytes(v[i].Substring(2)); ms.Write(pb, 0, pb.Length); } @@ -1330,5 +1483,72 @@ namespace KeePassLib.Utility return null; } + + private static string[] m_vPrefSepChars = null; + /// + /// Find a character that does not occur within a given text. + /// + public static char GetUnusedChar(string strText) + { + if(strText == null) { Debug.Assert(false); return '@'; } + + if(m_vPrefSepChars == null) + m_vPrefSepChars = new string[5] { + "@!$%#/\\:;,.*-_?", + PwCharSet.UpperCase, PwCharSet.LowerCase, + PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial + }; + + for(int i = 0; i < m_vPrefSepChars.Length; ++i) + { + foreach(char ch in m_vPrefSepChars[i]) + { + if(strText.IndexOf(ch) < 0) return ch; + } + } + + for(char ch = '\u00C0'; ch < char.MaxValue; ++ch) + { + if(strText.IndexOf(ch) < 0) return ch; + } + + return char.MinValue; + } + + public static char ByteToSafeChar(byte bt) + { + const char chDefault = '.'; + + // 00-1F are C0 control chars + if(bt < 0x20) return chDefault; + + // 20-7F are basic Latin; 7F is DEL + if(bt < 0x7F) return (char)bt; + + // 80-9F are C1 control chars + if(bt < 0xA0) return chDefault; + + // A0-FF are Latin-1 supplement; AD is soft hyphen + if(bt == 0xAD) return '-'; + return (char)bt; + } + + public static int Count(string str, string strNeedle) + { + if(str == null) { Debug.Assert(false); return 0; } + if(string.IsNullOrEmpty(strNeedle)) { Debug.Assert(false); return 0; } + + int iOffset = 0, iCount = 0; + while(iOffset < str.Length) + { + int p = str.IndexOf(strNeedle, iOffset); + if(p < 0) break; + + ++iCount; + iOffset = p + 1; + } + + return iCount; + } } } diff --git a/src/KeePassLib2Android/Utility/TimeUtil.cs b/src/KeePassLib2Android/Utility/TimeUtil.cs index 94aa4cd2..f851c16a 100644 --- a/src/KeePassLib2Android/Utility/TimeUtil.cs +++ b/src/KeePassLib2Android/Utility/TimeUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -20,6 +20,8 @@ using System; using System.Diagnostics; +using KeePassLib.Interfaces; + namespace KeePassLib.Utility { /// @@ -218,5 +220,44 @@ namespace KeePassLib.Utility return null; } #endif + + private static readonly DateTime m_dtInvMin = + new DateTime(2999, 12, 27, 23, 59, 59); + private static readonly DateTime m_dtInvMax = + new DateTime(2999, 12, 29, 23, 59, 59); + public static int Compare(DateTime dtA, DateTime dtB, bool bUnkIsPast) + { + if(bUnkIsPast) + { + // 2999-12-28 23:59:59 in KeePass 1.x means 'unknown'; + // expect time zone corruption (twice) + // bool bInvA = ((dtA.Year == 2999) && (dtA.Month == 12) && + // (dtA.Day >= 27) && (dtA.Day <= 29) && (dtA.Minute == 59) && + // (dtA.Second == 59)); + // bool bInvB = ((dtB.Year == 2999) && (dtB.Month == 12) && + // (dtB.Day >= 27) && (dtB.Day <= 29) && (dtB.Minute == 59) && + // (dtB.Second == 59)); + // Faster due to internal implementation of DateTime: + bool bInvA = ((dtA >= m_dtInvMin) && (dtA <= m_dtInvMax) && + (dtA.Minute == 59) && (dtA.Second == 59)); + bool bInvB = ((dtB >= m_dtInvMin) && (dtB <= m_dtInvMax) && + (dtB.Minute == 59) && (dtB.Second == 59)); + + if(bInvA) return (bInvB ? 0 : -1); + if(bInvB) return 1; + } + + return dtA.CompareTo(dtB); + } + + internal static int CompareLastMod(ITimeLogger tlA, ITimeLogger tlB, + bool bUnkIsPast) + { + if(tlA == null) { Debug.Assert(false); return ((tlB == null) ? 0 : -1); } + if(tlB == null) { Debug.Assert(false); return 1; } + + return Compare(tlA.LastModificationTime, tlB.LastModificationTime, + bUnkIsPast); + } } } diff --git a/src/KeePassLib2Android/Utility/UrlUtil.cs b/src/KeePassLib2Android/Utility/UrlUtil.cs index d9c903a4..50150134 100644 --- a/src/KeePassLib2Android/Utility/UrlUtil.cs +++ b/src/KeePassLib2Android/Utility/UrlUtil.cs @@ -1,6 +1,6 @@ /* KeePass Password Safe - The Open-Source Password Manager - Copyright (C) 2003-2012 Dominik Reichl + Copyright (C) 2003-2013 Dominik Reichl 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 @@ -34,8 +34,19 @@ namespace KeePassLib.Utility /// public static class UrlUtil { - private static readonly char[] m_vDirSeps = new char[] { '\\', '/', - Path.DirectorySeparatorChar }; + private static readonly char[] m_vDirSeps = new char[] { + '\\', '/', UrlUtil.LocalDirSepChar }; + private static readonly char[] m_vPathTrimCharsWs = new char[] { + '\"', ' ', '\t', '\r', '\n' }; + + public static char LocalDirSepChar + { +#if KeePassRT + get { return '\\'; } +#else + get { return Path.DirectorySeparatorChar; } +#endif + } /// /// Get the directory (path) of a file name. The returned string is @@ -148,7 +159,7 @@ namespace KeePassLib.Utility } if(bUrl) return (strPath + '/'); - return (strPath + Path.DirectorySeparatorChar); + return (strPath + UrlUtil.LocalDirSepChar); } /* /// @@ -211,13 +222,22 @@ namespace KeePassLib.Utility public static string GetQuotedAppPath(string strPath) { - int nFirst = strPath.IndexOf('\"'); - int nSecond = strPath.IndexOf('\"', nFirst + 1); + if(strPath == null) { Debug.Assert(false); return string.Empty; } - if((nFirst >= 0) && (nSecond >= 0)) - return strPath.Substring(nFirst + 1, nSecond - nFirst - 1); + // int nFirst = strPath.IndexOf('\"'); + // int nSecond = strPath.IndexOf('\"', nFirst + 1); + // if((nFirst >= 0) && (nSecond >= 0)) + // return strPath.Substring(nFirst + 1, nSecond - nFirst - 1); + // return strPath; - return strPath; + string str = strPath.Trim(); + if(str.Length <= 1) return str; + if(str[0] != '\"') return str; + + int iSecond = str.IndexOf('\"', 1); + if(iSecond <= 0) return str; + + return str.Substring(1, iSecond - 1); } public static string FileUrlToPath(string strUrl) @@ -229,14 +249,14 @@ namespace KeePassLib.Utility if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp)) str = str.Substring(8, str.Length - 8); - str = str.Replace('/', Path.DirectorySeparatorChar); + str = str.Replace('/', UrlUtil.LocalDirSepChar); return str; } public static bool UnhideFile(string strFile) { -#if KeePassLibSD +#if (KeePassLibSD || KeePassRT) return false; #else if(strFile == null) throw new ArgumentNullException("strFile"); @@ -256,7 +276,7 @@ namespace KeePassLib.Utility public static bool HideFile(string strFile, bool bHide) { -#if KeePassLibSD +#if (KeePassLibSD || KeePassRT) return false; #else if(strFile == null) throw new ArgumentNullException("strFile"); @@ -297,7 +317,9 @@ namespace KeePassLib.Utility return strTargetFile; } +#if (!KeePassLibSD && !KeePassRT) if(NativeLib.IsUnix()) +#endif { bool bBaseUnc = IsUncPath(strBaseFile); bool bTargetUnc = IsUncPath(strTargetFile); @@ -316,21 +338,19 @@ namespace KeePassLib.Utility StringBuilder sbRel = new StringBuilder(); for(int j = i; j < (vBase.Length - 1); ++j) { - if(sbRel.Length > 0) sbRel.Append(Path.DirectorySeparatorChar); + if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar); sbRel.Append(".."); } for(int k = i; k < vTarget.Length; ++k) { - if(sbRel.Length > 0) sbRel.Append(Path.DirectorySeparatorChar); + if(sbRel.Length > 0) sbRel.Append(UrlUtil.LocalDirSepChar); sbRel.Append(vTarget[k]); } return sbRel.ToString(); } -#if KeePassLibSD - return strTargetFile; -#else +#if (!KeePassLibSD && !KeePassRT) try // Windows { const int nMaxPath = NativeMethods.MAX_PATH * 2; @@ -344,7 +364,8 @@ namespace KeePassLib.Utility return str; } - catch(Exception) { Debug.Assert(false); return strTargetFile; } + catch(Exception) { Debug.Assert(false); } + return strTargetFile; #endif } @@ -420,7 +441,16 @@ namespace KeePassLib.Utility } string str; - try { str = Path.GetFullPath(strPath); } + try + { +#if KeePassRT + var dirT = Windows.Storage.StorageFolder.GetFolderFromPathAsync( + strPath).AwaitEx(); + str = dirT.Path; +#else + str = Path.GetFullPath(strPath); +#endif + } catch(Exception) { Debug.Assert(false); return strPath; } Debug.Assert(str.IndexOf("\\..\\") < 0); @@ -476,7 +506,7 @@ namespace KeePassLib.Utility public static string ConvertSeparators(string strPath) { - return ConvertSeparators(strPath, Path.DirectorySeparatorChar); + return ConvertSeparators(strPath, UrlUtil.LocalDirSepChar); } public static string ConvertSeparators(string strPath, char chSeparator) @@ -594,7 +624,11 @@ namespace KeePassLib.Utility string strDir; if(NativeLib.IsUnix()) strDir = NativeMethods.GetUserRuntimeDir(); +#if KeePassRT + else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path; +#else else strDir = Path.GetTempPath(); +#endif try { @@ -605,5 +639,83 @@ namespace KeePassLib.Utility return strDir; } + +#if !KeePassLibSD + // Structurally mostly equivalent to UrlUtil.GetFileInfos + public static List GetFilePaths(string strDir, string strPattern, + SearchOption opt) + { + List l = new List(); + if(strDir == null) { Debug.Assert(false); return l; } + if(strPattern == null) { Debug.Assert(false); return l; } + + string[] v = Directory.GetFiles(strDir, strPattern, opt); + if(v == null) { Debug.Assert(false); return l; } + + // Only accept files with the correct extension; GetFiles may + // return additional files, see GetFiles documentation + string strExt = GetExtension(strPattern); + if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) && + (strExt.IndexOf('?') < 0)) + { + strExt = "." + strExt; + + foreach(string strPathRaw in v) + { + if(strPathRaw == null) { Debug.Assert(false); continue; } + string strPath = strPathRaw.Trim(m_vPathTrimCharsWs); + if(strPath.Length == 0) { Debug.Assert(false); continue; } + Debug.Assert(strPath == strPathRaw); + + if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp)) + continue; + + l.Add(strPathRaw); + } + } + else l.AddRange(v); + + return l; + } + + // Structurally mostly equivalent to UrlUtil.GetFilePaths + public static List GetFileInfos(DirectoryInfo di, string strPattern, + SearchOption opt) + { + List l = new List(); + if(di == null) { Debug.Assert(false); return l; } + if(strPattern == null) { Debug.Assert(false); return l; } + + FileInfo[] v = di.GetFiles(strPattern, opt); + if(v == null) { Debug.Assert(false); return l; } + + // Only accept files with the correct extension; GetFiles may + // return additional files, see GetFiles documentation + string strExt = GetExtension(strPattern); + if(!string.IsNullOrEmpty(strExt) && (strExt.IndexOf('*') < 0) && + (strExt.IndexOf('?') < 0)) + { + strExt = "." + strExt; + + foreach(FileInfo fi in v) + { + if(fi == null) { Debug.Assert(false); continue; } + string strPathRaw = fi.FullName; + if(strPathRaw == null) { Debug.Assert(false); continue; } + string strPath = strPathRaw.Trim(m_vPathTrimCharsWs); + if(strPath.Length == 0) { Debug.Assert(false); continue; } + Debug.Assert(strPath == strPathRaw); + + if(!strPath.EndsWith(strExt, StrUtil.CaseIgnoreCmp)) + continue; + + l.Add(fi); + } + } + else l.AddRange(v); + + return l; + } +#endif } }