Keepass original source code version 2.34

This commit is contained in:
Philipp Crocoll 2016-08-30 04:09:53 +02:00
parent 3585d4f61f
commit 6d1e28e502
84 changed files with 6370 additions and 1972 deletions

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -194,13 +194,6 @@ namespace KeePassLib.Collections
return true;
}
public void Add(AutoTypeAssociation a)
{
Debug.Assert(a != null); if(a == null) throw new ArgumentNullException("a");
m_lWindowAssocs.Add(a);
}
public AutoTypeAssociation GetAt(int iIndex)
{
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
@ -209,6 +202,22 @@ namespace KeePassLib.Collections
return m_lWindowAssocs[iIndex];
}
public void Add(AutoTypeAssociation a)
{
if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); }
m_lWindowAssocs.Add(a);
}
public void Insert(int iIndex, AutoTypeAssociation a)
{
if((iIndex < 0) || (iIndex > m_lWindowAssocs.Count))
throw new ArgumentOutOfRangeException("iIndex");
if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); }
m_lWindowAssocs.Insert(iIndex, a);
}
public void RemoveAt(int iIndex)
{
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
@ -216,5 +225,20 @@ namespace KeePassLib.Collections
m_lWindowAssocs.RemoveAt(iIndex);
}
// public void Sort()
// {
// m_lWindowAssocs.Sort(AutoTypeConfig.AssocCompareFn);
// }
// private static int AssocCompareFn(AutoTypeAssociation x,
// AutoTypeAssociation y)
// {
// if(x == null) { Debug.Assert(false); return ((y == null) ? 0 : -1); }
// if(y == null) { Debug.Assert(false); return 1; }
// int cn = x.WindowName.CompareTo(y.WindowName);
// if(cn != 0) return cn;
// return x.Sequence.CompareTo(y.Sequence);
// }
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,7 +25,6 @@ using System.Diagnostics;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -283,11 +283,7 @@ namespace KeePassLib.Collections
public List<string> GetKeys()
{
List<string> v = new List<string>();
foreach(string strKey in m_vStrings.Keys) v.Add(strKey);
return v;
return new List<string>(m_vStrings.Keys);
}
public void EnableProtection(string strField, bool bProtect)
@ -299,7 +295,8 @@ namespace KeePassLib.Collections
{
byte[] pbData = ps.ReadUtf8();
Set(strField, new ProtectedString(bProtect, pbData));
MemUtil.ZeroByteArray(pbData);
if(bProtect) MemUtil.ZeroByteArray(pbData);
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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);
}
/// <summary>
/// Get an object of the list.
/// </summary>
@ -225,7 +233,7 @@ namespace KeePassLib.Collections
if(nCount <= 1) return;
int nIndex = m_vObjects.IndexOf(tObject);
Debug.Assert(nIndex >= 0);
if(nIndex < 0) { Debug.Assert(false); return; }
if(bUp && (nIndex > 0)) // No assert for top item
{
@ -241,6 +249,68 @@ namespace KeePassLib.Collections
}
}
public void MoveOne(T[] vObjects, bool bUp)
{
Debug.Assert(vObjects != null);
if(vObjects == null) throw new ArgumentNullException("vObjects");
List<int> lIndices = new List<int>();
foreach(T t in vObjects)
{
if(t == null) { Debug.Assert(false); continue; }
int p = IndexOf(t);
if(p >= 0) lIndices.Add(p);
else { Debug.Assert(false); }
}
MoveOne(lIndices.ToArray(), bUp);
}
public void MoveOne(int[] vIndices, bool bUp)
{
Debug.Assert(vIndices != null);
if(vIndices == null) throw new ArgumentNullException("vIndices");
int n = m_vObjects.Count;
if(n <= 1) return; // No moving possible
int m = vIndices.Length;
if(m == 0) return; // Nothing to move
int[] v = new int[m];
Array.Copy(vIndices, v, m);
Array.Sort<int>(v);
if((bUp && (v[0] <= 0)) || (!bUp && (v[m - 1] >= (n - 1))))
return; // Moving as a block is not possible
int iStart = (bUp ? 0 : (m - 1));
int iExcl = (bUp ? m : -1);
int iStep = (bUp ? 1 : -1);
for(int i = iStart; i != iExcl; i += iStep)
{
int p = v[i];
if((p < 0) || (p >= n)) { Debug.Assert(false); continue; }
T t = m_vObjects[p];
if(bUp)
{
Debug.Assert(p > 0);
m_vObjects.RemoveAt(p);
m_vObjects.Insert(p - 1, t);
}
else // Down
{
Debug.Assert(p < (n - 1));
m_vObjects.RemoveAt(p);
m_vObjects.Insert(p + 1, t);
}
}
}
/// <summary>
/// Move some of the objects in this list to the top/bottom.
/// </summary>

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
@ -33,8 +34,8 @@ namespace KeePassLib.Collections
{
public sealed class PwObjectPool
{
private SortedDictionary<PwUuidComparable, IStructureItem> m_dict =
new SortedDictionary<PwUuidComparable, IStructureItem>();
private SortedDictionary<PwUuid, IStructureItem> m_dict =
new SortedDictionary<PwUuid, IStructureItem>();
public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries)
{
@ -42,16 +43,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 +64,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<PwUuidComparable, IStructureItem> kvp in m_dict)
foreach(KeyValuePair<PwUuid, IStructureItem> kvp in m_dict)
{
if(kvp.Value.GetType() != t) return false;
}
@ -77,4 +78,154 @@ namespace KeePassLib.Collections
return true;
}
}
internal sealed class PwObjectPoolEx
{
private Dictionary<PwUuid, ulong> m_dUuidToId =
new Dictionary<PwUuid, ulong>();
private Dictionary<ulong, IStructureItem> m_dIdToItem =
new Dictionary<ulong, IStructureItem>();
private PwObjectPoolEx()
{
}
public static PwObjectPoolEx FromGroup(PwGroup pg)
{
PwObjectPoolEx p = new PwObjectPoolEx();
if(pg == null) { Debug.Assert(false); return p; }
ulong uFreeId = 2; // 0 = "not found", 1 is a hole
p.m_dUuidToId[pg.Uuid] = uFreeId;
p.m_dIdToItem[uFreeId] = pg;
uFreeId += 2; // Make hole
p.AddGroupRec(pg, ref uFreeId);
return p;
}
private void AddGroupRec(PwGroup pg, ref ulong uFreeId)
{
if(pg == null) { Debug.Assert(false); return; }
ulong uId = uFreeId;
// Consecutive entries must have consecutive IDs
foreach(PwEntry pe in pg.Entries)
{
Debug.Assert(!m_dUuidToId.ContainsKey(pe.Uuid));
Debug.Assert(!m_dIdToItem.ContainsValue(pe));
m_dUuidToId[pe.Uuid] = uId;
m_dIdToItem[uId] = pe;
++uId;
}
++uId; // Make hole
// Consecutive groups must have consecutive IDs
foreach(PwGroup pgSub in pg.Groups)
{
Debug.Assert(!m_dUuidToId.ContainsKey(pgSub.Uuid));
Debug.Assert(!m_dIdToItem.ContainsValue(pgSub));
m_dUuidToId[pgSub.Uuid] = uId;
m_dIdToItem[uId] = pgSub;
++uId;
}
++uId; // Make hole
foreach(PwGroup pgSub in pg.Groups)
{
AddGroupRec(pgSub, ref uId);
}
uFreeId = uId;
}
public ulong GetIdByUuid(PwUuid pwUuid)
{
if(pwUuid == null) { Debug.Assert(false); return 0; }
ulong uId;
m_dUuidToId.TryGetValue(pwUuid, out uId);
return uId;
}
public IStructureItem GetItemByUuid(PwUuid pwUuid)
{
if(pwUuid == null) { Debug.Assert(false); return null; }
ulong uId;
if(!m_dUuidToId.TryGetValue(pwUuid, out uId)) return null;
Debug.Assert(uId != 0);
return GetItemById(uId);
}
public IStructureItem GetItemById(ulong uId)
{
IStructureItem p;
m_dIdToItem.TryGetValue(uId, out p);
return p;
}
}
internal sealed class PwObjectBlock<T> : IEnumerable<T>
where T : class, ITimeLogger, IStructureItem, IDeepCloneable<T>
{
private List<T> m_l = new List<T>();
public T PrimaryItem
{
get { return ((m_l.Count > 0) ? m_l[0] : null); }
}
private DateTime m_dtLocationChanged = DateTime.MinValue;
public DateTime LocationChanged
{
get { return m_dtLocationChanged; }
}
private PwObjectPoolEx m_poolAssoc = null;
public PwObjectPoolEx PoolAssoc
{
get { return m_poolAssoc; }
}
public PwObjectBlock()
{
}
#if DEBUG
public override string ToString()
{
return ("PwObjectBlock, Count = " + m_l.Count.ToString());
}
#endif
IEnumerator IEnumerable.GetEnumerator()
{
return m_l.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return m_l.GetEnumerator();
}
public void Add(T t, DateTime dtLoc, PwObjectPoolEx pool)
{
if(t == null) { Debug.Assert(false); return; }
m_l.Add(t);
if(dtLoc > m_dtLocationChanged)
{
m_dtLocationChanged = dtLoc;
m_poolAssoc = pool;
}
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,8 +22,6 @@ using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
namespace KeePassLib.Cryptography.Cipher
{
@ -70,7 +68,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 +84,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 +102,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;
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -26,7 +26,7 @@ using KeePassLib.Utility;
namespace KeePassLib.Cryptography.Cipher
{
public sealed class Salsa20Cipher
public sealed class Salsa20Cipher : IDisposable
{
private uint[] m_state = new uint[16];
private uint[] m_x = new uint[16]; // Working buffer
@ -34,7 +34,7 @@ namespace KeePassLib.Cryptography.Cipher
private byte[] m_output = new byte[64];
private int m_outputPos = 64;
private static readonly uint[] m_sigma = new uint[4]{
private static readonly uint[] m_sigma = new uint[4] {
0x61707865, 0x3320646E, 0x79622D32, 0x6B206574
};
@ -45,6 +45,17 @@ namespace KeePassLib.Cryptography.Cipher
}
~Salsa20Cipher()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool bDisposing)
{
// Clear sensitive data
Array.Clear(m_state, 0, m_state.Length);

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,9 +22,12 @@ using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Resources;
namespace KeePassLib.Cryptography.Cipher
@ -34,8 +37,10 @@ namespace KeePassLib.Cryptography.Cipher
/// </summary>
public sealed class StandardAesEngine : ICipherEngine
{
#if !KeePassUAP
private const CipherMode m_rCipherMode = CipherMode.CBC;
private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7;
#endif
private static PwUuid m_uuidAes = null;
@ -48,11 +53,9 @@ namespace KeePassLib.Cryptography.Cipher
get
{
if(m_uuidAes == null)
{
m_uuidAes = new PwUuid(new byte[]{
0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50,
0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF });
}
return m_uuidAes;
}
@ -86,12 +89,12 @@ namespace KeePassLib.Cryptography.Cipher
if(bEncrypt)
{
Debug.Assert(stream.CanWrite);
if(stream.CanWrite == false) throw new ArgumentException("Stream must be writable!");
if(!stream.CanWrite) throw new ArgumentException("Stream must be writable!");
}
else // Decrypt
{
Debug.Assert(stream.CanRead);
if(stream.CanRead == false) throw new ArgumentException("Encrypted stream must be readable!");
if(!stream.CanRead) throw new ArgumentException("Encrypted stream must be readable!");
}
}
@ -99,23 +102,25 @@ 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 KeePassUAP
return StandardAesEngineExt.CreateStream(s, bEncrypt, pbLocalKey, pbLocalIV);
#else
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 +130,7 @@ namespace KeePassLib.Cryptography.Cipher
return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write :
CryptoStreamMode.Read);
#endif
}
public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV)

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,12 +18,14 @@
*/
using System;
using System.Security;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
#endif
using KeePassLib.Native;
using KeePassLib.Utility;
@ -31,8 +33,8 @@ using KeePassLib.Utility;
namespace KeePassLib.Cryptography
{
/// <summary>
/// Cryptographically strong random number generator. The returned values
/// are unpredictable and cannot be reproduced.
/// Cryptographically strong random number generator. The returned
/// values are unpredictable and cannot be reproduced.
/// <c>CryptoRandom</c> is a singleton class.
/// </summary>
public sealed class CryptoRandom
@ -42,6 +44,7 @@ namespace KeePassLib.Cryptography
private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider();
private ulong m_uGeneratedBytesCount = 0;
private static object g_oSyncRoot = new object();
private object m_oSyncRoot = new object();
private static CryptoRandom m_pInstance = null;
@ -49,10 +52,18 @@ namespace KeePassLib.Cryptography
{
get
{
if(m_pInstance != null) return m_pInstance;
CryptoRandom cr;
lock(g_oSyncRoot)
{
cr = m_pInstance;
if(cr == null)
{
cr = new CryptoRandom();
m_pInstance = cr;
}
}
m_pInstance = new CryptoRandom();
return m_pInstance;
return cr;
}
}
@ -100,10 +111,10 @@ namespace KeePassLib.Cryptography
byte[] pbNewData = pbEntropy;
if(pbEntropy.Length >= 64)
{
#if !KeePassLibSD
SHA512Managed shaNew = new SHA512Managed();
#else
#if KeePassLibSD
SHA256Managed shaNew = new SHA256Managed();
#else
SHA512Managed shaNew = new SHA512Managed();
#endif
pbNewData = shaNew.ComputeHash(pbEntropy);
}
@ -115,11 +126,11 @@ namespace KeePassLib.Cryptography
ms.Write(pbNewData, 0, pbNewData.Length);
byte[] pbFinal = ms.ToArray();
#if !KeePassLibSD
#if KeePassLibSD
SHA256Managed shaPool = new SHA256Managed();
#else
Debug.Assert(pbFinal.Length == (64 + pbNewData.Length));
SHA512Managed shaPool = new SHA512Managed();
#else
SHA256Managed shaPool = new SHA256Managed();
#endif
m_pbEntropyPool = shaPool.ComputeHash(pbFinal);
}
@ -138,11 +149,17 @@ namespace KeePassLib.Cryptography
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);
// 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,22 +168,35 @@ namespace KeePassLib.Cryptography
pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID());
ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD
try
{
pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount);
ms.Write(pb, 0, pb.Length);
#if KeePassUAP
Version v = EnvironmentExt.OSVersion.Version;
#else
Version v = Environment.OSVersion.Version;
#endif
pb = MemUtil.UInt32ToBytes((uint)v.GetHashCode());
ms.Write(pb, 0, pb.Length);
#if !KeePassUAP
pb = MemUtil.UInt64ToBytes((ulong)Environment.WorkingSet);
ms.Write(pb, 0, pb.Length);
#endif
}
catch(Exception) { Debug.Assert(false); }
Version v = Environment.OSVersion.Version;
int nv = (v.Major << 28) + (v.MajorRevision << 24) +
(v.Minor << 20) + (v.MinorRevision << 16) +
(v.Revision << 12) + v.Build;
pb = MemUtil.UInt32ToBytes((uint)nv);
ms.Write(pb, 0, pb.Length);
#if KeePassUAP
pb = DiagnosticsExt.GetProcessEntropy();
ms.Write(pb, 0, pb.Length);
#elif !KeePassLibSD
Process p = null;
try
{
p = Process.GetCurrentProcess();
Process p = Process.GetCurrentProcess();
pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64());
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)p.HandleCount);
@ -198,7 +228,12 @@ namespace KeePassLib.Cryptography
// pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
// ms.Write(pb, 0, pb.Length);
}
catch(Exception) { }
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
finally
{
try { if(p != null) p.Dispose(); }
catch(Exception) { Debug.Assert(false); }
}
#endif
pb = Guid.NewGuid().ToByteArray();
@ -266,7 +301,7 @@ namespace KeePassLib.Cryptography
long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32);
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy);
#else
Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy);

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,7 +19,10 @@
using System;
using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography.Cipher;
@ -113,7 +116,7 @@ namespace KeePassLib.Cryptography
{
SHA256Managed sha256 = new SHA256Managed();
byte[] pbKey32 = sha256.ComputeHash(pbKey);
byte[] pbIV = new byte[]{ 0xE8, 0x30, 0x09, 0x4B,
byte[] pbIV = new byte[8] { 0xE8, 0x30, 0x09, 0x4B,
0x97, 0x20, 0x5D, 0x2A }; // Unique constant
m_salsa20 = new Salsa20Cipher(pbKey32, pbIV);

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,10 +19,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Utility;
@ -87,12 +90,9 @@ namespace KeePassLib.Cryptography
if(m_hash == null) { Debug.Assert(false); return; }
// Validate hash algorithm
if((!m_hash.CanReuseTransform) || (!m_hash.CanTransformMultipleBlocks) ||
(m_hash.InputBlockSize != 1) || (m_hash.OutputBlockSize != 1))
if(!m_hash.CanReuseTransform || !m_hash.CanTransformMultipleBlocks)
{
#if DEBUG
MessageService.ShowWarning("Broken HashAlgorithm object in HashingStreamEx.");
#endif
Debug.Assert(false);
m_hash = null;
}
}
@ -102,8 +102,14 @@ namespace KeePassLib.Cryptography
m_sBaseStream.Flush();
}
#if KeePassUAP
protected override void Dispose(bool disposing)
{
if(!disposing) return;
#else
public override void Close()
{
#endif
if(m_hash != null)
{
try

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,8 +19,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Utility;
@ -39,7 +43,7 @@ namespace KeePassLib.Cryptography
uint uCodeDigits, bool bAddChecksum, int iTruncationOffset)
{
byte[] pbText = MemUtil.UInt64ToBytes(uFactor);
Array.Reverse(pbText); // Big-Endian
Array.Reverse(pbText); // To big-endian
HMACSHA1 hsha1 = new HMACSHA1(pbSecret);
byte[] pbHash = hsha1.ComputeHash(pbText);
@ -58,7 +62,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,

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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;

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -67,6 +67,17 @@ namespace KeePassLib.Cryptography.PasswordGenerator
pcsUsed.Add(ch);
}
}
else if(ch == '^')
{
ch = csStream.ReadChar();
if(ch == char.MinValue) // ^ at the end
{
vGenerated.AddLast('^');
break;
}
if(bInCharSetDef) pcsCustom.Remove(ch);
}
else if(ch == '[')
{
pcsCustom.Clear();

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -46,51 +46,87 @@ namespace KeePassLib.Cryptography.PasswordGenerator
public const string Invalid = "\t\r\n";
public const string LookAlike = @"O0l1I|";
internal const string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
private const int CharTabSize = (0x10000 / 8);
private List<char> m_vChars = new List<char>();
private byte[] m_vTab = new byte[CharTabSize];
private string m_strHighAnsi = string.Empty;
private string m_strSpecial = string.Empty;
private static string m_strHighAnsi = null;
public static string HighAnsiChars
{
get
{
if(m_strHighAnsi == null) { new PwCharSet(); } // Create string
Debug.Assert(m_strHighAnsi != null);
return m_strHighAnsi;
}
}
private static string m_strSpecial = null;
public static string SpecialChars
{
get
{
if(m_strSpecial == null) { new PwCharSet(); } // Create string
Debug.Assert(m_strSpecial != null);
return m_strSpecial;
}
}
/// <summary>
/// Create a new, empty character set collection object.
/// </summary>
public PwCharSet()
{
this.Initialize(true);
Initialize(true);
}
public PwCharSet(string strCharSet)
{
this.Initialize(true);
this.Add(strCharSet);
Initialize(true);
Add(strCharSet);
}
private PwCharSet(bool bFullInitialize)
{
this.Initialize(bFullInitialize);
Initialize(bFullInitialize);
}
private void Initialize(bool bFullInitialize)
{
this.Clear();
Clear();
if(bFullInitialize == false) return;
if(!bFullInitialize) return;
StringBuilder sbHighAnsi = new StringBuilder();
for(char ch = '~'; ch < 255; ++ch)
sbHighAnsi.Append(ch);
m_strHighAnsi = sbHighAnsi.ToString();
if(m_strHighAnsi == null)
{
StringBuilder sbHighAnsi = new StringBuilder();
// [U+0080, U+009F] are C1 control characters,
// U+00A0 is non-breaking space
for(char ch = '\u00A1'; ch <= '\u00AC'; ++ch)
sbHighAnsi.Append(ch);
// U+00AD is soft hyphen (format character)
for(char ch = '\u00AE'; ch < '\u00FF'; ++ch)
sbHighAnsi.Append(ch);
sbHighAnsi.Append('\u00FF');
PwCharSet pcs = new PwCharSet(false);
pcs.AddRange('!', '/');
pcs.AddRange(':', '@');
pcs.AddRange('[', '`');
pcs.Remove(@"-_ ");
pcs.Remove(PwCharSet.Brackets);
m_strSpecial = pcs.ToString();
m_strHighAnsi = sbHighAnsi.ToString();
}
if(m_strSpecial == null)
{
PwCharSet pcs = new PwCharSet(false);
pcs.AddRange('!', '/');
pcs.AddRange(':', '@');
pcs.AddRange('[', '`');
pcs.Add(@"|~");
pcs.Remove(@"-_ ");
pcs.Remove(PwCharSet.Brackets);
m_strSpecial = pcs.ToString();
}
}
/// <summary>
@ -118,9 +154,6 @@ namespace KeePassLib.Cryptography.PasswordGenerator
}
}
public string SpecialChars { get { return m_strSpecial; } }
public string HighAnsiChars { get { return m_strHighAnsi; } }
/// <summary>
/// Remove all characters from this set.
/// </summary>
@ -142,7 +175,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
foreach(char ch in strCharacters)
{
if(this.Contains(ch) == false) return false;
if(!Contains(ch)) return false;
}
return true;
@ -156,7 +189,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
{
if(ch == char.MinValue) { Debug.Assert(false); return; }
if(this.Contains(ch) == false)
if(!Contains(ch))
{
m_vChars.Add(ch);
m_vTab[ch / 8] |= (byte)(1 << (ch % 8));
@ -175,20 +208,20 @@ namespace KeePassLib.Cryptography.PasswordGenerator
m_vChars.Capacity = m_vChars.Count + strCharSet.Length;
foreach(char ch in strCharSet)
this.Add(ch);
Add(ch);
}
public void Add(string strCharSet1, string strCharSet2)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
Add(strCharSet1);
Add(strCharSet2);
}
public void Add(string strCharSet1, string strCharSet2, string strCharSet3)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
this.Add(strCharSet3);
Add(strCharSet1);
Add(strCharSet2);
Add(strCharSet3);
}
public void AddRange(char chMin, char chMax)
@ -196,9 +229,9 @@ namespace KeePassLib.Cryptography.PasswordGenerator
m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1;
for(char ch = chMin; ch < chMax; ++ch)
this.Add(ch);
Add(ch);
this.Add(chMax);
Add(chMax);
}
public bool AddCharSet(char chCharSetIdentifier)
@ -207,29 +240,29 @@ namespace KeePassLib.Cryptography.PasswordGenerator
switch(chCharSetIdentifier)
{
case 'a': this.Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
case 'A': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
case 'a': Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
case 'A': Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
PwCharSet.Digits); break;
case 'U': this.Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
case 'c': this.Add(PwCharSet.LowerConsonants); break;
case 'C': this.Add(PwCharSet.LowerConsonants,
case 'U': Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
case 'c': Add(PwCharSet.LowerConsonants); break;
case 'C': Add(PwCharSet.LowerConsonants,
PwCharSet.UpperConsonants); break;
case 'z': this.Add(PwCharSet.UpperConsonants); break;
case 'd': this.Add(PwCharSet.Digits); break; // Digit
case 'h': this.Add(PwCharSet.LowerHex); break;
case 'H': this.Add(PwCharSet.UpperHex); break;
case 'l': this.Add(PwCharSet.LowerCase); break;
case 'L': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
case 'u': this.Add(PwCharSet.UpperCase); break;
case 'p': this.Add(PwCharSet.Punctuation); break;
case 'b': this.Add(PwCharSet.Brackets); break;
case 's': this.Add(PwCharSet.PrintableAsciiSpecial); break;
case 'S': this.Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
this.Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
case 'v': this.Add(PwCharSet.LowerVowels); break;
case 'V': this.Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
case 'Z': this.Add(PwCharSet.UpperVowels); break;
case 'x': this.Add(m_strHighAnsi); break;
case 'z': Add(PwCharSet.UpperConsonants); break;
case 'd': Add(PwCharSet.Digits); break; // Digit
case 'h': Add(PwCharSet.LowerHex); break;
case 'H': Add(PwCharSet.UpperHex); break;
case 'l': Add(PwCharSet.LowerCase); break;
case 'L': Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
case 'u': Add(PwCharSet.UpperCase); break;
case 'p': Add(PwCharSet.Punctuation); break;
case 'b': Add(PwCharSet.Brackets); break;
case 's': Add(PwCharSet.PrintableAsciiSpecial); break;
case 'S': Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
case 'v': Add(PwCharSet.LowerVowels); break;
case 'V': Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
case 'Z': Add(PwCharSet.UpperVowels); break;
case 'x': Add(m_strHighAnsi); break;
default: bResult = false; break;
}
@ -238,7 +271,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
public bool Remove(char ch)
{
m_vTab[ch / 8] &= (byte)~(1 << (ch % 8));
m_vTab[ch / 8] &= (byte)(~(1 << (ch % 8)));
return m_vChars.Remove(ch);
}
@ -261,10 +294,10 @@ namespace KeePassLib.Cryptography.PasswordGenerator
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
if(this.Contains(strCharacters) == false)
if(!Contains(strCharacters))
return false;
return this.Remove(strCharacters);
return Remove(strCharacters);
}
/// <summary>
@ -284,16 +317,16 @@ namespace KeePassLib.Cryptography.PasswordGenerator
{
StringBuilder sb = new StringBuilder();
sb.Append(this.RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
sb.Append(this.RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
sb.Append(this.RemoveIfAllExist(@"-") ? 'm' : '_');
sb.Append(this.RemoveIfAllExist(@"_") ? 'u' : '_');
sb.Append(this.RemoveIfAllExist(@" ") ? 's' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
sb.Append(this.RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_');
sb.Append(RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
sb.Append(RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
sb.Append(RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
sb.Append(RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
sb.Append(RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
sb.Append(RemoveIfAllExist(@"-") ? 'm' : '_');
sb.Append(RemoveIfAllExist(@"_") ? 'u' : '_');
sb.Append(RemoveIfAllExist(@" ") ? 's' : '_');
sb.Append(RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
sb.Append(RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_');
return sb.ToString();
}
@ -303,16 +336,16 @@ namespace KeePassLib.Cryptography.PasswordGenerator
if(strRanges == null) { Debug.Assert(false); return; }
if(strRanges.Length < 10) { Debug.Assert(false); return; }
if(strRanges[0] != '_') this.Add(PwCharSet.UpperCase);
if(strRanges[1] != '_') this.Add(PwCharSet.LowerCase);
if(strRanges[2] != '_') this.Add(PwCharSet.Digits);
if(strRanges[3] != '_') this.Add(m_strSpecial);
if(strRanges[4] != '_') this.Add(PwCharSet.Punctuation);
if(strRanges[5] != '_') this.Add('-');
if(strRanges[6] != '_') this.Add('_');
if(strRanges[7] != '_') this.Add(' ');
if(strRanges[8] != '_') this.Add(PwCharSet.Brackets);
if(strRanges[9] != '_') this.Add(m_strHighAnsi);
if(strRanges[0] != '_') Add(PwCharSet.UpperCase);
if(strRanges[1] != '_') Add(PwCharSet.LowerCase);
if(strRanges[2] != '_') Add(PwCharSet.Digits);
if(strRanges[3] != '_') Add(m_strSpecial);
if(strRanges[4] != '_') Add(PwCharSet.Punctuation);
if(strRanges[5] != '_') Add('-');
if(strRanges[6] != '_') Add('_');
if(strRanges[7] != '_') Add(' ');
if(strRanges[8] != '_') Add(PwCharSet.Brackets);
if(strRanges[9] != '_') Add(m_strHighAnsi);
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -253,14 +253,15 @@ namespace KeePassLib.Cryptography.PasswordGenerator
if((ch >= 'A') && (ch <= 'Z')) pcs.Add(PwCharSet.UpperCase);
else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase);
else if((ch >= '0') && (ch <= '9')) pcs.Add(PwCharSet.Digits);
else if((@"!#$%&'*+,./:;=?@^").IndexOf(ch) >= 0) pcs.Add(pcs.SpecialChars);
else if(PwCharSet.SpecialChars.IndexOf(ch) >= 0)
pcs.Add(PwCharSet.SpecialChars);
else if(ch == ' ') pcs.Add(' ');
else if(ch == '-') pcs.Add('-');
else if(ch == '_') pcs.Add('_');
else if(ch == '\"') pcs.Add(pcs.SpecialChars);
else if(ch == '\\') pcs.Add(pcs.SpecialChars);
else if((@"()[]{}<>").IndexOf(ch) >= 0) pcs.Add(PwCharSet.Brackets);
else if((ch >= '~') && (ch <= 255)) pcs.Add(pcs.HighAnsiChars);
else if(PwCharSet.Brackets.IndexOf(ch) >= 0)
pcs.Add(PwCharSet.Brackets);
else if(PwCharSet.HighAnsiChars.IndexOf(ch) >= 0)
pcs.Add(PwCharSet.HighAnsiChars);
else pcs.Add(ch);
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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
{
/// <summary>
/// Bloom filter-based popular password checking.
/// </summary>
public static class PopularPasswords
{
private const int PpcTableSize = 8192 * 8; // Bits, multiple of 64
private static Dictionary<int, Dictionary<string, bool>> m_dicts =
new Dictionary<int, Dictionary<string, bool>>();
// 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<string, bool> 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<string, bool> 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<string> vPasswords = new List<string>();
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<string, bool> d;
if(!m_dicts.TryGetValue(cc, out d))
{
d = new Dictionary<string, bool>();
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

View File

@ -1,6 +1,6 @@
/*
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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
/// </summary>
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<char, ulong> m_dHisto = new Dictionary<char, ulong>();
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<char, bool> d = new Dictionary<char, bool>();
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<char, EntropyEncoder> m_dEncs =
new Dictionary<char, EntropyEncoder>();
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<QePatternInstance> Path;
public QePathState(int iPosition, List<QePatternInstance> lPath)
{
this.Position = iPosition;
this.Path = lPath;
}
}
private static object m_objSyncInit = new object();
private static List<QeCharType> 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<QeCharType>();
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));
}
}
}
/// <summary>
@ -46,84 +320,95 @@ namespace KeePassLib.Cryptography
/// </summary>
/// <param name="vPasswordChars">Password to check.</param>
/// <returns>Estimated bit-strength of the password.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
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<char, uint> vCharCounts = new Dictionary<char, uint>();
Dictionary<int, uint> vDifferences = new Dictionary<int, uint>();
double dblEffectiveLength = 0.0;
EnsureInitialized();
for(int i = 0; i < vPasswordChars.Length; ++i) // Get character types
int n = vPasswordChars.Length;
List<QePatternInstance>[] vPatterns = new List<QePatternInstance>[n];
for(int i = 0; i < n; ++i)
{
char tch = vPasswordChars[i];
vPatterns[i] = new List<QePatternInstance>();
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<QePathState> sRec = new Stack<QePathState>();
sRec.Push(new QePathState(0, new List<QePatternInstance>()));
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<QePatternInstance> 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<QePatternInstance> lNewPath =
new List<QePatternInstance>(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);
}
/// <summary>
@ -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<QePatternInstance> 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<QePatternInstance>[] 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<char>(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<QePatternInstance>[] 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<QePatternInstance>[] 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<QePatternInstance>[] 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<QePatternInstance>[] 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<QePatternInstance>[] 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
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,21 +20,32 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Security;
using System.Security.Cryptography;
using System.Text;
#if KeePassUAP
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
#else
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Keys;
using KeePassLib.Native;
using KeePassLib.Utility;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
#if (KeePassUAP && KeePassLibSD)
#error KeePassUAP and KeePassLibSD are mutually exclusive.
#endif
namespace KeePassLib.Cryptography
{
/* #pragma warning disable 1591
/// <summary>
/* /// <summary>
/// Return values of the <c>SelfTest.Perform</c> method.
/// </summary>
public enum SelfTestResult
@ -43,8 +54,7 @@ namespace KeePassLib.Cryptography
RijndaelEcbError = 1,
Salsa20Error = 2,
NativeKeyTransformationError = 3
}
#pragma warning restore 1591 */
} */
/// <summary>
/// Class containing self-test methods.
@ -73,15 +83,21 @@ namespace KeePassLib.Cryptography
Debug.Assert((int)PwIcon.World == 1);
Debug.Assert((int)PwIcon.Warning == 2);
Debug.Assert((int)PwIcon.BlackBerry == 68);
#if KeePassUAP
SelfTestEx.Perform();
#endif
}
internal static void TestFipsComplianceProblems()
{
#if !KeePassUAP
try { new RijndaelManaged(); }
catch(Exception exAes)
{
throw new SecurityException("AES/Rijndael: " + exAes.Message);
}
#endif
try { new SHA256Managed(); }
catch(Exception exSha256)
@ -106,6 +122,13 @@ namespace KeePassLib.Cryptography
for(i = 0; i < 16; ++i) pbTestData[i] = 0;
pbTestData[0] = 0x04;
#if KeePassUAP
AesEngine r = new AesEngine();
r.Init(true, new KeyParameter(pbTestKey));
if(r.GetBlockSize() != pbTestData.Length)
throw new SecurityException(KLRes.EncAlgorithmAes + " (BS).");
r.ProcessBlock(pbTestData, 0, pbTestData, 0);
#else
RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size
@ -121,6 +144,7 @@ namespace KeePassLib.Cryptography
ICryptoTransform iCrypt = r.CreateEncryptor();
iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0);
#endif
if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
throw new SecurityException(KLRes.EncAlgorithmAes + ".");
@ -146,7 +170,7 @@ namespace KeePassLib.Cryptography
Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV);
c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected))
throw new SecurityException("Salsa20.");
throw new SecurityException("Salsa20-1");
#if DEBUG
// Extended test in debug mode
@ -163,13 +187,24 @@ namespace KeePassLib.Cryptography
int nPos = Salsa20ToPos(c, r, pb.Length, 65536);
c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected2))
throw new SecurityException("Salsa20-2.");
throw new SecurityException("Salsa20-2");
nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008);
Array.Clear(pb, 0, pb.Length);
c.Encrypt(pb, pb.Length, true);
if(!MemUtil.ArraysEqual(pb, pbExpected3))
throw new SecurityException("Salsa20-3.");
throw new SecurityException("Salsa20-3");
Dictionary<string, bool> d = new Dictionary<string, bool>();
const int nRounds = 100;
for(int i = 0; i < nRounds; ++i)
{
byte[] z = new byte[32];
c = new Salsa20Cipher(z, BitConverter.GetBytes((long)i));
c.Encrypt(z, z.Length, true);
d[MemUtil.ByteArrayToHexString(z)] = true;
}
if(d.Count != nRounds) throw new SecurityException("Salsa20-4");
#endif
}
@ -200,12 +235,12 @@ namespace KeePassLib.Cryptography
byte[] pbManaged = new byte[32];
Array.Copy(pbOrgKey, pbManaged, 32);
if(CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds) == false)
if(!CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds))
throw new SecurityException("Managed transform.");
byte[] pbNative = new byte[32];
Array.Copy(pbOrgKey, pbNative, 32);
if(NativeLib.TransformKey256(pbNative, pbSeed, uRounds) == false)
if(!NativeLib.TransformKey256(pbNative, pbSeed, uRounds))
return; // Native library not available ("success")
if(!MemUtil.ArraysEqual(pbManaged, pbNative))
@ -224,35 +259,64 @@ 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<byte>(pb, pbN) != 9)
throw new InvalidOperationException("MemUtil-1");
pbN = Encoding.ASCII.GetBytes("01234567890123");
pbN = enc.GetBytes("01234567890123");
if(MemUtil.IndexOf<byte>(pb, pbN) != 0)
throw new InvalidOperationException("MemUtil-2");
pbN = Encoding.ASCII.GetBytes("a");
pbN = enc.GetBytes("a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 21)
throw new InvalidOperationException("MemUtil-3");
pbN = Encoding.ASCII.GetBytes("0a");
pbN = enc.GetBytes("0a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 20)
throw new InvalidOperationException("MemUtil-4");
pbN = Encoding.ASCII.GetBytes("1");
pbN = enc.GetBytes("1");
if(MemUtil.IndexOf<byte>(pb, pbN) != 1)
throw new InvalidOperationException("MemUtil-5");
pbN = Encoding.ASCII.GetBytes("b");
pbN = enc.GetBytes("b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-6");
pbN = Encoding.ASCII.GetBytes("012b");
pbN = enc.GetBytes("012b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-7");
byte[] pbRes = MemUtil.ParseBase32("MY======");
byte[] pbExp = Encoding.ASCII.GetBytes("f");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-1");
pbRes = MemUtil.ParseBase32("MZXQ====");
pbExp = Encoding.ASCII.GetBytes("fo");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-2");
pbRes = MemUtil.ParseBase32("MZXW6===");
pbExp = Encoding.ASCII.GetBytes("foo");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-3");
pbRes = MemUtil.ParseBase32("MZXW6YQ=");
pbExp = Encoding.ASCII.GetBytes("foob");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-4");
pbRes = MemUtil.ParseBase32("MZXW6YTB");
pbExp = Encoding.ASCII.GetBytes("fooba");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-5");
pbRes = MemUtil.ParseBase32("MZXW6YTBOI======");
pbExp = Encoding.ASCII.GetBytes("foobar");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-6");
pbRes = MemUtil.ParseBase32("JNSXSIDQOJXXM2LEMVZCAYTBONSWIIDPNYQG63TFFV2GS3LFEBYGC43TO5XXEZDTFY======");
pbExp = Encoding.ASCII.GetBytes("Key provider based on one-time passwords.");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-7");
#endif
}
private static void TestHmacOtp()
{
#if (DEBUG && !KeePassLibSD)
byte[] pbSecret = Encoding.ASCII.GetBytes("12345678901234567890");
byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890");
string[] vExp = new string[]{ "755224", "287082", "359152",
"969429", "338314", "254676", "287922", "162583", "399871",
"520489" };
@ -268,7 +332,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 +343,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 +367,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();
@ -318,6 +383,41 @@ namespace KeePassLib.Cryptography
throw new SecurityException("ProtectedString-8");
if(!ps.IsProtected) throw new SecurityException("ProtectedString-9");
if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10");
Random r = new Random();
string str = string.Empty;
ps = new ProtectedString();
for(int i = 0; i < 100; ++i)
{
bool bProt = ((r.Next() % 4) != 0);
ps = ps.WithProtection(bProt);
int x = r.Next(str.Length + 1);
int c = r.Next(20);
char ch = (char)r.Next(1, 256);
string strIns = new string(ch, c);
str = str.Insert(x, strIns);
ps = ps.Insert(x, strIns);
if(ps.IsProtected != bProt)
throw new SecurityException("ProtectedString-11");
if(ps.ReadString() != str)
throw new SecurityException("ProtectedString-12");
ps = ps.WithProtection(bProt);
x = r.Next(str.Length);
c = r.Next(str.Length - x + 1);
str = str.Remove(x, c);
ps = ps.Remove(x, c);
if(ps.IsProtected != bProt)
throw new SecurityException("ProtectedString-13");
if(ps.ReadString() != str)
throw new SecurityException("ProtectedString-14");
}
#endif
}
@ -358,16 +458,74 @@ namespace KeePassLib.Cryptography
throw new InvalidOperationException("StrUtil-V3");
if(StrUtil.VersionToString(0x00FF000000000000UL) != "255")
throw new InvalidOperationException("StrUtil-V4");
if(StrUtil.VersionToString(0x00FF000000000000UL, true) != "255.0")
if(StrUtil.VersionToString(0x00FF000000000000UL, 2) != "255.0")
throw new InvalidOperationException("StrUtil-V5");
if(StrUtil.VersionToString(0x0000000000070000UL, true) != "0.0.7")
if(StrUtil.VersionToString(0x0000000000070000UL) != "0.0.7")
throw new InvalidOperationException("StrUtil-V6");
if(StrUtil.VersionToString(0x0000000000000000UL) != "0")
throw new InvalidOperationException("StrUtil-V7");
if(StrUtil.VersionToString(0x00000000FFFF0000UL, 4) != "0.0.65535.0")
throw new InvalidOperationException("StrUtil-V8");
if(StrUtil.VersionToString(0x0000000000000000UL, 4) != "0.0.0.0")
throw new InvalidOperationException("StrUtil-V9");
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");
if(!string.Equals("abcd", "aBcd", StrUtil.CaseIgnoreCmp))
throw new InvalidOperationException("StrUtil-Case1");
if(string.Equals(@"a<b", @"a>b", StrUtil.CaseIgnoreCmp))
throw new InvalidOperationException("StrUtil-Case2");
#endif
}
private static void TestUrlUtil()
{
#if DEBUG
#if !KeePassUAP
Debug.Assert(Uri.UriSchemeHttp.Equals("http", StrUtil.CaseIgnoreCmp));
Debug.Assert(Uri.UriSchemeHttps.Equals("https", StrUtil.CaseIgnoreCmp));
#endif
if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") !=
"domain")
throw new InvalidOperationException("UrlUtil-H1");
@ -396,6 +554,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
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -39,18 +39,18 @@ namespace KeePassLib.Interfaces
}
/// <summary>
/// The date/time when the object was last accessed.
/// The date/time when the object was last modified.
/// </summary>
DateTime LastAccessTime
DateTime LastModificationTime
{
get;
set;
}
/// <summary>
/// The date/time when the object was last modified.
/// The date/time when the object was last accessed.
/// </summary>
DateTime LastModificationTime
DateTime LastAccessTime
{
get;
set;

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,11 +18,17 @@
*/
using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
#if KeePassUAP
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
#else
using System.Security.Cryptography;
#endif
using KeePassLib.Native;
using KeePassLib.Resources;
@ -118,8 +124,15 @@ namespace KeePassLib.Keys
foreach(IUserKey pKey in m_vUserKeys)
{
if(pKey == null) { Debug.Assert(false); continue; }
#if KeePassUAP
if(pKey.GetType() == tUserKeyType)
return true;
#else
if(tUserKeyType.IsInstanceOfType(pKey))
return true;
#endif
}
return false;
@ -138,8 +151,15 @@ namespace KeePassLib.Keys
foreach(IUserKey pKey in m_vUserKeys)
{
if(pKey == null) { Debug.Assert(false); continue; }
#if KeePassUAP
if(pKey.GetType() == tUserKeyType)
return pKey;
#else
if(tUserKeyType.IsInstanceOfType(pKey))
return pKey;
#endif
}
return null;
@ -154,21 +174,32 @@ namespace KeePassLib.Keys
ValidateUserKeys();
// Concatenate user key data
MemoryStream ms = new MemoryStream();
List<byte[]> lData = new List<byte[]>();
int cbData = 0;
foreach(IUserKey pKey in m_vUserKeys)
{
ProtectedBinary b = pKey.KeyData;
if(b != null)
{
byte[] pbKeyData = b.ReadData();
ms.Write(pbKeyData, 0, pbKeyData.Length);
MemUtil.ZeroByteArray(pbKeyData);
lData.Add(pbKeyData);
cbData += pbKeyData.Length;
}
}
byte[] pbAllData = new byte[cbData];
int p = 0;
foreach(byte[] pbData in lData)
{
Array.Copy(pbData, 0, pbAllData, p, pbData.Length);
p += pbData.Length;
MemUtil.ZeroByteArray(pbData);
}
Debug.Assert(p == cbData);
SHA256Managed sha256 = new SHA256Managed();
byte[] pbHash = sha256.ComputeHash(ms.ToArray());
ms.Close();
byte[] pbHash = sha256.ComputeHash(pbAllData);
MemUtil.ZeroByteArray(pbAllData);
return pbHash;
}
@ -179,8 +210,8 @@ namespace KeePassLib.Keys
byte[] pbThis = CreateRawCompositeKey32();
byte[] pbOther = ckOther.CreateRawCompositeKey32();
bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
Array.Clear(pbOther, 0, pbOther.Length);
Array.Clear(pbThis, 0, pbThis.Length);
MemUtil.ZeroByteArray(pbOther);
MemUtil.ZeroByteArray(pbThis);
return bResult;
}
@ -256,20 +287,34 @@ namespace KeePassLib.Keys
byte[] pbNewKey = new byte[32];
Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length);
// Try to use the native library first
if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds))
try
{
// Try to use the native library first
if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds))
return (new SHA256Managed()).ComputeHash(pbNewKey);
if(!TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds))
return null;
return (new SHA256Managed()).ComputeHash(pbNewKey);
if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds) == false)
return null;
SHA256Managed sha256 = new SHA256Managed();
return sha256.ComputeHash(pbNewKey);
}
finally { MemUtil.ZeroByteArray(pbNewKey); }
}
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
ulong uNumRounds)
{
#if KeePassUAP
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 +346,7 @@ namespace KeePassLib.Keys
iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0);
iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16);
}
#endif
return true;
}
@ -325,9 +371,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 +379,14 @@ namespace KeePassLib.Keys
pbNewKey[i] = (byte)i;
}
#if KeePassUAP
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 +409,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 KeePassUAP
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 +433,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;

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,12 +19,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,14 +18,18 @@
*/
using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Text;
using System.Xml;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Serialization;
using KeePassLib.Utility;
@ -60,19 +64,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 +156,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 +267,18 @@ 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);
#if KeePassUAP
XmlWriterSettings xws = new XmlWriterSettings();
xws.Encoding = StrUtil.Utf8;
xws.Indent = false;
XmlWriter xtw = XmlWriter.Create(sOut, xws);
#else
XmlTextWriter xtw = new XmlTextWriter(sOut, StrUtil.Utf8);
#endif
xtw.WriteStartDocument();
xtw.WriteWhitespace("\r\n");
@ -266,6 +309,8 @@ namespace KeePassLib.Keys
xtw.WriteWhitespace("\r\n");
xtw.WriteEndDocument(); // End KeyFile
xtw.Close();
sOut.Close();
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,9 +18,12 @@
*/
using System;
using System.Text;
using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Security;
using KeePassLib.Utility;
@ -68,6 +71,10 @@ namespace KeePassLib.Keys
Debug.Assert(pbPasswordUtf8 != null);
if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8");
#if (DEBUG && !KeePassLibSD)
Debug.Assert(ValidatePassword(pbPasswordUtf8));
#endif
SHA256Managed sha256 = new SHA256Managed();
byte[] pbRaw = sha256.ComputeHash(pbPasswordUtf8);
@ -80,5 +87,19 @@ namespace KeePassLib.Keys
// m_psPassword = null;
// m_pbKeyData = null;
// }
#if (DEBUG && !KeePassLibSD)
private static bool ValidatePassword(byte[] pb)
{
try
{
string str = StrUtil.Utf8.GetString(pb);
return str.IsNormalized(NormalizationForm.FormC);
}
catch(Exception) { Debug.Assert(false); }
return false;
}
#endif
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,9 +18,13 @@
*/
using System;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
using System.Security;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography;
using KeePassLib.Resources;
@ -37,7 +41,7 @@ namespace KeePassLib.Keys
private ProtectedBinary m_pbKeyData = null;
// Constant initialization vector (unique for KeePass)
private static readonly byte[] m_pbEntropy = new byte[]{
private static readonly byte[] m_pbEntropy = new byte[] {
0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
};
@ -67,10 +71,14 @@ namespace KeePassLib.Keys
byte[] pbKey = LoadUserKey(false);
if(pbKey == null) pbKey = CreateUserKey();
if(pbKey == null) throw new SecurityException(KLRes.UserAccountKeyError);
if(pbKey == null) // Should never happen
{
Debug.Assert(false);
throw new SecurityException(KLRes.UserAccountKeyError);
}
m_pbKeyData = new ProtectedBinary(true, pbKey);
Array.Clear(pbKey, 0, pbKey.Length);
MemUtil.ZeroByteArray(pbKey);
}
// public void Clear()
@ -80,8 +88,12 @@ namespace KeePassLib.Keys
private static string GetUserKeyFilePath(bool bCreate)
{
#if KeePassUAP
string strUserDir = EnvironmentExt.AppDataRoamingFolderPath;
#else
string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
#endif
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
strUserDir += PwDefs.ShortProductName;
@ -90,10 +102,10 @@ namespace KeePassLib.Keys
Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
return strUserDir + UserKeyFileName;
return (strUserDir + UserKeyFileName);
}
private static byte[] LoadUserKey(bool bShowWarning)
private static byte[] LoadUserKey(bool bThrow)
{
byte[] pbKey = null;
@ -105,13 +117,10 @@ namespace KeePassLib.Keys
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
}
catch(Exception exLoad)
catch(Exception)
{
if(bShowWarning) MessageService.ShowWarning(exLoad);
if(bThrow) throw;
pbKey = null;
}
#endif
@ -121,28 +130,23 @@ namespace KeePassLib.Keys
private static byte[] CreateUserKey()
{
byte[] pbKey = null;
#if KeePassLibSD
return null;
#else
string strFilePath = GetUserKeyFilePath(true);
#if !KeePassLibSD
try
{
string strFilePath = GetUserKeyFilePath(true);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
m_pbEntropy, DataProtectionScope.CurrentUser);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
m_pbEntropy, DataProtectionScope.CurrentUser);
File.WriteAllBytes(strFilePath, pbProtectedKey);
File.WriteAllBytes(strFilePath, pbProtectedKey);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
Array.Clear(pbRandomKey, 0, pbRandomKey.Length);
pbKey = LoadUserKey(true);
}
catch(Exception) { pbKey = null; }
#endif
byte[] pbKey = LoadUserKey(true);
Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey));
MemUtil.ZeroByteArray(pbRandomKey);
return pbKey;
#endif
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,8 +19,17 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
#if !KeePassUAP
using System.IO;
using System.Threading;
using System.Windows.Forms;
#endif
using KeePassLib.Utility;
@ -44,6 +53,61 @@ namespace KeePassLib.Native
set { m_bAllowNative = value; }
}
private static int? g_oiPointerSize = null;
/// <summary>
/// Size of a native pointer (in bytes).
/// </summary>
public static int PointerSize
{
get
{
if(!g_oiPointerSize.HasValue)
#if KeePassUAP
g_oiPointerSize = Marshal.SizeOf<IntPtr>();
#else
g_oiPointerSize = Marshal.SizeOf(typeof(IntPtr));
#endif
return g_oiPointerSize.Value;
}
}
private static ulong? m_ouMonoVersion = null;
public static ulong MonoVersion
{
get
{
if(m_ouMonoVersion.HasValue) return m_ouMonoVersion.Value;
ulong uVersion = 0;
try
{
Type t = Type.GetType("Mono.Runtime");
if(t != null)
{
MethodInfo mi = t.GetMethod("GetDisplayName",
BindingFlags.NonPublic | BindingFlags.Static);
if(mi != null)
{
string strName = (mi.Invoke(null, null) as string);
if(!string.IsNullOrEmpty(strName))
{
Match m = Regex.Match(strName, "\\d+(\\.\\d+)+");
if(m.Success)
uVersion = StrUtil.ParseVersion(m.Value);
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }
}
}
catch(Exception) { Debug.Assert(false); }
m_ouMonoVersion = uVersion;
return uVersion;
}
}
/// <summary>
/// Determine if the native library is installed.
/// </summary>
@ -87,9 +151,13 @@ namespace KeePassLib.Native
{
if(m_platID.HasValue) return m_platID.Value;
#if KeePassUAP
m_platID = EnvironmentExt.OSVersion.Platform;
#else
m_platID = Environment.OSVersion.Platform;
#endif
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
// Mono returns PlatformID.Unix on Mac OS X, workaround this
if(m_platID.Value == PlatformID.Unix)
{
@ -102,7 +170,55 @@ namespace KeePassLib.Native
return m_platID.Value;
}
#if !KeePassLibSD
private static DesktopType? m_tDesktop = null;
public static DesktopType GetDesktopType()
{
if(!m_tDesktop.HasValue)
{
DesktopType t = DesktopType.None;
if(!IsUnix()) t = DesktopType.Windows;
else
{
try
{
string strXdg = (Environment.GetEnvironmentVariable(
"XDG_CURRENT_DESKTOP") ?? string.Empty).Trim();
string strGdm = (Environment.GetEnvironmentVariable(
"GDMSESSION") ?? string.Empty).Trim();
StringComparison sc = StrUtil.CaseIgnoreCmp;
if(strXdg.Equals("Unity", sc))
t = DesktopType.Unity;
else if(strXdg.Equals("LXDE", sc))
t = DesktopType.Lxde;
else if(strXdg.Equals("XFCE", sc))
t = DesktopType.Xfce;
else if(strXdg.Equals("MATE", sc))
t = DesktopType.Mate;
else if(strXdg.Equals("X-Cinnamon", sc))
t = DesktopType.Cinnamon;
else if(strXdg.Equals("Pantheon", sc)) // Elementary OS
t = DesktopType.Pantheon;
else if(strXdg.Equals("KDE", sc) || // Mint 16
strGdm.Equals("kde-plasma", sc)) // Ubuntu 12.04
t = DesktopType.Kde;
else if(strXdg.Equals("GNOME", sc))
{
if(strGdm.Equals("cinnamon", sc)) // Mint 13
t = DesktopType.Cinnamon;
else t = DesktopType.Gnome;
}
}
catch(Exception) { Debug.Assert(false); }
}
m_tDesktop = t;
}
return m_tDesktop.Value;
}
#if (!KeePassLibSD && !KeePassUAP)
public static string RunConsoleApp(string strAppPath, string strParams)
{
return RunConsoleApp(strAppPath, strParams, null);
@ -110,40 +226,134 @@ 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)
{
EnsureNoBom(p.StandardInput);
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<Form> lDisabledForms = new List<Form>();
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;
}
return fnRun();
}
private static void EnsureNoBom(StreamWriter sw)
{
if(sw == null) { Debug.Assert(false); return; }
if(!MonoWorkarounds.IsRequired(1219)) return;
try
{
Encoding enc = sw.Encoding;
if(enc == null) { Debug.Assert(false); return; }
byte[] pbBom = enc.GetPreamble();
if((pbBom == null) || (pbBom.Length == 0)) return;
// For Mono >= 4.0 (using Microsoft's reference source)
try
{
FieldInfo fi = typeof(StreamWriter).GetField("haveWrittenPreamble",
BindingFlags.Instance | BindingFlags.NonPublic);
if(fi != null)
{
fi.SetValue(sw, true);
return;
}
}
catch(Exception) { Debug.Assert(false); }
// For Mono < 4.0
FieldInfo fiPD = typeof(StreamWriter).GetField("preamble_done",
BindingFlags.Instance | BindingFlags.NonPublic);
if(fiPD != null) fiPD.SetValue(sw, true);
else { Debug.Assert(false); }
}
catch(Exception) { Debug.Assert(false); }
return null;
}
#endif
@ -157,7 +367,10 @@ namespace KeePassLib.Native
public static bool TransformKey256(byte[] pBuf256, byte[] pKey256,
ulong uRounds)
{
if(m_bAllowNative == false) return false;
#if KeePassUAP
return false;
#else
if(!m_bAllowNative) return false;
KeyValuePair<IntPtr, IntPtr> kvp = PrepareArrays256(pBuf256, pKey256);
bool bResult = false;
@ -170,26 +383,31 @@ namespace KeePassLib.Native
if(bResult) GetBuffers256(kvp, pBuf256, pKey256);
NativeLib.FreeArrays(kvp);
FreeArrays(kvp);
return bResult;
#endif
}
/// <summary>
/// Benchmark key transformation.
/// </summary>
/// <param name="uTimeMs">Number of seconds to perform the benchmark.</param>
/// <param name="uTimeMs">Number of milliseconds to perform the benchmark.</param>
/// <param name="puRounds">Number of transformations done.</param>
/// <returns>Returns <c>true</c>, if the benchmark was successful.</returns>
public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds)
{
puRounds = 0;
if(m_bAllowNative == false) return false;
#if KeePassUAP
return false;
#else
if(!m_bAllowNative) return false;
try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); }
catch(Exception) { return false; }
return true;
#endif
}
private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256,

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,20 +18,22 @@
*/
using System;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using KeePassLib.Utility;
namespace KeePassLib.Native
{
internal static class NativeMethods
internal static partial class NativeMethods
{
internal const int MAX_PATH = 260;
// internal const uint TF_SFT_SHOWNORMAL = 0x00000001;
// internal const uint TF_SFT_HIDDEN = 0x00000008;
/* [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKey")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey32(IntPtr pBuf256,
@ -70,6 +72,7 @@ namespace KeePassLib.Native
return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
} */
#if !KeePassUAP
[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKey256")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey32(IntPtr pBuf256,
@ -83,7 +86,7 @@ namespace KeePassLib.Native
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
UInt64 uRounds)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
if(NativeLib.PointerSize == 8)
return TransformKey64(pBuf256, pKey256, uRounds);
else
return TransformKey32(pBuf256, pKey256, uRounds);
@ -97,67 +100,88 @@ namespace KeePassLib.Native
internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
if(NativeLib.PointerSize == 8)
return TransformKeyBenchmark64(uTimeMs);
else
return TransformKeyBenchmark32(uTimeMs);
return TransformKeyBenchmark32(uTimeMs);
}
#endif
#if !KeePassLibSD
[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
internal static extern int StrCmpLogicalW(string x, string y);
/* [DllImport("KeePassLibC32.dll", EntryPoint = "TF_ShowLangBar")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TF_ShowLangBar32(UInt32 dwFlags);
[DllImport("KeePassLibC64.dll", EntryPoint = "TF_ShowLangBar")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TF_ShowLangBar64(UInt32 dwFlags);
internal static bool TfShowLangBar(uint dwFlags)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
return TF_ShowLangBar64(dwFlags);
return TF_ShowLangBar32(dwFlags);
} */
#if (!KeePassLibSD && !KeePassUAP)
[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath,
[In] string pszFrom, [In] uint dwAttrFrom, [In] string pszTo,
[In] uint dwAttrTo);
#endif
[In] string pszFrom, uint dwAttrFrom, [In] string pszTo, uint dwAttrTo);
private static bool? m_bSupportsLogicalCmp = null;
[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern int StrCmpLogicalW(string x, string y);
private static bool? m_obSupportsLogicalCmp = null;
private static void TestNaturalComparisonsSupport()
{
#if KeePassLibSD
#warning No native natural comparisons supported.
m_bSupportsLogicalCmp = false;
#else
try
{
StrCmpLogicalW("0", "0"); // Throws exception if unsupported
m_bSupportsLogicalCmp = true;
m_obSupportsLogicalCmp = true;
}
catch(Exception) { m_bSupportsLogicalCmp = false; }
#endif
catch(Exception) { m_obSupportsLogicalCmp = false; }
}
#endif
internal static bool SupportsStrCmpNaturally
{
get
{
if(m_bSupportsLogicalCmp.HasValue == false)
#if (!KeePassLibSD && !KeePassUAP)
if(!m_obSupportsLogicalCmp.HasValue)
TestNaturalComparisonsSupport();
return m_bSupportsLogicalCmp.Value;
return m_obSupportsLogicalCmp.Value;
#else
return false;
#endif
}
}
internal static int StrCmpNaturally(string x, string y)
{
if(m_bSupportsLogicalCmp.HasValue == false) TestNaturalComparisonsSupport();
if(m_bSupportsLogicalCmp.Value == false) return 0;
#if (!KeePassLibSD && !KeePassUAP)
if(!NativeMethods.SupportsStrCmpNaturally)
{
Debug.Assert(false);
return string.Compare(x, y, true);
}
#if KeePassLibSD
#warning No native natural comparisons supported.
return x.CompareTo(y);
#else
return StrCmpLogicalW(x, y);
#else
Debug.Assert(false);
return string.Compare(x, y, true);
#endif
}
internal static string GetUserRuntimeDir()
{
#if !KeePassLibSD
#if KeePassLibSD
return Path.GetTempPath();
#else
#if KeePassUAP
string strRtDir = EnvironmentExt.AppDataLocalFolderPath;
#else
string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
if(string.IsNullOrEmpty(strRtDir))
strRtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
@ -166,13 +190,12 @@ namespace KeePassLib.Native
Debug.Assert(false);
return Path.GetTempPath(); // Not UrlUtil (otherwise cyclic)
}
#endif
strRtDir = UrlUtil.EnsureTerminatingSeparator(strRtDir, false);
strRtDir += PwDefs.ShortProductName;
return strRtDir;
#else
return Path.GetTempPath();
#endif
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -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-2016 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.34.0.*")]
[assembly: AssemblyFileVersion("2.34.0.0")]

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,9 +18,12 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
#if !KeePassUAP
using System.Drawing;
using System.IO;
#endif
using KeePassLib.Utility;
@ -33,7 +36,13 @@ namespace KeePassLib
{
private PwUuid m_pwUuid;
private byte[] m_pbImageDataPng;
private Image m_pCachedImage;
private Image m_imgOrg = null;
private Dictionary<long, Image> m_dImageCache = new Dictionary<long, Image>();
// Recommended maximum sizes, not obligatory
internal const int MaxWidth = 128;
internal const int MaxHeight = 128;
public PwUuid Uuid
{
@ -45,32 +54,73 @@ namespace KeePassLib
get { return m_pbImageDataPng; }
}
[Obsolete("Use GetImage instead.")]
public Image Image
{
get { return m_pCachedImage; }
#if (!KeePassLibSD && !KeePassUAP)
get { return GetImage(16, 16); } // Backward compatibility
#else
get { return GetImage(); } // Backward compatibility
#endif
}
public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng)
{
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");
m_pwUuid = pwUuid;
m_pbImageDataPng = pbImageDataPng;
#if !KeePassLibSD
// MemoryStream ms = new MemoryStream(m_pbImageDataPng, false);
// m_pCachedImage = Image.FromStream(ms);
// m_imgOrg = Image.FromStream(ms);
// ms.Close();
m_pCachedImage = GfxUtil.LoadImage(m_pbImageDataPng);
#else
m_pCachedImage = null;
#endif
try { m_imgOrg = GfxUtil.LoadImage(m_pbImageDataPng); }
catch(Exception) { Debug.Assert(false); }
if(m_imgOrg != null)
m_dImageCache[GetID(m_imgOrg.Width, m_imgOrg.Height)] =
m_imgOrg;
}
private static long GetID(int w, int h)
{
return (((long)w << 32) ^ (long)h);
}
/// <summary>
/// Get the icon as an <c>Image</c> (original size).
/// </summary>
public Image GetImage()
{
return m_imgOrg;
}
#if (!KeePassLibSD && !KeePassUAP)
/// <summary>
/// Get the icon as an <c>Image</c> (with the specified size).
/// </summary>
/// <param name="w">Width of the returned image.</param>
/// <param name="h">Height of the returned image.</param>
public Image GetImage(int w, int h)
{
if(w < 0) { Debug.Assert(false); return m_imgOrg; }
if(h < 0) { Debug.Assert(false); return m_imgOrg; }
if(m_imgOrg == null) return null;
long lID = GetID(w, h);
Image img;
if(m_dImageCache.TryGetValue(lID, out img)) return img;
img = GfxUtil.ScaleImage(m_imgOrg, w, h, ScaleTransformFlags.UIIcon);
m_dImageCache[lID] = img;
return img;
}
#endif
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,12 +19,13 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
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 <c>FileVersion64</c> instead.
/// </summary>
public const uint Version32 = 0x02140100;
public const uint Version32 = 0x02220000;
/// <summary>
/// Version, encoded as 64-bit unsigned integer
/// (component-wise, 16 bits per component).
/// </summary>
public const ulong FileVersion64 = 0x0002001400010000UL;
public const ulong FileVersion64 = 0x0002002200000000UL;
/// <summary>
/// Version, encoded as string.
/// </summary>
public const string VersionString = "2.20.1";
public const string VersionString = "2.34";
public const string Copyright = @"Copyright © 2003-2012 Dominik Reichl";
public const string Copyright = @"Copyright © 2003-2016 Dominik Reichl";
/// <summary>
/// Product website URL. Terminated by a forward slash.
@ -93,7 +94,8 @@ namespace KeePassLib
/// URL to a TXT file (eventually compressed) that contains information
/// about the latest KeePass version available on the website.
/// </summary>
public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz";
public const string VersionUrl = "https://sslsites.de/keepass.info/update/version2x.txt.gz";
// public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz";
/// <summary>
/// URL to the root path of the online KeePass help. Terminated by
@ -219,7 +221,7 @@ namespace KeePassLib
}
}
#pragma warning disable 1591 // Missing XML comments warning
// #pragma warning disable 1591 // Missing XML comments warning
/// <summary>
/// Search parameters for group and entry searches.
/// </summary>
@ -317,7 +319,11 @@ namespace KeePassLib
set { m_bSearchInTags = value; }
}
#if KeePassUAP
private StringComparison m_scType = StringComparison.OrdinalIgnoreCase;
#else
private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase;
#endif
/// <summary>
/// String comparison type. Specifies the condition when the specified
/// text matches a group/entry string.
@ -405,9 +411,9 @@ namespace KeePassLib
return (SearchParameters)this.MemberwiseClone();
}
}
#pragma warning restore 1591 // Missing XML comments warning
// #pragma warning restore 1591 // Missing XML comments warning
#pragma warning disable 1591 // Missing XML comments warning
// #pragma warning disable 1591 // Missing XML comments warning
/// <summary>
/// Memory protection configuration structure (for default fields).
/// </summary>
@ -437,7 +443,7 @@ namespace KeePassLib
return false;
}
}
#pragma warning restore 1591 // Missing XML comments warning
// #pragma warning restore 1591 // Missing XML comments warning
public sealed class ObjectTouchedEventArgs : EventArgs
{
@ -458,4 +464,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;
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,8 +20,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
#if !KeePassUAP
using System.Drawing;
#endif
using KeePassLib.Collections;
using KeePassLib.Interfaces;
@ -83,7 +85,7 @@ namespace KeePassLib
{
get { return m_pParentGroup; }
/// Plugins: use <c>PwGroup.AddEntry</c> instead.
// Plugins: use <c>PwGroup.AddEntry</c> instead.
internal set { m_pParentGroup = value; }
}
@ -199,15 +201,6 @@ namespace KeePassLib
set { m_tCreation = value; }
}
/// <summary>
/// The date/time when this entry was last accessed (read).
/// </summary>
public DateTime LastAccessTime
{
get { return m_tLastAccess; }
set { m_tLastAccess = value; }
}
/// <summary>
/// The date/time when this entry was last modified.
/// </summary>
@ -217,6 +210,15 @@ namespace KeePassLib
set { m_tLastMod = value; }
}
/// <summary>
/// The date/time when this entry was last accessed (read).
/// </summary>
public DateTime LastAccessTime
{
get { return m_tLastAccess; }
set { m_tLastAccess = value; }
}
/// <summary>
/// The date/time when this entry expires. Use the <c>Expires</c> property
/// to specify if the entry does actually expire or not.
@ -320,6 +322,14 @@ namespace KeePassLib
}
}
#if DEBUG
// For display in debugger
public override string ToString()
{
return (@"PwEntry '" + m_listStrings.ReadSafe(PwDefs.TitleField) + @"'");
}
#endif
/// <summary>
/// Clone the current entry. The returned entry is an exact value copy
/// of the current entry (including UUID and parent group reference).
@ -413,7 +423,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 +466,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 +504,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 +704,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;
@ -844,6 +856,24 @@ namespace KeePassLib
}
}
}
public void SetCreatedNow()
{
DateTime dt = DateTime.Now;
m_tCreation = dt;
m_tLastAccess = dt;
}
public PwEntry Duplicate()
{
PwEntry pe = CloneDeep();
pe.SetUuid(new PwUuid(true), true);
pe.SetCreatedNow();
return pe;
}
}
public sealed class PwEntryComparer : IComparer<PwEntry>
@ -868,6 +898,7 @@ namespace KeePassLib
string strB = b.Strings.ReadSafe(m_strFieldName);
if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB);
return string.Compare(strA, strB, m_bCaseInsensitive);
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -65,6 +65,8 @@ namespace KeePassLib
/// </summary>
public enum PwMergeMethod
{
// Do not change the explicitly assigned values, otherwise
// serialization (e.g. of Ecas triggers) breaks
None = 0,
OverwriteExisting = 1,
KeepExisting = 2,
@ -161,6 +163,26 @@ namespace KeePassLib
Manual = 2
}
public enum ProxyAuthType
{
None = 0,
/// <summary>
/// Use default user credentials (provided by the system).
/// </summary>
Default = 1,
Manual = 2,
/// <summary>
/// <c>Default</c> or <c>Manual</c>, depending on whether
/// manual credentials are available.
/// This type exists for supporting upgrading from KeePass
/// 2.28 to 2.29; the user cannot select this type.
/// </summary>
Auto = 3
}
/// <summary>
/// Comparison modes for in-memory protected objects.
/// </summary>
@ -202,6 +224,96 @@ namespace KeePassLib
IgnoreHistory = 0x10,
IgnoreLastBackup = 0x20,
// For groups:
PropertiesOnly = 0x40,
IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod)
}
public enum IOAccessType
{
None = 0,
/// <summary>
/// The IO connection is being opened for reading.
/// </summary>
Read = 1,
/// <summary>
/// The IO connection is being opened for writing.
/// </summary>
Write = 2,
/// <summary>
/// The IO connection is being opened for testing
/// whether a file/object exists.
/// </summary>
Exists = 3,
/// <summary>
/// The IO connection is being opened for deleting a file/object.
/// </summary>
Delete = 4,
/// <summary>
/// The IO connection is being opened for renaming/moving a file/object.
/// </summary>
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,
// https://sourceforge.net/p/keepass/patches/84/
/// <summary>
/// This flag prevents any handles being garbage-collected
/// before the started process has terminated, without
/// blocking the current thread.
/// </summary>
GCKeepAlive = 4,
// https://sourceforge.net/p/keepass/patches/85/
DoEvents = 8,
DisableForms = 16
}
[Flags]
public enum ScaleTransformFlags
{
None = 0,
/// <summary>
/// <c>UIIcon</c> indicates that the returned image is going
/// to be displayed as icon in the UI and that it is not
/// subject to future changes in size.
/// </summary>
UIIcon = 1
}
public enum DesktopType
{
None = 0,
Windows,
Gnome,
Kde,
Unity,
Lxde,
Xfce,
Mate,
Cinnamon,
Pantheon
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -137,7 +137,7 @@ namespace KeePassLib
{
get { return m_pParentGroup; }
/// Plugins: use <c>PwGroup.AddGroup</c> instead.
// Plugins: use <c>PwGroup.AddGroup</c> instead.
internal set { Debug.Assert(value != this); m_pParentGroup = value; }
}
@ -329,6 +329,14 @@ namespace KeePassLib
m_pwIcon = pwIcon;
}
#if DEBUG
// For display in debugger
public override string ToString()
{
return (@"PwGroup '" + m_strName + @"'");
}
#endif
/// <summary>
/// Deeply clone the current group. The returned group will be an exact
/// value copy of the current object (including UUID, etc.).
@ -352,9 +360,9 @@ namespace KeePassLib
pg.m_pwCustomIconID = m_pwCustomIconID;
pg.m_tCreation = m_tCreation;
pg.m_tExpire = m_tExpire;
pg.m_tLastAccess = m_tLastAccess;
pg.m_tLastMod = m_tLastMod;
pg.m_tLastAccess = m_tLastAccess;
pg.m_tExpire = m_tExpire;
pg.m_bExpires = m_bExpires;
pg.m_uUsageCount = m_uUsageCount;
@ -363,6 +371,9 @@ namespace KeePassLib
pg.m_strDefaultAutoTypeSequence = m_strDefaultAutoTypeSequence;
pg.m_bEnableAutoType = m_bEnableAutoType;
pg.m_bEnableSearching = m_bEnableSearching;
pg.m_pwLastTopVisibleEntry = m_pwLastTopVisibleEntry;
return pg;
@ -385,6 +396,76 @@ namespace KeePassLib
return pg;
}
public bool EqualsGroup(PwGroup pg, PwCompareOptions pwOpt,
MemProtCmpMode mpCmpStr)
{
if(pg == null) { Debug.Assert(false); return false; }
bool bIgnoreLastAccess = ((pwOpt & PwCompareOptions.IgnoreLastAccess) !=
PwCompareOptions.None);
bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) !=
PwCompareOptions.None);
if(!m_uuid.Equals(pg.m_uuid)) return false;
if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
{
if(m_pParentGroup != pg.m_pParentGroup) return false;
if(!bIgnoreLastMod && (m_tParentGroupLastMod != pg.m_tParentGroupLastMod))
return false;
}
if(m_strName != pg.m_strName) return false;
if(m_strNotes != pg.m_strNotes) return false;
if(m_pwIcon != pg.m_pwIcon) return false;
if(!m_pwCustomIconID.Equals(pg.m_pwCustomIconID)) return false;
if(m_tCreation != pg.m_tCreation) return false;
if(!bIgnoreLastMod && (m_tLastMod != pg.m_tLastMod)) return false;
if(!bIgnoreLastAccess && (m_tLastAccess != pg.m_tLastAccess)) return false;
if(m_tExpire != pg.m_tExpire) return false;
if(m_bExpires != pg.m_bExpires) return false;
if(!bIgnoreLastAccess && (m_uUsageCount != pg.m_uUsageCount)) return false;
// if(m_bIsExpanded != pg.m_bIsExpanded) return false;
if(m_strDefaultAutoTypeSequence != pg.m_strDefaultAutoTypeSequence) return false;
if(m_bEnableAutoType.HasValue != pg.m_bEnableAutoType.HasValue) return false;
if(m_bEnableAutoType.HasValue)
{
if(m_bEnableAutoType.Value != pg.m_bEnableAutoType.Value) return false;
}
if(m_bEnableSearching.HasValue != pg.m_bEnableSearching.HasValue) return false;
if(m_bEnableSearching.HasValue)
{
if(m_bEnableSearching.Value != pg.m_bEnableSearching.Value) return false;
}
if(!m_pwLastTopVisibleEntry.Equals(pg.m_pwLastTopVisibleEntry)) return false;
if((pwOpt & PwCompareOptions.PropertiesOnly) == PwCompareOptions.None)
{
if(m_listEntries.UCount != pg.m_listEntries.UCount) return false;
for(uint u = 0; u < m_listEntries.UCount; ++u)
{
PwEntry peA = m_listEntries.GetAt(u);
PwEntry peB = pg.m_listEntries.GetAt(u);
if(!peA.EqualsEntry(peB, pwOpt, mpCmpStr)) return false;
}
if(m_listGroups.UCount != pg.m_listGroups.UCount) return false;
for(uint u = 0; u < m_listGroups.UCount; ++u)
{
PwGroup pgA = m_listGroups.GetAt(u);
PwGroup pgB = pg.m_listGroups.GetAt(u);
if(!pgA.EqualsGroup(pgB, pwOpt, mpCmpStr)) return false;
}
}
return true;
}
/// <summary>
/// Assign properties to the current group based on a template group.
/// </summary>
@ -398,10 +479,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)
@ -422,6 +505,9 @@ namespace KeePassLib
m_strDefaultAutoTypeSequence = pgTemplate.m_strDefaultAutoTypeSequence;
m_bEnableAutoType = pgTemplate.m_bEnableAutoType;
m_bEnableSearching = pgTemplate.m_bEnableSearching;
m_pwLastTopVisibleEntry = pgTemplate.m_pwLastTopVisibleEntry;
}
@ -573,8 +659,6 @@ namespace KeePassLib
/// <summary>
/// Pack all groups into one flat linked list of references (recursively).
/// Temporary IDs (<c>TemporaryID</c> field) and levels (<c>TemporaryLevel</c>)
/// are assigned automatically.
/// </summary>
/// <returns>Flat list of all groups.</returns>
public LinkedList<PwGroup> GetFlatGroupList()
@ -671,6 +755,7 @@ namespace KeePassLib
/// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will
/// be stored.</param>
/// <param name="slStatus">Optional status reporting object.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage,
IStatusLogger slStatus)
{
@ -764,9 +849,11 @@ namespace KeePassLib
Regex rx = null;
if(sp.RegularExpression)
{
RegexOptions ro = RegexOptions.Compiled;
RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled
if((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) ||
#if !KeePassUAP
(sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) ||
#endif
(sp.ComparisonMode == StringComparison.OrdinalIgnoreCase))
{
ro |= RegexOptions.IgnoreCase;
@ -938,6 +1025,30 @@ namespace KeePassLib
return vTags;
}
#if !KeePassLibSD
public IDictionary<string, uint> BuildEntryTagsDict(bool bSort)
{
IDictionary<string, uint> d;
if(!bSort) d = new Dictionary<string, uint>(StrUtil.CaseIgnoreComparer);
else d = new SortedDictionary<string, uint>(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<PwEntry> listStorage,
bool bSearchRecursive)
{
@ -972,7 +1083,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 +1098,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 +1162,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)
@ -1081,6 +1192,8 @@ namespace KeePassLib
/// </summary>
/// <param name="strSeparator">String that separates the group
/// names.</param>
/// <param name="bIncludeTopMostGroup">Specifies whether the returned
/// path starts with the topmost group.</param>
/// <returns>Full path of the group.</returns>
public string GetFullPath(string strSeparator, bool bIncludeTopMostGroup)
{
@ -1151,6 +1264,7 @@ namespace KeePassLib
}
}
#if !KeePassLibSD
/// <summary>
/// Find/create a subtree of groups.
/// </summary>
@ -1164,11 +1278,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 +1325,7 @@ namespace KeePassLib
return pgContainer;
}
#endif
/// <summary>
/// Get the level of the group (i.e. the number of parent groups).
@ -1422,6 +1549,69 @@ namespace KeePassLib
}
m_listGroups.Clear();
}
internal List<PwGroup> GetTopSearchSkippedGroups()
{
List<PwGroup> l = new List<PwGroup>();
if(!GetSearchingEnabledInherited()) l.Add(this);
else GetTopSearchSkippedGroupsRec(l);
return l;
}
private void GetTopSearchSkippedGroupsRec(List<PwGroup> l)
{
if(m_bEnableSearching.HasValue && !m_bEnableSearching.Value)
{
l.Add(this);
return;
}
else { Debug.Assert(GetSearchingEnabledInherited()); }
foreach(PwGroup pgSub in m_listGroups)
pgSub.GetTopSearchSkippedGroupsRec(l);
}
public void SetCreatedNow(bool bRecursive)
{
DateTime dt = DateTime.Now;
m_tCreation = dt;
m_tLastAccess = dt;
if(!bRecursive) return;
GroupHandler gh = delegate(PwGroup pg)
{
pg.m_tCreation = dt;
pg.m_tLastAccess = dt;
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
pe.CreationTime = dt;
pe.LastAccessTime = dt;
return true;
};
TraverseTree(TraversalMethod.PreOrder, gh, eh);
}
public PwGroup Duplicate()
{
PwGroup pg = CloneDeep();
pg.Uuid = new PwUuid(true);
pg.CreateNewItemUuids(true, true, true);
pg.SetCreatedNow(true);
pg.TakeOwnership(true, true, true);
return pg;
}
}
public sealed class PwGroupComparer : IComparer<PwGroup>

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/
using System;
using System.Collections.Generic;
using System.Xml;
using System.Diagnostics;
@ -27,10 +28,10 @@ namespace KeePassLib
{
// [ImmutableObject(true)]
/// <summary>
/// Represents an UUID of a password entry or group. Once created, <c>PwUuid</c>
/// objects aren't modifyable anymore (immutable).
/// Represents an UUID of a password entry or group. Once created,
/// <c>PwUuid</c> objects aren't modifyable anymore (immutable).
/// </summary>
public sealed class PwUuid
public sealed class PwUuid : IComparable<PwUuid>, IEquatable<PwUuid>
{
/// <summary>
/// Standard size in bytes of a UUID.
@ -40,9 +41,9 @@ namespace KeePassLib
/// <summary>
/// Zero UUID (all bytes are zero).
/// </summary>
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
/// <summary>
/// Get the 16 UUID bytes.
@ -52,14 +53,6 @@ namespace KeePassLib
get { return m_pbUuid; }
}
/// <summary>
/// Construct a new UUID object. Its value is initialized to zero.
/// </summary>
private PwUuid()
{
SetZero();
}
/// <summary>
/// Construct a new UUID object.
/// </summary>
@ -88,38 +81,95 @@ namespace KeePassLib
/// otherwise it returns <c>false</c>.</returns>
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);
}
}
/// <summary>
/// Compare this UUID with another.
/// </summary>
/// <param name="uuid">Second UUID object.</param>
/// <returns>Returns <c>true</c> if both PwUuid object contain the same
/// value, otherwise <c>false</c> is returned.</returns>
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<byte> l = new List<byte>(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;
}
/// <summary>
/// Convert the UUID to its string representation.
/// </summary>
@ -129,29 +179,15 @@ namespace KeePassLib
return MemUtil.ByteArrayToHexString(m_pbUuid);
}
/// <summary>
/// Set the UUID value. The input parameter will not be modified.
/// </summary>
/// <param name="uuidBytes">UUID bytes. The byte array must contain
/// exactly <c>UUIDSize</c> bytes, otherwise the function will fail.</param>
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);
}
/// <summary>
/// Set the UUID value to zero.
/// </summary>
private void SetZero()
{
Array.Clear(m_pbUuid, 0, (int)UuidSize);
return ToHexString();
}
#endif
}
[Obsolete]
public sealed class PwUuidComparable : IComparable<PwUuidComparable>
{
private byte[] m_pbUuid = new byte[PwUuid.UuidSize];

View File

@ -29,6 +29,7 @@ namespace KeePassLib.Resources
m_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed);
m_strEncAlgorithmAes = TryGetEx(dictNew, "EncAlgorithmAes", m_strEncAlgorithmAes);
m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard);
m_strExpect100Continue = TryGetEx(dictNew, "Expect100Continue", m_strExpect100Continue);
m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError);
m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText);
m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted);
@ -44,21 +45,28 @@ namespace KeePassLib.Resources
m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported);
m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed);
m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp);
m_strGeneral = TryGetEx(dictNew, "General", m_strGeneral);
m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey);
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_strPassive = TryGetEx(dictNew, "Passive", m_strPassive);
m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth);
m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout);
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError);
m_strUserAgent = TryGetEx(dictNew, "UserAgent", m_strUserAgent);
}
private static readonly string[] m_vKeyNames = {
"CryptoStreamFailed",
"EncAlgorithmAes",
"ErrorInClipboard",
"Expect100Continue",
"FatalError",
"FatalErrorText",
"FileCorrupted",
@ -74,15 +82,21 @@ namespace KeePassLib.Resources
"FileVersionUnsupported",
"FinalKeyCreationFailed",
"FrameworkNotImplExcp",
"General",
"InvalidCompositeKey",
"InvalidCompositeKeyHint",
"InvalidDataWhileDecoding",
"KeePass1xHint",
"KeyFileDbSel",
"MasterSeedLengthInvalid",
"OldFormat",
"Passive",
"PreAuth",
"Timeout",
"TryAgainSecs",
"UnknownHeaderId",
"UserAccountKeyError"
"UserAccountKeyError",
"UserAgent"
};
public static string[] GetKeyNames()
@ -123,6 +137,17 @@ namespace KeePassLib.Resources
get { return m_strErrorInClipboard; }
}
private static string m_strExpect100Continue =
@"Expect 100-Continue responses";
/// <summary>
/// Look up a localized string similar to
/// 'Expect 100-Continue responses'.
/// </summary>
public static string Expect100Continue
{
get { return m_strExpect100Continue; }
}
private static string m_strFatalError =
@"Fatal Error";
/// <summary>
@ -288,6 +313,17 @@ namespace KeePassLib.Resources
get { return m_strFrameworkNotImplExcp; }
}
private static string m_strGeneral =
@"General";
/// <summary>
/// Look up a localized string similar to
/// 'General'.
/// </summary>
public static string General
{
get { return m_strGeneral; }
}
private static string m_strInvalidCompositeKey =
@"The composite key is invalid!";
/// <summary>
@ -332,6 +368,17 @@ namespace KeePassLib.Resources
get { return m_strKeePass1xHint; }
}
private static string m_strKeyFileDbSel =
@"Database files cannot be used as key files.";
/// <summary>
/// Look up a localized string similar to
/// 'Database files cannot be used as key files.'.
/// </summary>
public static string KeyFileDbSel
{
get { return m_strKeyFileDbSel; }
}
private static string m_strMasterSeedLengthInvalid =
@"The length of the master key seed is invalid!";
/// <summary>
@ -354,6 +401,39 @@ namespace KeePassLib.Resources
get { return m_strOldFormat; }
}
private static string m_strPassive =
@"Passive";
/// <summary>
/// Look up a localized string similar to
/// 'Passive'.
/// </summary>
public static string Passive
{
get { return m_strPassive; }
}
private static string m_strPreAuth =
@"Pre-authenticate";
/// <summary>
/// Look up a localized string similar to
/// 'Pre-authenticate'.
/// </summary>
public static string PreAuth
{
get { return m_strPreAuth; }
}
private static string m_strTimeout =
@"Timeout";
/// <summary>
/// Look up a localized string similar to
/// 'Timeout'.
/// </summary>
public static string Timeout
{
get { return m_strTimeout; }
}
private static string m_strTryAgainSecs =
@"Please try it again in a few seconds.";
/// <summary>
@ -386,5 +466,16 @@ namespace KeePassLib.Resources
{
get { return m_strUserAccountKeyError; }
}
private static string m_strUserAgent =
@"User agent";
/// <summary>
/// Look up a localized string similar to
/// 'User agent'.
/// </summary>
public static string UserAgent
{
get { return m_strUserAgent; }
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,10 +18,16 @@
*/
using System;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Threading;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Native;
using KeePassLib.Utility;
#if KeePassLibSD
@ -30,6 +36,17 @@ using KeePassLibSD;
namespace KeePassLib.Security
{
[Flags]
public enum PbCryptFlags
{
None = 0,
Encrypt = 1,
Decrypt = 2
}
public delegate void PbCryptDelegate(byte[] pbData, PbCryptFlags cf,
long lID);
/// <summary>
/// Represents a protected binary, i.e. a byte array that is encrypted
/// in memory. A <c>ProtectedBinary</c> object is immutable and
@ -37,26 +54,98 @@ namespace KeePassLib.Security
/// </summary>
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
{
private const int PmBlockSize = 16;
private const int BlockSize = 16;
// In-memory protection is supported only on Windows 2000 SP3 and
// higher.
private static bool m_bProtectionSupported;
private static PbCryptDelegate g_fExtCrypt = null;
/// <summary>
/// A plugin can provide a custom memory protection method
/// by assigning a non-null delegate to this property.
/// </summary>
public static PbCryptDelegate ExtCrypt
{
get { return g_fExtCrypt; }
set { g_fExtCrypt = value; }
}
// Local copy of the delegate that was used for encryption,
// in order to allow correct decryption even when the global
// delegate changes
private PbCryptDelegate m_fExtCrypt = null;
private enum PbMemProt
{
None = 0,
ProtectedMemory,
Salsa20,
ExtCrypt
}
// ProtectedMemory is supported only on Windows 2000 SP3 and higher
#if !KeePassLibSD
private static bool? g_obProtectedMemorySupported = null;
#endif
private static bool ProtectedMemorySupported
{
get
{
#if KeePassLibSD
return false;
#else
bool? ob = g_obProtectedMemorySupported;
if(ob.HasValue) return ob.Value;
// Mono does not implement any encryption for ProtectedMemory;
// https://sourceforge.net/p/keepass/feature-requests/1907/
if(NativeLib.IsUnix())
{
g_obProtectedMemorySupported = false;
return false;
}
ob = false;
try // Test whether ProtectedMemory is supported
{
// BlockSize * 3 in order to test encryption for multiple
// blocks, but not introduce a power of 2 as factor
byte[] pb = new byte[ProtectedBinary.BlockSize * 3];
for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)i;
ProtectedMemory.Protect(pb, MemoryProtectionScope.SameProcess);
for(int i = 0; i < pb.Length; ++i)
{
if(pb[i] != (byte)i) { ob = true; break; }
}
}
catch(Exception) { } // Windows 98 / ME
g_obProtectedMemorySupported = ob;
return ob.Value;
#endif
}
}
private static long g_lCurID = 0;
private long m_lID;
private byte[] m_pbData; // Never null
// The real length of the data. This value can be different than
// The real length of the data; this value can be different from
// m_pbData.Length, as the length of m_pbData always is a multiple
// of PmBlockSize (required for fast in-memory protection).
// of BlockSize (required for ProtectedMemory)
private uint m_uDataLen;
private bool m_bProtected;
private bool m_bProtected; // Protection requested by the caller
private PbMemProt m_mp = PbMemProt.None; // Actual protection
private object m_objSync = new object();
private static byte[] g_pbKey32 = null;
/// <summary>
/// A flag specifying whether the <c>ProtectedBinary</c> object has
/// turned on in-memory protection or not.
/// turned on memory protection or not.
/// </summary>
public bool IsProtected
{
@ -71,23 +160,9 @@ namespace KeePassLib.Security
get { return m_uDataLen; }
}
static ProtectedBinary()
{
try // Test whether ProtectedMemory is supported
{
byte[] pbDummy = new byte[PmBlockSize * 2];
ProtectedMemory.Protect(pbDummy, MemoryProtectionScope.SameProcess);
m_bProtectionSupported = true;
}
catch(Exception) // Windows 98 / ME
{
m_bProtectionSupported = false;
}
}
/// <summary>
/// Construct a new, empty protected binary data object. Protection
/// is disabled.
/// Construct a new, empty protected binary data object.
/// Protection is disabled.
/// </summary>
public ProtectedBinary()
{
@ -116,34 +191,103 @@ namespace KeePassLib.Security
/// <param name="bEnableProtection">Enable protection or not.</param>
/// <param name="xbProtected"><c>XorredBuffer</c> object used to
/// initialize the <c>ProtectedBinary</c> object.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected)
{
Debug.Assert(xbProtected != null); if(xbProtected == null) throw new ArgumentNullException("xbProtected");
Debug.Assert(xbProtected != null);
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
}
private void Init(bool bEnableProtection, byte[] pbData)
{
if(pbData == null) throw new ArgumentNullException("pbData");
#if KeePassLibSD
m_lID = ++g_lCurID;
#else
m_lID = Interlocked.Increment(ref g_lCurID);
#endif
m_bProtected = bEnableProtection;
m_uDataLen = (uint)pbData.Length;
int nBlocks = (int)m_uDataLen / PmBlockSize;
if((nBlocks * PmBlockSize) < (int)m_uDataLen) ++nBlocks;
Debug.Assert((nBlocks * PmBlockSize) >= (int)m_uDataLen);
const int bs = ProtectedBinary.BlockSize;
int nBlocks = (int)m_uDataLen / bs;
if((nBlocks * bs) < (int)m_uDataLen) ++nBlocks;
Debug.Assert((nBlocks * bs) >= (int)m_uDataLen);
m_pbData = new byte[nBlocks * PmBlockSize];
m_pbData = new byte[nBlocks * bs];
Array.Copy(pbData, m_pbData, (int)m_uDataLen);
// Data size must be > 0, otherwise 'Protect' throws
if(m_bProtected && m_bProtectionSupported && (m_uDataLen > 0))
Encrypt();
}
private void Encrypt()
{
Debug.Assert(m_mp == PbMemProt.None);
// Nothing to do if caller didn't request protection
if(!m_bProtected) return;
// ProtectedMemory.Protect throws for data size == 0
if(m_pbData.Length == 0) return;
PbCryptDelegate f = g_fExtCrypt;
if(f != null)
{
f(m_pbData, PbCryptFlags.Encrypt, m_lID);
m_fExtCrypt = f;
m_mp = PbMemProt.ExtCrypt;
return;
}
if(ProtectedBinary.ProtectedMemorySupported)
{
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
m_mp = PbMemProt.ProtectedMemory;
return;
}
byte[] pbKey32 = g_pbKey32;
if(pbKey32 == null)
{
pbKey32 = CryptoRandom.Instance.GetRandomBytes(32);
byte[] pbUpd = Interlocked.Exchange<byte[]>(ref g_pbKey32, pbKey32);
if(pbUpd != null) pbKey32 = pbUpd;
}
Salsa20Cipher s = new Salsa20Cipher(pbKey32,
BitConverter.GetBytes(m_lID));
s.Encrypt(m_pbData, m_pbData.Length, true);
s.Dispose();
m_mp = PbMemProt.Salsa20;
}
private void Decrypt()
{
if(m_pbData.Length == 0) return;
if(m_mp == PbMemProt.ProtectedMemory)
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess);
else if(m_mp == PbMemProt.Salsa20)
{
Salsa20Cipher s = new Salsa20Cipher(g_pbKey32,
BitConverter.GetBytes(m_lID));
s.Encrypt(m_pbData, m_pbData.Length, true);
s.Dispose();
}
else if(m_mp == PbMemProt.ExtCrypt)
m_fExtCrypt(m_pbData, PbCryptFlags.Decrypt, m_lID);
else { Debug.Assert(m_mp == PbMemProt.None); }
m_mp = PbMemProt.None;
}
/// <summary>
@ -160,16 +304,12 @@ namespace KeePassLib.Security
byte[] pbReturn = new byte[m_uDataLen];
if(m_bProtected && m_bProtectionSupported)
lock(m_objSync)
{
lock(m_objSync)
{
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess);
Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
}
Decrypt();
Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
Encrypt();
}
else Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
return pbReturn;
}
@ -179,9 +319,6 @@ namespace KeePassLib.Security
/// of bytes generated by a random stream.
/// </summary>
/// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected data.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public byte[] ReadXorredData(CryptoRandomStream crsRandomSource)
{
Debug.Assert(crsRandomSource != null);
@ -191,7 +328,7 @@ namespace KeePassLib.Security
uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen);
Debug.Assert(randomPad.Length == pbData.Length);
for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i];
@ -199,8 +336,11 @@ namespace KeePassLib.Security
return pbData;
}
private int? m_hash = null;
public override int GetHashCode()
{
if(m_hash.HasValue) return m_hash.Value;
int h = (m_bProtected ? 0x7B11D289 : 0);
byte[] pb = ReadData();
@ -211,6 +351,7 @@ namespace KeePassLib.Security
}
MemUtil.ZeroByteArray(pb);
m_hash = h;
return h;
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,8 +18,8 @@
*/
using System;
using System.Text;
using System.Diagnostics;
using System.Text;
using KeePassLib.Cryptography;
using KeePassLib.Utility;
@ -47,7 +47,7 @@ namespace KeePassLib.Security
private bool m_bIsProtected;
private static ProtectedString m_psEmpty = new ProtectedString();
private static readonly ProtectedString m_psEmpty = new ProtectedString();
public static ProtectedString Empty
{
get { return m_psEmpty; }
@ -55,7 +55,7 @@ namespace KeePassLib.Security
/// <summary>
/// A flag specifying whether the <c>ProtectedString</c> object
/// has turned on in-memory protection or not.
/// has turned on memory protection or not.
/// </summary>
public bool IsProtected
{
@ -112,10 +112,9 @@ namespace KeePassLib.Security
/// to the value supplied in the parameters.
/// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
/// the string will be protected in-memory (encrypted). If it
/// the string will be protected in memory (encrypted). If it
/// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="strValue">The initial string value. This
/// parameter won't be modified.</param>
/// <param name="strValue">The initial string value.</param>
public ProtectedString(bool bEnableProtection, string strValue)
{
Init(bEnableProtection, strValue);
@ -126,7 +125,7 @@ namespace KeePassLib.Security
/// to the value supplied in the parameters (UTF-8 encoded string).
/// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
/// the string will be protected in-memory (encrypted). If it
/// the string will be protected in memory (encrypted). If it
/// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="vUtf8Value">The initial string value, encoded as
/// UTF-8 byte array. This parameter won't be modified; the caller
@ -144,15 +143,15 @@ namespace KeePassLib.Security
/// <param name="xbProtected"><c>XorredBuffer</c> object containing the
/// string in UTF-8 representation. The UTF-8 string must not
/// be <c>null</c>-terminated.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected)
{
Debug.Assert(xbProtected != null);
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
}
private void Init(bool bEnableProtection, string str)
@ -222,8 +221,6 @@ namespace KeePassLib.Security
/// </summary>
/// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected string.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
{
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
@ -232,7 +229,7 @@ namespace KeePassLib.Security
uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen);
Debug.Assert(randomPad.Length == pbData.Length);
for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i];
@ -246,7 +243,103 @@ namespace KeePassLib.Security
byte[] pb = ReadUtf8();
ProtectedString ps = new ProtectedString(bProtect, pb);
MemUtil.ZeroByteArray(pb);
if(bProtect) MemUtil.ZeroByteArray(pb);
return ps;
}
public ProtectedString Insert(int iStart, string strInsert)
{
if(iStart < 0) throw new ArgumentOutOfRangeException("iStart");
if(strInsert == null) throw new ArgumentNullException("strInsert");
if(strInsert.Length == 0) return this;
// Only operate directly with strings when m_bIsProtected is
// false, not in the case of non-null m_strPlainText, because
// the operation creates a new sequence in memory
if(!m_bIsProtected)
return new ProtectedString(false, ReadString().Insert(
iStart, strInsert));
UTF8Encoding utf8 = StrUtil.Utf8;
byte[] pb = ReadUtf8();
char[] v = utf8.GetChars(pb);
char[] vNew;
try
{
if(iStart > v.Length)
throw new ArgumentOutOfRangeException("iStart");
char[] vIns = strInsert.ToCharArray();
vNew = new char[v.Length + vIns.Length];
Array.Copy(v, 0, vNew, 0, iStart);
Array.Copy(vIns, 0, vNew, iStart, vIns.Length);
Array.Copy(v, iStart, vNew, iStart + vIns.Length,
v.Length - iStart);
}
finally
{
Array.Clear(v, 0, v.Length);
MemUtil.ZeroByteArray(pb);
}
byte[] pbNew = utf8.GetBytes(vNew);
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Insert(iStart, strInsert));
Array.Clear(vNew, 0, vNew.Length);
MemUtil.ZeroByteArray(pbNew);
return ps;
}
public ProtectedString Remove(int iStart, int nCount)
{
if(iStart < 0) throw new ArgumentOutOfRangeException("iStart");
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
if(nCount == 0) return this;
// Only operate directly with strings when m_bIsProtected is
// false, not in the case of non-null m_strPlainText, because
// the operation creates a new sequence in memory
if(!m_bIsProtected)
return new ProtectedString(false, ReadString().Remove(
iStart, nCount));
UTF8Encoding utf8 = StrUtil.Utf8;
byte[] pb = ReadUtf8();
char[] v = utf8.GetChars(pb);
char[] vNew;
try
{
if((iStart + nCount) > v.Length)
throw new ArgumentException("iStart + nCount");
vNew = new char[v.Length - nCount];
Array.Copy(v, 0, vNew, 0, iStart);
Array.Copy(v, iStart + nCount, vNew, iStart, v.Length -
(iStart + nCount));
}
finally
{
Array.Clear(v, 0, v.Length);
MemUtil.ZeroByteArray(pb);
}
byte[] pbNew = utf8.GetBytes(vNew);
ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew);
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Remove(iStart, nCount));
Array.Clear(vNew, 0, vNew.Length);
MemUtil.ZeroByteArray(pbNew);
return ps;
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Text;
using KeePassLib.Utility;
@ -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;
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,10 +19,10 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using KeePassLib.Cryptography;
using KeePassLib.Resources;
@ -154,13 +154,15 @@ namespace KeePassLib.Serialization
byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16);
string strTime = TimeUtil.SerializeUtc(DateTime.Now);
#if !KeePassLibSD
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime,
#if KeePassUAP
EnvironmentExt.UserName, EnvironmentExt.MachineName,
EnvironmentExt.UserDomainName);
#elif KeePassLibSD
string.Empty, string.Empty, string.Empty);
#else
Environment.UserName, Environment.MachineName,
Environment.UserDomainName);
#else
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime,
string.Empty, string.Empty, string.Empty);
#endif
StringBuilder sb = new StringBuilder();
@ -242,8 +244,8 @@ namespace KeePassLib.Serialization
if(bDisposing) Thread.Sleep(50);
}
if(bDisposing && !bFileDeleted)
IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception
// if(bDisposing && !bFileDeleted)
// IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception
m_iocLockFile = null;
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,14 +19,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
using System.Security.AccessControl;
#endif
using KeePassLib.Native;
using KeePassLib.Resources;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
@ -41,6 +43,16 @@ namespace KeePassLib.Serialization
private const string StrTempSuffix = ".tmp";
private static Dictionary<string, bool> g_dEnabled =
new Dictionary<string, bool>(StrUtil.CaseIgnoreComparer);
private static bool g_bExtraSafe = false;
internal static bool ExtraSafe
{
get { return g_bExtraSafe; }
set { g_bExtraSafe = value; }
}
public FileTransactionEx(IOConnectionInfo iocBaseFile)
{
Initialize(iocBaseFile, true);
@ -58,6 +70,30 @@ namespace KeePassLib.Serialization
m_bTransacted = bTransacted;
m_iocBase = iocBaseFile.CloneDeep();
string strPath = m_iocBase.Path;
#if !KeePassUAP
// 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(strPath.StartsWith("ftp:", StrUtil.CaseIgnoreCmp) &&
(Environment.Version.Major >= 4) && !NativeLib.IsUnix())
m_bTransacted = false;
else
{
#endif
foreach(KeyValuePair<string, bool> kvp in g_dEnabled)
{
if(strPath.StartsWith(kvp.Key, StrUtil.CaseIgnoreCmp))
{
m_bTransacted = kvp.Value;
break;
}
}
#if !KeePassUAP
}
#endif
if(m_bTransacted)
{
m_iocTemp = m_iocBase.CloneDeep();
@ -91,11 +127,18 @@ namespace KeePassLib.Serialization
{
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
FileSecurity bkSecurity = null;
bool bEfsEncrypted = false;
#endif
if(g_bExtraSafe)
{
if(!IOConnection.FileExists(m_iocTemp))
throw new FileNotFoundException(m_iocTemp.Path +
MessageService.NewLine + KLRes.FileSaveFailed);
}
if(IOConnection.FileExists(m_iocBase))
{
#if !KeePassLibSD
@ -103,15 +146,18 @@ namespace KeePassLib.Serialization
{
try
{
#if !KeePassUAP
FileAttributes faBase = File.GetAttributes(m_iocBase.Path);
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
#endif
DateTime tCreation = File.GetCreationTime(m_iocBase.Path);
bkSecurity = File.GetAccessControl(m_iocBase.Path);
File.SetCreationTime(m_iocTemp.Path, tCreation);
#if !KeePassUAP
// May throw with Mono
bkSecurity = File.GetAccessControl(m_iocBase.Path);
#endif
}
catch(Exception) { Debug.Assert(false); }
catch(Exception) { Debug.Assert(NativeLib.IsUnix()); }
}
#endif
@ -120,7 +166,7 @@ namespace KeePassLib.Serialization
IOConnection.RenameFile(m_iocTemp, m_iocBase);
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
if(m_iocBase.IsLocalFile())
{
try
@ -140,5 +186,15 @@ namespace KeePassLib.Serialization
if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); // Hide again
}
// For plugins
public static void Configure(string strPrefix, bool? obTransacted)
{
if(string.IsNullOrEmpty(strPrefix)) { Debug.Assert(false); return; }
if(obTransacted.HasValue)
g_dEnabled[strPrefix] = obTransacted.Value;
else g_dEnabled.Remove(strPrefix);
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,11 +18,14 @@
*/
using System;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Native;
using KeePassLib.Utility;
@ -104,9 +107,9 @@ namespace KeePassLib.Serialization
m_bVerify = bVerify;
UTF8Encoding utf8 = StrUtil.Utf8;
if(m_bWriting == false) // Reading mode
if(!m_bWriting) // Reading mode
{
if(m_sBaseStream.CanRead == false)
if(!m_sBaseStream.CanRead)
throw new InvalidOperationException();
m_brInput = new BinaryReader(sBaseStream, utf8);
@ -115,7 +118,7 @@ namespace KeePassLib.Serialization
}
else // Writing mode
{
if(m_sBaseStream.CanWrite == false)
if(!m_sBaseStream.CanWrite)
throw new InvalidOperationException();
m_bwOutput = new BinaryWriter(sBaseStream, utf8);
@ -129,8 +132,14 @@ namespace KeePassLib.Serialization
if(m_bWriting) m_bwOutput.Flush();
}
#if KeePassUAP
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
@ -178,7 +187,7 @@ namespace KeePassLib.Serialization
if(m_nBufferPos == m_pbBuffer.Length)
{
if(ReadHashedBlock() == false)
return nCount - nRemaining; // Bytes actually read
return (nCount - nRemaining); // Bytes actually read
}
int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nRemaining);

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,42 +19,250 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
using System.Reflection;
using System.Text;
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
using System.Net.Cache;
using System.Net.Security;
#endif
#if !KeePassUAP
using System.Security.Cryptography.X509Certificates;
#endif
using KeePassLib.Native;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
#if !KeePassLibSD
public sealed class IOWebClient : WebClient
internal sealed class IOWebClient : WebClient
{
private IOConnectionInfo m_ioc;
public IOWebClient(IOConnectionInfo ioc) : base()
{
m_ioc = ioc;
}
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
IOConnection.ConfigureWebRequest(request);
IOConnection.ConfigureWebRequest(request, m_ioc);
return request;
}
}
#endif
internal abstract class WrapperStream : Stream
{
private readonly Stream m_s;
protected Stream BaseStream
{
get { return m_s; }
}
public override bool CanRead
{
get { return m_s.CanRead; }
}
public override bool CanSeek
{
get { return m_s.CanSeek; }
}
public override bool CanTimeout
{
get { return m_s.CanTimeout; }
}
public override bool CanWrite
{
get { return m_s.CanWrite; }
}
public override long Length
{
get { return m_s.Length; }
}
public override long Position
{
get { return m_s.Position; }
set { m_s.Position = value; }
}
public override int ReadTimeout
{
get { return m_s.ReadTimeout; }
set { m_s.ReadTimeout = value; }
}
public override int WriteTimeout
{
get { return m_s.WriteTimeout; }
set { m_s.WriteTimeout = value; }
}
public WrapperStream(Stream sBase) : base()
{
if(sBase == null) throw new ArgumentNullException("sBase");
m_s = sBase;
}
#if !KeePassUAP
public override IAsyncResult BeginRead(byte[] buffer, int offset,
int count, AsyncCallback callback, object state)
{
return m_s.BeginRead(buffer, offset, count, callback, state);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset,
int count, AsyncCallback callback, object state)
{
return BeginWrite(buffer, offset, count, callback, state);
}
#endif
#if KeePassUAP
protected override void Dispose(bool disposing)
{
if(disposing) m_s.Dispose();
}
#else
public override void Close()
{
m_s.Close();
}
#endif
#if !KeePassUAP
public override int EndRead(IAsyncResult asyncResult)
{
return m_s.EndRead(asyncResult);
}
public override void EndWrite(IAsyncResult asyncResult)
{
m_s.EndWrite(asyncResult);
}
#endif
public override void Flush()
{
m_s.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return m_s.Read(buffer, offset, count);
}
public override int ReadByte()
{
return m_s.ReadByte();
}
public override long Seek(long offset, SeekOrigin origin)
{
return m_s.Seek(offset, origin);
}
public override void SetLength(long value)
{
m_s.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
m_s.Write(buffer, offset, count);
}
public override void WriteByte(byte value)
{
m_s.WriteByte(value);
}
}
internal sealed class IocStream : WrapperStream
{
private readonly bool m_bWrite; // Initially opened for writing
public IocStream(Stream sBase) : base(sBase)
{
m_bWrite = sBase.CanWrite;
}
#if KeePassUAP
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
#else
public override void Close()
{
base.Close();
#endif
if(MonoWorkarounds.IsRequired(10163) && m_bWrite)
{
try
{
Stream s = this.BaseStream;
Type t = s.GetType();
if(t.Name == "WebConnectionStream")
{
PropertyInfo pi = t.GetProperty("Request",
BindingFlags.Instance | BindingFlags.NonPublic);
if(pi != null)
{
WebRequest wr = (pi.GetValue(s, null) as WebRequest);
if(wr != null)
IOConnection.DisposeResponse(wr.GetResponse(), false);
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }
}
}
catch(Exception) { Debug.Assert(false); }
}
}
public static Stream WrapIfRequired(Stream s)
{
if(s == null) { Debug.Assert(false); return null; }
if(MonoWorkarounds.IsRequired(10163) && s.CanWrite)
return new IocStream(s);
return s;
}
}
public static class IOConnection
{
#if !KeePassLibSD
private static ProxyServerType m_pstProxyType = ProxyServerType.System;
private static string m_strProxyAddr = string.Empty;
private static string m_strProxyPort = string.Empty;
private static ProxyAuthType m_patProxyAuthType = ProxyAuthType.Auto;
private static string m_strProxyUserName = string.Empty;
private static string m_strProxyPassword = string.Empty;
#if !KeePassUAP
private static bool? m_obDefaultExpect100Continue = null;
private static bool m_bSslCertsAcceptInvalid = false;
internal static bool SslCertsAcceptInvalid
{
// get { return m_bSslCertsAcceptInvalid; }
set { m_bSslCertsAcceptInvalid = value; }
}
#endif
#endif
// Web request methods
@ -64,41 +272,81 @@ namespace KeePassLib.Serialization
// Web request headers
public const string WrhMoveFileTo = "MoveFileTo";
public static event EventHandler<IOAccessEventArgs> IOAccessPre;
#if !KeePassLibSD
#if !KeePassUAP
// 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;
}
#endif
public static void SetProxy(ProxyServerType pst, string strAddr,
string strPort, string strUserName, string strPassword)
internal static void SetProxy(ProxyServerType pst, string strAddr,
string strPort, ProxyAuthType pat, string strUserName,
string strPassword)
{
m_pstProxyType = pst;
m_strProxyAddr = (strAddr ?? string.Empty);
m_strProxyPort = (strPort ?? string.Empty);
m_patProxyAuthType = pat;
m_strProxyUserName = (strUserName ?? string.Empty);
m_strProxyPassword = (strPassword ?? string.Empty);
}
internal static void ConfigureWebRequest(WebRequest request)
internal static void ConfigureWebRequest(WebRequest request,
IOConnectionInfo ioc)
{
if(request == null) { Debug.Assert(false); return; } // No throw
// WebDAV support
if(request is HttpWebRequest)
{
request.PreAuthenticate = true; // Also auth GET
if(request.Method == WebRequestMethods.Http.Post)
request.Method = WebRequestMethods.Http.Put;
}
// else if(request is FtpWebRequest)
// {
// Debug.Assert(((FtpWebRequest)request).UsePassive);
// }
IocProperties p = ((ioc != null) ? ioc.Properties : null);
if(p == null) { Debug.Assert(false); p = new IocProperties(); }
IHasIocProperties ihpReq = (request as IHasIocProperties);
if(ihpReq != null)
{
IocProperties pEx = ihpReq.IOConnectionProperties;
if(pEx != null) p.CopyTo(pEx);
else ihpReq.IOConnectionProperties = p.CloneDeep();
}
if(IsHttpWebRequest(request))
{
// WebDAV support
#if !KeePassUAP
request.PreAuthenticate = true; // Also auth GET
#endif
if(string.Equals(request.Method, WebRequestMethods.Http.Post,
StrUtil.CaseIgnoreCmp))
request.Method = WebRequestMethods.Http.Put;
#if !KeePassUAP
HttpWebRequest hwr = (request as HttpWebRequest);
if(hwr != null)
{
string strUA = p.Get(IocKnownProperties.UserAgent);
if(!string.IsNullOrEmpty(strUA)) hwr.UserAgent = strUA;
}
else { Debug.Assert(false); }
#endif
}
#if !KeePassUAP
else if(IsFtpWebRequest(request))
{
FtpWebRequest fwr = (request as FtpWebRequest);
if(fwr != null)
{
bool? obPassive = p.GetBool(IocKnownProperties.Passive);
if(obPassive.HasValue) fwr.UsePassive = obPassive.Value;
}
else { Debug.Assert(false); }
}
#endif
#if !KeePassUAP
// Not implemented and ignored in Mono < 2.10
try
{
@ -106,6 +354,7 @@ namespace KeePassLib.Serialization
}
catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); }
#endif
try
{
@ -113,10 +362,20 @@ namespace KeePassLib.Serialization
if(GetWebProxy(out prx)) request.Proxy = prx;
}
catch(Exception) { Debug.Assert(false); }
#if !KeePassUAP
long? olTimeout = p.GetLong(IocKnownProperties.Timeout);
if(olTimeout.HasValue && (olTimeout.Value >= 0))
request.Timeout = (int)Math.Min(olTimeout.Value, (long)int.MaxValue);
bool? ob = p.GetBool(IocKnownProperties.PreAuth);
if(ob.HasValue) request.PreAuthenticate = ob.Value;
#endif
}
internal static void ConfigureWebClient(WebClient wc)
{
#if !KeePassUAP
// Not implemented and ignored in Mono < 2.10
try
{
@ -124,6 +383,7 @@ namespace KeePassLib.Serialization
}
catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); }
#endif
try
{
@ -134,64 +394,163 @@ namespace KeePassLib.Serialization
}
private static bool GetWebProxy(out IWebProxy prx)
{
bool b = GetWebProxyServer(out prx);
if(b) AssignCredentials(prx);
return b;
}
private static bool GetWebProxyServer(out IWebProxy prx)
{
prx = null;
if(m_pstProxyType == ProxyServerType.None)
return true; // Use null proxy
if(m_pstProxyType == ProxyServerType.Manual)
{
try
{
if(m_strProxyPort.Length > 0)
if(m_strProxyAddr.Length == 0)
{
// First try default (from config), then system
prx = WebRequest.DefaultWebProxy;
#if !KeePassUAP
if(prx == null) prx = WebRequest.GetSystemWebProxy();
#endif
}
else if(m_strProxyPort.Length > 0)
prx = new WebProxy(m_strProxyAddr, int.Parse(m_strProxyPort));
else prx = new WebProxy(m_strProxyAddr);
if((m_strProxyUserName.Length > 0) || (m_strProxyPassword.Length > 0))
prx.Credentials = new NetworkCredential(m_strProxyUserName,
m_strProxyPassword);
return true; // Use manual proxy
return (prx != null);
}
catch(Exception exProxy)
#if KeePassUAP
catch(Exception) { Debug.Assert(false); }
#else
catch(Exception ex)
{
string strInfo = m_strProxyAddr;
if(m_strProxyPort.Length > 0) strInfo += ":" + m_strProxyPort;
MessageService.ShowWarning(strInfo, exProxy.Message);
if(m_strProxyPort.Length > 0)
strInfo += ":" + m_strProxyPort;
MessageService.ShowWarning(strInfo, ex.Message);
}
#endif
return false; // Use default
}
if((m_strProxyUserName.Length == 0) && (m_strProxyPassword.Length == 0))
return false; // Use default proxy, no auth
Debug.Assert(m_pstProxyType == ProxyServerType.System);
try
{
prx = WebRequest.DefaultWebProxy;
if(prx == null) prx = WebRequest.GetSystemWebProxy();
if(prx == null) throw new InvalidOperationException();
// First try system, then default (from config)
#if !KeePassUAP
prx = WebRequest.GetSystemWebProxy();
#endif
if(prx == null) prx = WebRequest.DefaultWebProxy;
prx.Credentials = new NetworkCredential(m_strProxyUserName,
m_strProxyPassword);
return true;
return (prx != null);
}
catch(Exception) { Debug.Assert(false); }
return false;
}
private static void PrepareWebAccess()
private static void AssignCredentials(IWebProxy prx)
{
ServicePointManager.ServerCertificateValidationCallback =
ValidateServerCertificate;
if(prx == null) return; // No assert
string strUserName = m_strProxyUserName;
string strPassword = m_strProxyPassword;
ProxyAuthType pat = m_patProxyAuthType;
if(pat == ProxyAuthType.Auto)
{
if((strUserName.Length > 0) || (strPassword.Length > 0))
pat = ProxyAuthType.Manual;
else pat = ProxyAuthType.Default;
}
try
{
if(pat == ProxyAuthType.None)
prx.Credentials = null;
else if(pat == ProxyAuthType.Default)
prx.Credentials = CredentialCache.DefaultCredentials;
else if(pat == ProxyAuthType.Manual)
{
if((strUserName.Length > 0) || (strPassword.Length > 0))
prx.Credentials = new NetworkCredential(
strUserName, strPassword);
}
else { Debug.Assert(false); }
}
catch(Exception) { Debug.Assert(false); }
}
private static void PrepareWebAccess(IOConnectionInfo ioc)
{
#if !KeePassUAP
IocProperties p = ((ioc != null) ? ioc.Properties : null);
if(p == null) { Debug.Assert(false); p = new IocProperties(); }
try
{
if(m_bSslCertsAcceptInvalid)
ServicePointManager.ServerCertificateValidationCallback =
IOConnection.AcceptCertificate;
else
ServicePointManager.ServerCertificateValidationCallback = null;
}
catch(Exception) { Debug.Assert(false); }
try
{
SecurityProtocolType spt = (SecurityProtocolType.Ssl3 |
SecurityProtocolType.Tls);
// The flags Tls11 and Tls12 in SecurityProtocolType have been
// introduced in .NET 4.5 and must not be set when running under
// older .NET versions (otherwise an exception is thrown)
Type tSpt = typeof(SecurityProtocolType);
string[] vSpt = Enum.GetNames(tSpt);
foreach(string strSpt in vSpt)
{
if(strSpt.Equals("Tls11", StrUtil.CaseIgnoreCmp))
spt |= (SecurityProtocolType)Enum.Parse(tSpt, "Tls11", true);
else if(strSpt.Equals("Tls12", StrUtil.CaseIgnoreCmp))
spt |= (SecurityProtocolType)Enum.Parse(tSpt, "Tls12", true);
}
ServicePointManager.SecurityProtocol = spt;
}
catch(Exception) { Debug.Assert(false); }
try
{
bool bCurCont = ServicePointManager.Expect100Continue;
if(!m_obDefaultExpect100Continue.HasValue)
{
Debug.Assert(bCurCont); // Default should be true
m_obDefaultExpect100Continue = bCurCont;
}
bool bNewCont = m_obDefaultExpect100Continue.Value;
bool? ob = p.GetBool(IocKnownProperties.Expect100Continue);
if(ob.HasValue) bNewCont = ob.Value;
if(bNewCont != bCurCont)
ServicePointManager.Expect100Continue = bNewCont;
}
catch(Exception) { Debug.Assert(false); }
#endif
}
private static IOWebClient CreateWebClient(IOConnectionInfo ioc)
{
PrepareWebAccess();
PrepareWebAccess(ioc);
IOWebClient wc = new IOWebClient();
IOWebClient wc = new IOWebClient(ioc);
ConfigureWebClient(wc);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
@ -204,10 +563,10 @@ namespace KeePassLib.Serialization
private static WebRequest CreateWebRequest(IOConnectionInfo ioc)
{
PrepareWebAccess();
PrepareWebAccess(ioc);
WebRequest req = WebRequest.Create(ioc.Path);
ConfigureWebRequest(req);
ConfigureWebRequest(req, ioc);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
@ -219,6 +578,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);
@ -227,11 +588,14 @@ namespace KeePassLib.Serialization
if(ioc.IsLocalFile()) return OpenReadLocal(ioc);
return CreateWebClient(ioc).OpenRead(new Uri(ioc.Path));
return IocStream.WrapIfRequired(CreateWebClient(ioc).OpenRead(
new Uri(ioc.Path)));
}
#else
public static Stream OpenRead(IOConnectionInfo ioc)
{
RaiseIOAccessPreEvent(ioc, IOAccessType.Read);
return OpenReadLocal(ioc);
}
#endif
@ -247,22 +611,26 @@ namespace KeePassLib.Serialization
{
if(ioc == null) { Debug.Assert(false); return null; }
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
if(ioc.IsLocalFile()) return OpenWriteLocal(ioc);
Uri uri = new Uri(ioc.Path);
Stream s;
// Mono does not set HttpWebRequest.Method to POST for writes,
// so one needs to set the method to PUT explicitly
if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp,
StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps,
StrUtil.CaseIgnoreCmp)))
return CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
if(NativeLib.IsUnix() && IsHttpWebRequest(uri))
s = CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
else s = CreateWebClient(ioc).OpenWrite(uri);
return CreateWebClient(ioc).OpenWrite(uri);
return IocStream.WrapIfRequired(s);
}
#else
public static Stream OpenWrite(IOConnectionInfo ioc)
{
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
return OpenWriteLocal(ioc);
}
#endif
@ -282,6 +650,8 @@ 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
@ -317,15 +687,18 @@ namespace KeePassLib.Serialization
public static void DeleteFile(IOConnectionInfo ioc)
{
RaiseIOAccessPreEvent(ioc, IOAccessType.Delete);
if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; }
#if !KeePassLibSD
WebRequest req = CreateWebRequest(ioc);
if(req != null)
{
if(req is HttpWebRequest) req.Method = "DELETE";
else if(req is FtpWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile;
else if(req is FileWebRequest)
if(IsHttpWebRequest(req)) req.Method = "DELETE";
else if(IsFtpWebRequest(req))
req.Method = WebRequestMethods.Ftp.DeleteFile;
else if(IsFileWebRequest(req))
{
File.Delete(UrlUtil.FileUrlToPath(ioc.Path));
return;
@ -348,23 +721,39 @@ namespace KeePassLib.Serialization
/// <param name="iocTo">Target file path.</param>
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
WebRequest req = CreateWebRequest(iocFrom);
if(req != null)
{
if(req is HttpWebRequest)
if(IsHttpWebRequest(req))
{
#if KeePassUAP
throw new NotSupportedException();
#else
req.Method = "MOVE";
req.Headers.Set("Destination", iocTo.Path); // Full URL supported
#endif
}
else if(req is FtpWebRequest)
else if(IsFtpWebRequest(req))
{
#if KeePassUAP
throw new NotSupportedException();
#else
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;
#endif
}
else if(req is FileWebRequest)
else if(IsFileWebRequest(req))
{
File.Move(UrlUtil.FileUrlToPath(iocFrom.Path),
UrlUtil.FileUrlToPath(iocTo.Path));
@ -372,11 +761,17 @@ namespace KeePassLib.Serialization
}
else
{
#if KeePassUAP
throw new NotSupportedException();
#else
req.Method = WrmMoveFile;
req.Headers.Set(WrhMoveFileTo, iocTo.Path);
#endif
}
#if !KeePassUAP // Unreachable code
DisposeResponse(req.GetResponse(), true);
#endif
}
#endif
@ -408,7 +803,7 @@ namespace KeePassLib.Serialization
}
#endif
private static void DisposeResponse(WebResponse wr, bool bGetStream)
internal static void DisposeResponse(WebResponse wr, bool bGetStream)
{
if(wr == null) return;
@ -449,5 +844,67 @@ 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);
}
}
private static bool IsHttpWebRequest(Uri uri)
{
if(uri == null) { Debug.Assert(false); return false; }
string sch = uri.Scheme;
if(sch == null) { Debug.Assert(false); return false; }
return (sch.Equals("http", StrUtil.CaseIgnoreCmp) || // Uri.UriSchemeHttp
sch.Equals("https", StrUtil.CaseIgnoreCmp)); // Uri.UriSchemeHttps
}
internal static bool IsHttpWebRequest(WebRequest wr)
{
if(wr == null) { Debug.Assert(false); return false; }
#if KeePassUAP
return IsHttpWebRequest(wr.RequestUri);
#else
return (wr is HttpWebRequest);
#endif
}
internal static bool IsFtpWebRequest(WebRequest wr)
{
if(wr == null) { Debug.Assert(false); return false; }
#if KeePassUAP
return string.Equals(wr.RequestUri.Scheme, "ftp", StrUtil.CaseIgnoreCmp);
#else
return (wr is FtpWebRequest);
#endif
}
private static bool IsFileWebRequest(WebRequest wr)
{
if(wr == null) { Debug.Assert(false); return false; }
#if KeePassUAP
return string.Equals(wr.RequestUri.Scheme, "file", StrUtil.CaseIgnoreCmp);
#else
return (wr is FileWebRequest);
#endif
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,11 +19,11 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
@ -119,22 +119,67 @@ namespace KeePassLib.Serialization
set { m_ioCredSaveMode = value; }
}
private bool m_bComplete = false;
[XmlIgnore]
public bool IsComplete // Credentials etc. fully specified
{
get { return m_bComplete; }
set { m_bComplete = value; }
}
/* public IOFileFormatHint FileFormatHint
{
get { return m_ioHint; }
set { m_ioHint = value; }
} */
private IocProperties m_props = new IocProperties();
[XmlIgnore]
public IocProperties Properties
{
get { return m_props; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_props = value;
}
}
/// <summary>
/// For serialization only; use <c>Properties</c> in code.
/// </summary>
[DefaultValue("")]
public string PropertiesEx
{
get { return m_props.Serialize(); }
set
{
if(value == null) throw new ArgumentNullException("value");
IocProperties p = IocProperties.Deserialize(value);
Debug.Assert(p != null);
m_props = (p ?? new IocProperties());
}
}
public IOConnectionInfo CloneDeep()
{
return (IOConnectionInfo)this.MemberwiseClone();
IOConnectionInfo ioc = (IOConnectionInfo)this.MemberwiseClone();
ioc.m_props = m_props.CloneDeep();
return ioc;
}
#if DEBUG // For debugger display only
public override string ToString()
{
return GetDisplayName();
}
#endif
/*
/// <summary>
/// Serialize the current connection info to a string. Credentials
/// are only serialized if the <c>SaveCredentials</c> property
/// is <c>true</c>.
/// are serialized based on the <c>CredSaveMode</c> property.
/// </summary>
/// <param name="iocToCompile">Input object to be serialized.</param>
/// <returns>Serialized object as string.</returns>
@ -146,31 +191,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();
@ -276,14 +299,14 @@ namespace KeePassLib.Serialization
string str = m_strUrl;
if(m_strUser.Length > 0)
str += " (" + m_strUser + ")";
str += (" (" + m_strUser + ")");
return str;
}
public bool IsEmpty()
{
return (m_strUrl.Length > 0);
return (m_strUrl.Length == 0);
}
public static IOConnectionInfo FromPath(string strPath)
@ -306,7 +329,7 @@ namespace KeePassLib.Serialization
public bool IsLocalFile()
{
// Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs
return (m_strUrl.IndexOf(@"://") < 0);
return (m_strUrl.IndexOf("://") < 0);
}
public void ClearCredentials(bool bDependingOnRememberMode)

View File

@ -0,0 +1,192 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Xml;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
using StrDict = System.Collections.Generic.Dictionary<string, string>;
namespace KeePassLib.Serialization
{
public interface IHasIocProperties
{
IocProperties IOConnectionProperties { get; set; }
}
public sealed class IocProperties : IDeepCloneable<IocProperties>
{
private StrDict m_dict = new StrDict();
public IocProperties()
{
}
public IocProperties CloneDeep()
{
IocProperties p = new IocProperties();
p.m_dict = new StrDict(m_dict);
return p;
}
public string Get(string strKey)
{
if(string.IsNullOrEmpty(strKey)) return null;
foreach(KeyValuePair<string, string> kvp in m_dict)
{
if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp))
return kvp.Value;
}
return null;
}
public void Set(string strKey, string strValue)
{
if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); return; }
foreach(KeyValuePair<string, string> kvp in m_dict)
{
if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp))
{
if(string.IsNullOrEmpty(strValue)) m_dict.Remove(kvp.Key);
else m_dict[kvp.Key] = strValue;
return;
}
}
if(!string.IsNullOrEmpty(strValue)) m_dict[strKey] = strValue;
}
public bool? GetBool(string strKey)
{
string str = Get(strKey);
if(string.IsNullOrEmpty(str)) return null;
return StrUtil.StringToBool(str);
}
public void SetBool(string strKey, bool? ob)
{
if(ob.HasValue) Set(strKey, (ob.Value ? "1" : "0"));
else Set(strKey, null);
}
public long? GetLong(string strKey)
{
string str = Get(strKey);
if(string.IsNullOrEmpty(str)) return null;
long l;
if(StrUtil.TryParseLongInvariant(str, out l)) return l;
Debug.Assert(false);
return null;
}
public void SetLong(string strKey, long? ol)
{
if(ol.HasValue)
Set(strKey, ol.Value.ToString(NumberFormatInfo.InvariantInfo));
else Set(strKey, null);
}
public string Serialize()
{
if(m_dict.Count == 0) return string.Empty;
StringBuilder sbAll = new StringBuilder();
foreach(KeyValuePair<string, string> kvp in m_dict)
{
sbAll.Append(kvp.Key);
sbAll.Append(kvp.Value);
}
string strAll = sbAll.ToString();
char chSepOuter = ';';
if(strAll.IndexOf(chSepOuter) >= 0)
chSepOuter = StrUtil.GetUnusedChar(strAll);
strAll += chSepOuter;
char chSepInner = '=';
if(strAll.IndexOf(chSepInner) >= 0)
chSepInner = StrUtil.GetUnusedChar(strAll);
StringBuilder sb = new StringBuilder();
sb.Append(chSepOuter);
sb.Append(chSepInner);
foreach(KeyValuePair<string, string> kvp in m_dict)
{
sb.Append(chSepOuter);
sb.Append(kvp.Key);
sb.Append(chSepInner);
sb.Append(kvp.Value);
}
return sb.ToString();
}
public static IocProperties Deserialize(string strSerialized)
{
IocProperties p = new IocProperties();
if(string.IsNullOrEmpty(strSerialized)) return p; // No assert
char chSepOuter = strSerialized[0];
string[] v = strSerialized.Substring(1).Split(new char[] { chSepOuter });
if((v == null) || (v.Length < 2)) { Debug.Assert(false); return p; }
string strMeta = v[0];
if(string.IsNullOrEmpty(strMeta)) { Debug.Assert(false); return p; }
char chSepInner = strMeta[0];
char[] vSepInner = new char[] { chSepInner };
for(int i = 1; i < v.Length; ++i)
{
string strProp = v[i];
if(string.IsNullOrEmpty(strProp)) { Debug.Assert(false); continue; }
string[] vProp = strProp.Split(vSepInner);
if((vProp == null) || (vProp.Length < 2)) { Debug.Assert(false); continue; }
Debug.Assert(vProp.Length == 2);
p.Set(vProp[0], vProp[1]);
}
return p;
}
public void CopyTo(IocProperties p)
{
if(p == null) { Debug.Assert(false); return; }
foreach(KeyValuePair<string, string> kvp in m_dict)
{
p.m_dict[kvp.Key] = kvp.Value;
}
}
}
}

View File

@ -0,0 +1,99 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public sealed class IocPropertyInfo
{
private readonly string m_strName;
public string Name
{
get { return m_strName; }
}
private readonly Type m_t;
public Type Type
{
get { return m_t; }
}
private string m_strDisplayName;
public string DisplayName
{
get { return m_strDisplayName; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strDisplayName = value;
}
}
private List<string> m_lProtocols = new List<string>();
public IEnumerable<string> Protocols
{
get { return m_lProtocols; }
}
public IocPropertyInfo(string strName, Type t, string strDisplayName,
string[] vProtocols)
{
if(strName == null) throw new ArgumentNullException("strName");
if(t == null) throw new ArgumentNullException("t");
if(strDisplayName == null) throw new ArgumentNullException("strDisplayName");
m_strName = strName;
m_t = t;
m_strDisplayName = strDisplayName;
AddProtocols(vProtocols);
}
public void AddProtocols(string[] v)
{
if(v == null) { Debug.Assert(false); return; }
foreach(string strProtocol in v)
{
if(strProtocol == null) continue;
string str = strProtocol.Trim();
if(str.Length == 0) continue;
bool bFound = false;
foreach(string strEx in m_lProtocols)
{
if(strEx.Equals(str, StrUtil.CaseIgnoreCmp))
{
bFound = true;
break;
}
}
if(!bFound) m_lProtocols.Add(str);
}
}
}
}

View File

@ -0,0 +1,123 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using KeePassLib.Resources;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public static class IocKnownProtocols
{
public const string Http = "HTTP";
public const string Https = "HTTPS";
public const string WebDav = "WebDAV";
public const string Ftp = "FTP";
}
public static class IocKnownProperties
{
public const string Timeout = "Timeout";
public const string PreAuth = "PreAuth";
public const string UserAgent = "UserAgent";
public const string Expect100Continue = "Expect100Continue";
public const string Passive = "Passive";
}
public static class IocPropertyInfoPool
{
private static List<IocPropertyInfo> m_l = null;
public static IEnumerable<IocPropertyInfo> PropertyInfos
{
get { EnsureInitialized(); return m_l; }
}
private static void EnsureInitialized()
{
if(m_l != null) return;
string strGen = KLRes.General;
string strHttp = IocKnownProtocols.Http;
string strHttps = IocKnownProtocols.Https;
string strWebDav = IocKnownProtocols.WebDav;
string strFtp = IocKnownProtocols.Ftp;
string[] vGen = new string[] { strGen };
string[] vHttp = new string[] { strHttp, strHttps, strWebDav };
string[] vFtp = new string[] { strFtp };
List<IocPropertyInfo> l = new List<IocPropertyInfo>();
l.Add(new IocPropertyInfo(IocKnownProperties.Timeout,
typeof(long), KLRes.Timeout + " [ms]", vGen));
l.Add(new IocPropertyInfo(IocKnownProperties.PreAuth,
typeof(bool), KLRes.PreAuth, vGen));
l.Add(new IocPropertyInfo(IocKnownProperties.UserAgent,
typeof(string), KLRes.UserAgent, vHttp));
l.Add(new IocPropertyInfo(IocKnownProperties.Expect100Continue,
typeof(bool), KLRes.Expect100Continue, vHttp));
l.Add(new IocPropertyInfo(IocKnownProperties.Passive,
typeof(bool), KLRes.Passive, vFtp));
// l.Add(new IocPropertyInfo("Test", typeof(bool),
// "Long long long long long long long long long long long long long long long long long long long long",
// new string[] { "Proto 1/9", "Proto 2/9", "Proto 3/9", "Proto 4/9", "Proto 5/9",
// "Proto 6/9", "Proto 7/9", "Proto 8/9", "Proto 9/9" }));
m_l = l;
}
public static IocPropertyInfo Get(string strName)
{
if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; }
EnsureInitialized();
foreach(IocPropertyInfo pi in m_l)
{
if(pi.Name.Equals(strName, StrUtil.CaseIgnoreCmp))
return pi;
}
return null;
}
public static bool Add(IocPropertyInfo pi)
{
if(pi == null) { Debug.Assert(false); return false; }
// Name must be non-empty
string strName = pi.Name;
if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; }
IocPropertyInfo piEx = Get(strName); // Ensures initialized
if(piEx != null) { Debug.Assert(false); return false; } // Exists already
m_l.Add(pi);
return true;
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,18 +19,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Xml;
using System.IO;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
#if !KeePassUAP
using System.Drawing;
#endif
using KeePassLib;
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Interfaces;
using KeePassLib.Resources;
using KeePassLib.Security;
@ -100,11 +99,15 @@ namespace KeePassLib.Serialization
xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true;
#if KeePassUAP
xrs.DtdProcessing = DtdProcessing.Prohibit;
#else
#if !KeePassLibSD
xrs.ProhibitDtd = true;
xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
#endif
xrs.ValidationType = ValidationType.None;
#endif
return xrs;
}
@ -451,10 +454,10 @@ namespace KeePassLib.Serialization
(ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry);
Debug.Assert(tl != null);
if(xr.Name == ElemLastModTime)
tl.LastModificationTime = ReadTime(xr);
else if(xr.Name == ElemCreationTime)
if(xr.Name == ElemCreationTime)
tl.CreationTime = ReadTime(xr);
else if(xr.Name == ElemLastModTime)
tl.LastModificationTime = ReadTime(xr);
else if(xr.Name == ElemLastAccessTime)
tl.LastAccessTime = ReadTime(xr);
else if(xr.Name == ElemExpiryTime)
@ -560,7 +563,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 +591,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 +612,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 +720,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 +734,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 +748,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 +762,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);
@ -793,7 +809,19 @@ namespace KeePassLib.Serialization
if(strRef != null)
{
ProtectedBinary pb = BinPoolGet(strRef);
if(pb != null) return pb;
if(pb != null)
{
// https://sourceforge.net/p/keepass/feature-requests/2023/
xr.MoveToElement();
#if DEBUG
string strInner = ReadStringRaw(xr);
Debug.Assert(string.IsNullOrEmpty(strInner));
#else
ReadStringRaw(xr);
#endif
return pb;
}
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,13 +19,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Xml;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
#if !KeePassLibSD
using System.IO.Compression;
#else
@ -127,6 +130,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);
@ -159,6 +178,12 @@ namespace KeePassLib.Serialization
// the history maintenance settings)
m_pwDatabase.MaintainBackups(); // Don't mark database as modified
// Expand the root group, such that in case the user accidently
// collapses the root group he can simply reopen the database
PwGroup pgRoot = m_pwDatabase.RootGroup;
if(pgRoot != null) pgRoot.IsExpanded = true;
else { Debug.Assert(false); }
m_pbHashOfHeader = null;
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,20 +19,22 @@
using System;
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.IO;
using System.Security;
using System.Text;
using System.Xml;
#if !KeePassLibSD
using System.IO.Compression;
#else
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography;
#endif
#if KeePassLibSD
using KeePassLibSD;
#else
using System.IO.Compression;
#endif
using KeePassLib.Collections;
@ -121,7 +123,24 @@ namespace KeePassLib.Serialization
writerStream = hashedStream;
else { Debug.Assert(false); throw new FormatException("KdbFormat"); }
m_xmlWriter = new XmlTextWriter(writerStream, encNoBom);
#if KeePassUAP
XmlWriterSettings xws = new XmlWriterSettings();
xws.Encoding = encNoBom;
xws.Indent = true;
xws.IndentChars = "\t";
xws.NewLineOnAttributes = false;
XmlWriter xw = XmlWriter.Create(writerStream, xws);
#else
XmlTextWriter xw = new XmlTextWriter(writerStream, encNoBom);
xw.Formatting = Formatting.Indented;
xw.IndentChar = '\t';
xw.Indentation = 1;
#endif
m_xmlWriter = xw;
WriteDocument(pgDataSource);
m_xmlWriter.Flush();
@ -241,10 +260,6 @@ namespace KeePassLib.Serialization
BinPoolBuild(pgRoot);
m_xmlWriter.Formatting = Formatting.Indented;
m_xmlWriter.IndentChar = '\t';
m_xmlWriter.Indentation = 1;
m_xmlWriter.WriteStartDocument(true);
m_xmlWriter.WriteStartElement(ElemDocNode);
@ -363,7 +378,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 +403,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);
@ -454,8 +469,8 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteStartElement(name);
WriteObject(ElemLastModTime, times.LastModificationTime);
WriteObject(ElemCreationTime, times.CreationTime);
WriteObject(ElemLastModTime, times.LastModificationTime);
WriteObject(ElemLastAccessTime, times.LastAccessTime);
WriteObject(ElemExpiryTime, times.ExpiryTime);
WriteObject(ElemExpires, times.Expires);
@ -577,7 +592,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 +601,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 +610,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 +619,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 +701,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 +714,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
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,15 +19,11 @@
using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Diagnostics;
#if !KeePassLibSD
using System.IO.Compression;
#endif
using System.Text;
using System.Xml;
using KeePassLib.Collections;
using KeePassLib.Cryptography;
@ -63,12 +59,12 @@ namespace KeePassLib.Serialization
/// <summary>
/// File identifier, first 32-bit value.
/// </summary>
private const uint FileSignature1 = 0x9AA2D903;
internal const uint FileSignature1 = 0x9AA2D903;
/// <summary>
/// File identifier, second 32-bit value.
/// </summary>
private const uint FileSignature2 = 0xB54BFB67;
internal const uint FileSignature2 = 0xB54BFB67;
/// <summary>
/// File version of files saved by the current <c>KdbxFile</c> class.
@ -82,11 +78,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";
@ -191,7 +187,7 @@ namespace KeePassLib.Serialization
private PwDatabase m_pwDatabase; // Not null, see constructor
private XmlTextWriter m_xmlWriter = null;
private XmlWriter m_xmlWriter = null;
private CryptoRandomStream m_randomStream = null;
private KdbxFormat m_format = KdbxFormat.Default;
private IStatusLogger m_slLogger = null;
@ -324,7 +320,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 +363,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;

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,15 +19,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Serialization;
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
#endif
using KeePassLib.Utility;
@ -42,8 +44,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 +114,7 @@ namespace KeePassLib.Translation
else { Debug.Assert(false); }
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
internal void ApplyTo(Control c)
{
Debug.Assert(c != null); if(c == null) return;
@ -267,7 +269,7 @@ namespace KeePassLib.Translation
return m_strMemberName.CompareTo(kpOther.Name);
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
private static readonly Type[] m_vTextControls = new Type[] {
typeof(MenuStrip), typeof(PictureBox), typeof(ListView),
typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser),
@ -309,8 +311,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
{

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,11 +19,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Xml.Serialization;
#if !KeePassUAP
using System.Windows.Forms;
#endif
namespace KeePassLib.Translation
{
@ -66,6 +68,7 @@ namespace KeePassLib.Translation
}
}
#if (!KeePassLibSD && !KeePassUAP)
private Form m_formEnglish = null;
[XmlIgnore]
public Form FormEnglish
@ -74,7 +77,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");

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,10 +19,13 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Xml.Serialization;
#if !KeePassUAP
using System.Windows.Forms;
using System.Diagnostics;
#endif
namespace KeePassLib.Translation
{
@ -66,7 +69,7 @@ namespace KeePassLib.Translation
return dict;
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
public void ApplyTo(ToolStripItemCollection tsic)
{
if(tsic == null) throw new ArgumentNullException("tsic");

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,24 +19,27 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.ComponentModel;
#if !KeePassUAP
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
#endif
#if KeePassLibSD
using ICSharpCode.SharpZipLib.GZip;
#else
using System.IO.Compression;
#endif
using KeePassLib.Interfaces;
using KeePassLib.Utility;
#if !KeePassLibSD
using System.IO.Compression;
#else
using ICSharpCode.SharpZipLib.GZip;
#endif
namespace KeePassLib.Translation
{
[XmlRoot("Translation")]
@ -92,18 +95,25 @@ namespace KeePassLib.Translation
}
}
public static void SaveToFile(KPTranslation kpTrl, string strFileName,
public static void Save(KPTranslation kpTrl, string strFileName,
IXmlSerializerEx xs)
{
using(FileStream fs = new FileStream(strFileName, FileMode.Create,
FileAccess.Write, FileShare.None))
{
Save(kpTrl, fs, xs);
}
}
public static void Save(KPTranslation kpTrl, Stream sOut,
IXmlSerializerEx xs)
{
if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
#if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Compress);
GZipStream gz = new GZipStream(sOut, CompressionMode.Compress);
#else
GZipOutputStream gz = new GZipOutputStream(fs);
GZipOutputStream gz = new GZipOutputStream(sOut);
#endif
XmlWriterSettings xws = new XmlWriterSettings();
@ -118,27 +128,36 @@ namespace KeePassLib.Translation
xw.Close();
gz.Close();
fs.Close();
sOut.Close();
}
public static KPTranslation LoadFromFile(string strFile,
IXmlSerializerEx xs)
public static KPTranslation Load(string strFile, IXmlSerializerEx xs)
{
KPTranslation kpTrl = null;
using(FileStream fs = new FileStream(strFile, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
kpTrl = Load(fs, xs);
}
return kpTrl;
}
public static KPTranslation Load(Stream s, IXmlSerializerEx xs)
{
if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFile, FileMode.Open,
FileAccess.Read, FileShare.Read);
#if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Decompress);
GZipStream gz = new GZipStream(s, CompressionMode.Decompress);
#else
GZipInputStream gz = new GZipInputStream(fs);
GZipInputStream gz = new GZipInputStream(s);
#endif
KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation);
gz.Close();
fs.Close();
s.Close();
return kpTrl;
}
@ -153,7 +172,7 @@ namespace KeePassLib.Translation
return new Dictionary<string, string>();
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
public void ApplyTo(Form form)
{
if(form == null) throw new ArgumentNullException("form");

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,9 +19,9 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassLibSD
using System.IO.Compression;
@ -38,8 +38,7 @@ namespace KeePassLib.Utility
public static void Open(string strPrefix)
{
return; // Logging is not enabled in normal builds of KeePass!
// Logging is not enabled in normal builds of KeePass!
/*
AppLogEx.Close();
@ -49,7 +48,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 +63,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);

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,28 +19,74 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassUAP
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
#endif
namespace KeePassLib.Utility
{
public static class GfxUtil
{
#if (!KeePassLibSD && !KeePassUAP)
private sealed class GfxImage
{
public byte[] Data;
public int Width;
public int Height;
public GfxImage(byte[] pbData, int w, int h)
{
this.Data = pbData;
this.Width = w;
this.Height = h;
}
#if DEBUG
// For debugger display
public override string ToString()
{
return (this.Width.ToString() + "x" + this.Height.ToString());
}
#endif
}
#endif
#if KeePassUAP
public static Image LoadImage(byte[] pb)
{
if(pb == null) throw new ArgumentNullException("pb");
MemoryStream ms = new MemoryStream(pb, false);
try { return LoadImagePriv(ms); }
catch(Exception)
try { return Image.FromStream(ms); }
finally { ms.Close(); }
}
#else
public static Image LoadImage(byte[] pb)
{
if(pb == null) throw new ArgumentNullException("pb");
#if !KeePassLibSD
// First try to load the data as ICO and afterwards as
// normal image, because trying to load an ICO using
// the normal image loading methods can result in a
// low resolution image
try
{
Image imgIco = TryLoadIco(pb);
Image imgIco = ExtractBestImageFromIco(pb);
if(imgIco != null) return imgIco;
throw;
}
catch(Exception) { Debug.Assert(false); }
#endif
MemoryStream ms = new MemoryStream(pb, false);
try { return LoadImagePriv(ms); }
finally { ms.Close(); }
}
@ -72,7 +118,12 @@ namespace KeePassLib.Utility
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
#if !KeePassLibSD
g.DrawImageUnscaled(imgSrc, 0, 0);
#else
g.DrawImage(imgSrc, 0, 0);
#endif
}
return bmp;
@ -80,16 +131,299 @@ namespace KeePassLib.Utility
finally { if(imgSrc != null) imgSrc.Dispose(); }
}
private static Image TryLoadIco(byte[] pb)
{
#if !KeePassLibSD
MemoryStream ms = new MemoryStream(pb, false);
try { return (new Icon(ms)).ToBitmap(); }
catch(Exception) { }
finally { ms.Close(); }
#endif
private static Image ExtractBestImageFromIco(byte[] pb)
{
List<GfxImage> l = UnpackIco(pb);
if((l == null) || (l.Count == 0)) return null;
return null;
long qMax = 0;
foreach(GfxImage gi in l)
{
if(gi.Width == 0) gi.Width = 256;
if(gi.Height == 0) gi.Height = 256;
qMax = Math.Max(qMax, (long)gi.Width * (long)gi.Height);
}
byte[] pbHdrPng = new byte[] {
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A
};
byte[] pbHdrJpeg = new byte[] { 0xFF, 0xD8, 0xFF };
Image imgBest = null;
int bppBest = -1;
foreach(GfxImage gi in l)
{
if(((long)gi.Width * (long)gi.Height) < qMax) continue;
byte[] pbImg = gi.Data;
Image img = null;
try
{
if((pbImg.Length > pbHdrPng.Length) &&
MemUtil.ArraysEqual(pbHdrPng,
MemUtil.Mid<byte>(pbImg, 0, pbHdrPng.Length)))
img = GfxUtil.LoadImage(pbImg);
else if((pbImg.Length > pbHdrJpeg.Length) &&
MemUtil.ArraysEqual(pbHdrJpeg,
MemUtil.Mid<byte>(pbImg, 0, pbHdrJpeg.Length)))
img = GfxUtil.LoadImage(pbImg);
else
{
MemoryStream ms = new MemoryStream(pb, false);
try
{
Icon ico = new Icon(ms, gi.Width, gi.Height);
img = ico.ToBitmap();
ico.Dispose();
}
finally { ms.Close(); }
}
}
catch(Exception) { Debug.Assert(false); }
if(img == null) continue;
if((img.Width < gi.Width) || (img.Height < gi.Height))
{
Debug.Assert(false);
img.Dispose();
continue;
}
int bpp = GetBitsPerPixel(img.PixelFormat);
if(bpp > bppBest)
{
if(imgBest != null) imgBest.Dispose();
imgBest = img;
bppBest = bpp;
}
else img.Dispose();
}
return imgBest;
}
private static List<GfxImage> UnpackIco(byte[] pb)
{
if(pb == null) { Debug.Assert(false); return null; }
const int SizeICONDIR = 6;
const int SizeICONDIRENTRY = 16;
Debug.Assert(BitConverter.ToInt32(new byte[] { 1, 2, 3, 4 },
0) == 0x04030201); // Little-endian
if(pb.Length < SizeICONDIR) return null;
if(BitConverter.ToUInt16(pb, 0) != 0) return null; // Reserved, 0
if(BitConverter.ToUInt16(pb, 2) != 1) return null; // ICO type, 1
int n = BitConverter.ToUInt16(pb, 4);
if(n < 0) { Debug.Assert(false); return null; }
int cbDir = SizeICONDIR + (n * SizeICONDIRENTRY);
if(pb.Length < cbDir) return null;
List<GfxImage> l = new List<GfxImage>();
int iOffset = SizeICONDIR;
for(int i = 0; i < n; ++i)
{
int w = pb[iOffset];
int h = pb[iOffset + 1];
if((w < 0) || (h < 0)) { Debug.Assert(false); return null; }
int cb = BitConverter.ToInt32(pb, iOffset + 8);
if(cb <= 0) return null; // Data must have header (even BMP)
int p = BitConverter.ToInt32(pb, iOffset + 12);
if(p < cbDir) return null;
if((p + cb) > pb.Length) return null;
try
{
byte[] pbImage = MemUtil.Mid<byte>(pb, p, cb);
GfxImage img = new GfxImage(pbImage, w, h);
l.Add(img);
}
catch(Exception) { Debug.Assert(false); return null; }
iOffset += SizeICONDIRENTRY;
}
return l;
}
private static int GetBitsPerPixel(PixelFormat f)
{
int bpp = 0;
switch(f)
{
case PixelFormat.Format1bppIndexed:
bpp = 1;
break;
case PixelFormat.Format4bppIndexed:
bpp = 4;
break;
case PixelFormat.Format8bppIndexed:
bpp = 8;
break;
case PixelFormat.Format16bppArgb1555:
case PixelFormat.Format16bppGrayScale:
case PixelFormat.Format16bppRgb555:
case PixelFormat.Format16bppRgb565:
bpp = 16;
break;
case PixelFormat.Format24bppRgb:
bpp = 24;
break;
case PixelFormat.Format32bppArgb:
case PixelFormat.Format32bppPArgb:
case PixelFormat.Format32bppRgb:
bpp = 32;
break;
case PixelFormat.Format48bppRgb:
bpp = 48;
break;
case PixelFormat.Format64bppArgb:
case PixelFormat.Format64bppPArgb:
bpp = 64;
break;
default:
Debug.Assert(false);
break;
}
return bpp;
}
public static Image ScaleImage(Image img, int w, int h)
{
return ScaleImage(img, w, h, ScaleTransformFlags.None);
}
/// <summary>
/// Resize an image.
/// </summary>
/// <param name="img">Image to resize.</param>
/// <param name="w">Width of the returned image.</param>
/// <param name="h">Height of the returned image.</param>
/// <param name="f">Flags to customize scaling behavior.</param>
/// <returns>Resized image. This object is always different
/// from <paramref name="img" /> (i.e. they can be
/// disposed separately).</returns>
public static Image ScaleImage(Image img, int w, int h,
ScaleTransformFlags f)
{
if(img == null) throw new ArgumentNullException("img");
if(w < 0) throw new ArgumentOutOfRangeException("w");
if(h < 0) throw new ArgumentOutOfRangeException("h");
bool bUIIcon = ((f & ScaleTransformFlags.UIIcon) !=
ScaleTransformFlags.None);
// We must return a Bitmap object for UIUtil.CreateScaledImage
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
g.SmoothingMode = SmoothingMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
int wSrc = img.Width;
int hSrc = img.Height;
InterpolationMode im = InterpolationMode.HighQualityBicubic;
if((wSrc > 0) && (hSrc > 0))
{
if(bUIIcon && ((w % wSrc) == 0) && ((h % hSrc) == 0))
im = InterpolationMode.NearestNeighbor;
// else if((w < wSrc) && (h < hSrc))
// im = InterpolationMode.HighQualityBilinear;
}
else { Debug.Assert(false); }
g.InterpolationMode = im;
RectangleF rSource = new RectangleF(0.0f, 0.0f, wSrc, hSrc);
RectangleF rDest = new RectangleF(0.0f, 0.0f, w, h);
AdjustScaleRects(ref rSource, ref rDest);
g.DrawImage(img, rDest, rSource, GraphicsUnit.Pixel);
}
return bmp;
}
internal static void AdjustScaleRects(ref RectangleF rSource,
ref RectangleF rDest)
{
// When enlarging images, apply a -0.5 offset to avoid
// the scaled image being cropped on the top/left side;
// when shrinking images, do not apply a -0.5 offset,
// otherwise the image is cropped on the bottom/right
// side; this applies to all interpolation modes
if(rDest.Width > rSource.Width)
rSource.X = rSource.X - 0.5f;
if(rDest.Height > rSource.Height)
rSource.Y = rSource.Y - 0.5f;
// When shrinking, apply a +0.5 offset, such that the
// scaled image is less cropped on the bottom/right side
if(rDest.Width < rSource.Width)
rSource.X = rSource.X + 0.5f;
if(rDest.Height < rSource.Height)
rSource.Y = rSource.Y + 0.5f;
}
#if DEBUG
public static Image ScaleTest(Image[] vIcons)
{
Bitmap bmp = new Bitmap(1024, vIcons.Length * (256 + 12),
PixelFormat.Format32bppArgb);
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
int[] v = new int[] { 16, 24, 32, 48, 64, 128, 256 };
int x;
int y = 8;
foreach(Image imgIcon in vIcons)
{
if(imgIcon == null) { Debug.Assert(false); continue; }
x = 128;
foreach(int q in v)
{
Image img = ScaleImage(imgIcon, q, q,
ScaleTransformFlags.UIIcon);
g.DrawImageUnscaled(img, x, y);
img.Dispose();
x += q + 8;
}
y += v[v.Length - 1] + 8;
}
}
return bmp;
}
#endif // DEBUG
#endif // !KeePassLibSD
#endif // KeePassUAP
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,15 +18,16 @@
*/
using System;
using System.Text;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
#if !KeePassLibSD
using System.IO.Compression;
#else
#if KeePassLibSD
using KeePassLibSD;
#else
using System.IO.Compression;
#endif
namespace KeePassLib.Utility
@ -36,6 +37,73 @@ namespace KeePassLib.Utility
/// </summary>
public static class MemUtil
{
private static readonly uint[] m_vSBox = new uint[256] {
0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,
0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4,
0x07CE9E5B, 0x31788A0C, 0xF683F6F4, 0xEA061F49,
0xFA5C2ACA, 0x4B9E494E, 0xB0AB25BA, 0x767731FC,
0x261893A7, 0x2B09F2CE, 0x046261E4, 0x41367B4B,
0x18A7F225, 0x8F923C0E, 0x5EF3A325, 0x28D0435E,
0x84C22919, 0xED66873C, 0x8CEDE444, 0x7FC47C24,
0xFCFC6BA3, 0x676F928D, 0xB4147187, 0xD8FB126E,
0x7D798D17, 0xFF82E424, 0x1712FA5B, 0xABB09DD5,
0x8156BA63, 0x84E4D969, 0xC937FB9A, 0x2F1E5BFC,
0x178ECA11, 0x0E71CD5F, 0x52AAC6F4, 0x71EEFC8F,
0x7090D749, 0x21CACA31, 0x92996378, 0x0939A8A8,
0xE9EE1934, 0xD2718616, 0xF2500543, 0xB911873C,
0xD3CB3EEC, 0x2BA0DBEB, 0xB42D0A27, 0xECE67C0F,
0x302925F0, 0x6114F839, 0xD39E6307, 0xE28970D6,
0xEB982F99, 0x941B4CDF, 0xC540E550, 0x8124FC45,
0x98B025C7, 0xE2BF90EA, 0x4F57C976, 0xCF546FE4,
0x59566DC8, 0xE3F4360D, 0xF5F9D231, 0xD6180B22,
0xB54E088A, 0xB5DFE6A6, 0x3637A36F, 0x056E9284,
0xAFF8FBC5, 0x19E01648, 0x8611F043, 0xDAE44337,
0xF61B6A1C, 0x257ACD9E, 0xDD35F507, 0xEF05CAFA,
0x05EB4A83, 0xFC25CA92, 0x0A4728E6, 0x9CF150EF,
0xAEEF67DE, 0xA9472337, 0x57C81EFE, 0x3E5E009F,
0x02CB03BB, 0x2BA85674, 0xF21DC251, 0x78C34A34,
0xABB1F5BF, 0xB95A2FBD, 0x1FB47777, 0x9A96E8AC,
0x5D2D2838, 0x55AAC92A, 0x99EE324E, 0x10F6214B,
0x58ABDFB1, 0x2008794D, 0xBEC880F0, 0xE75E5341,
0x88015C34, 0x352D8FBF, 0x622B7F6C, 0xF5C59EA2,
0x1F759D8E, 0xADE56159, 0xCC7B4C25, 0x5B8BC48C,
0xB6BD15AF, 0x3C5B5110, 0xE74A7C3D, 0xEE613161,
0x156A1C67, 0x72C06817, 0xEA0A6F69, 0x4CECF993,
0xCA9D554C, 0x8E20361F, 0x42D396B9, 0x595DE578,
0x749D7955, 0xFD1BA5FD, 0x81FC160E, 0xDB97E28C,
0x7CF148F7, 0x0B0B3CF5, 0x534DE605, 0x46421066,
0xD4B68DD1, 0x9E479CE6, 0xAE667A9D, 0xBC082082,
0xB06DD6EF, 0x20F0F23F, 0xB99E1551, 0xF47A2E3A,
0x71DA50C6, 0x67B65779, 0x2A8CB376, 0x1EA71EEE,
0x29ABCD50, 0xB6EB0C6B, 0x23C10511, 0x6F3F2144,
0x6AF23012, 0xF696BD9E, 0xB94099D8, 0xAD5A9C81,
0x7A0794FA, 0x7EDF59D6, 0x1E72E574, 0x8561913C,
0x4E4D568F, 0xEECB9928, 0x9C124D2E, 0x0848B82C,
0xF1CA395F, 0x9DAF43DC, 0xF77EC323, 0x394E9B59,
0x7E200946, 0x8B811D68, 0x16DA3305, 0xAB8DE2C3,
0xE6C53B64, 0x98C2D321, 0x88A97D81, 0xA7106419,
0x8E52F7BF, 0x8ED262AF, 0x7CCA974E, 0xF0933241,
0x040DD437, 0xE143B3D4, 0x3019F56F, 0xB741521D,
0xF1745362, 0x4C435F9F, 0xB4214D0D, 0x0B0C348B,
0x5051D189, 0x4C30447E, 0x7393D722, 0x95CEDD0B,
0xDD994E80, 0xC3D22ED9, 0x739CD900, 0x131EB9C4,
0xEF1062B2, 0x4F0DE436, 0x52920073, 0x9A7F3D80,
0x896E7B1B, 0x2C8BBE5A, 0xBD304F8A, 0xA993E22C,
0x134C41A0, 0xFA989E00, 0x39CE9726, 0xFB89FCCF,
0xE8FBAC97, 0xD4063FFC, 0x935A2B5A, 0x44C8EE83,
0xCB2BC7B6, 0x02989E92, 0x75478BEA, 0x144378D0,
0xD853C087, 0x8897A34E, 0xDD23629D, 0xBDE2A2A2,
0x581D8ECC, 0x5DA8AEE8, 0xFF8AAFD0, 0xBA2BCF6E,
0x4BD98DAC, 0xF2EDB9E4, 0xFA2DC868, 0x47E84661,
0xECEB1C7D, 0x41705CA4, 0x5982E4D4, 0xEB5204A1,
0xD196CAFB, 0x6414804D, 0x3ABD4B46, 0x8B494C26,
0xB432D52B, 0x39C5356B, 0x6EC80BF7, 0x71BE5483,
0xCEC4A509, 0xE9411D61, 0x52F341E5, 0xD2E6197B,
0x4F02826C, 0xA9E48838, 0xD1F8F247, 0xE4957FB3,
0x586CCA99, 0x9A8B6A5B, 0x4998FBEA, 0xF762BE4C,
0x90DFE33C, 0x9731511E, 0x88C6A82F, 0xDD65A4D4
};
/// <summary>
/// Convert a hexadecimal string to a byte array. The input string must be
/// even (i.e. its length is a multiple of 2).
@ -119,27 +187,84 @@ namespace KeePassLib.Utility
return sb.ToString();
}
/// <summary>
/// Decode Base32 strings according to RFC 4648.
/// </summary>
public static byte[] ParseBase32(string str)
{
if((str == null) || ((str.Length % 8) != 0))
{
Debug.Assert(false);
return null;
}
ulong uMaxBits = (ulong)str.Length * 5UL;
List<byte> l = new List<byte>((int)(uMaxBits / 8UL) + 1);
Debug.Assert(l.Count == 0);
for(int i = 0; i < str.Length; i += 8)
{
ulong u = 0;
int nBits = 0;
for(int j = 0; j < 8; ++j)
{
char ch = str[i + j];
if(ch == '=') break;
ulong uValue;
if((ch >= 'A') && (ch <= 'Z'))
uValue = (ulong)(ch - 'A');
else if((ch >= 'a') && (ch <= 'z'))
uValue = (ulong)(ch - 'a');
else if((ch >= '2') && (ch <= '7'))
uValue = (ulong)(ch - '2') + 26UL;
else { Debug.Assert(false); return null; }
u <<= 5;
u += uValue;
nBits += 5;
}
int nBitsTooMany = (nBits % 8);
u >>= nBitsTooMany;
nBits -= nBitsTooMany;
Debug.Assert((nBits % 8) == 0);
int idxNewBytes = l.Count;
while(nBits > 0)
{
l.Add((byte)(u & 0xFF));
u >>= 8;
nBits -= 8;
}
l.Reverse(idxNewBytes, l.Count - idxNewBytes);
}
return l.ToArray();
}
/// <summary>
/// Set all bytes in a byte array to zero.
/// </summary>
/// <param name="pbArray">Input array. All bytes of this array will be set
/// to zero.</param>
/// <param name="pbArray">Input array. All bytes of this array
/// will be set to zero.</param>
#if KeePassLibSD
[MethodImpl(MethodImplOptions.NoInlining)]
#else
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
#endif
public static void ZeroByteArray(byte[] pbArray)
{
Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray");
// for(int i = 0; i < pbArray.Length; ++i)
// pbArray[i] = 0;
Debug.Assert(pbArray != null);
if(pbArray == null) throw new ArgumentNullException("pbArray");
Array.Clear(pbArray, 0, pbArray.Length);
}
/// <summary>
/// Convert 2 bytes to a 16-bit unsigned integer using Little-Endian
/// encoding.
/// Convert 2 bytes to a 16-bit unsigned integer (little-endian).
/// </summary>
/// <param name="pb">Input bytes. Array must contain at least 2 bytes.</param>
/// <returns>16-bit unsigned integer.</returns>
public static ushort BytesToUInt16(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 2));
@ -150,44 +275,35 @@ namespace KeePassLib.Utility
}
/// <summary>
/// Convert 4 bytes to a 32-bit unsigned integer using Little-Endian
/// encoding.
/// Convert 4 bytes to a 32-bit unsigned integer (little-endian).
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>32-bit unsigned integer.</returns>
public static uint BytesToUInt32(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 4));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 4) throw new ArgumentException("Input array must contain 4 bytes!");
if(pb.Length != 4) throw new ArgumentException();
return (uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) |
((uint)pb[3] << 24);
return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) |
((uint)pb[3] << 24));
}
/// <summary>
/// Convert 8 bytes to a 64-bit unsigned integer using Little-Endian
/// encoding.
/// Convert 8 bytes to a 64-bit unsigned integer (little-endian).
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>64-bit unsigned integer.</returns>
public static ulong BytesToUInt64(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 8));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 8) throw new ArgumentException();
return (ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) |
return ((ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) |
((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) |
((ulong)pb[6] << 48) | ((ulong)pb[7] << 56);
((ulong)pb[6] << 48) | ((ulong)pb[7] << 56));
}
/// <summary>
/// Convert a 16-bit unsigned integer to 2 bytes using Little-Endian
/// encoding.
/// Convert a 16-bit unsigned integer to 2 bytes (little-endian).
/// </summary>
/// <param name="uValue">16-bit input word.</param>
/// <returns>Two bytes representing the 16-bit value.</returns>
public static byte[] UInt16ToBytes(ushort uValue)
{
byte[] pb = new byte[2];
@ -202,11 +318,8 @@ namespace KeePassLib.Utility
}
/// <summary>
/// Convert a 32-bit unsigned integer to 4 bytes using Little-Endian
/// encoding.
/// Convert a 32-bit unsigned integer to 4 bytes (little-endian).
/// </summary>
/// <param name="uValue">32-bit input word.</param>
/// <returns>Four bytes representing the 32-bit value.</returns>
public static byte[] UInt32ToBytes(uint uValue)
{
byte[] pb = new byte[4];
@ -223,11 +336,8 @@ namespace KeePassLib.Utility
}
/// <summary>
/// Convert a 64-bit unsigned integer to 8 bytes using Little-Endian
/// encoding.
/// Convert a 64-bit unsigned integer to 8 bytes (little-endian).
/// </summary>
/// <param name="uValue">64-bit input word.</param>
/// <returns>Eight bytes representing the 64-bit value.</returns>
public static byte[] UInt64ToBytes(ulong uValue)
{
byte[] pb = new byte[8];
@ -277,6 +387,31 @@ namespace KeePassLib.Utility
pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i];
}
/// <summary>
/// Fast hash that can be used e.g. for hash tables.
/// The algorithm might change in the future; do not store
/// the hashes for later use.
/// </summary>
public static uint Hash32(byte[] v, int iStart, int iLength)
{
uint u = 0x326F637B;
if(v == null) { Debug.Assert(false); return u; }
if(iStart < 0) { Debug.Assert(false); return u; }
if(iLength < 0) { Debug.Assert(false); return u; }
int m = iStart + iLength;
if(m > v.Length) { Debug.Assert(false); return u; }
for(int i = iStart; i < m; ++i)
{
u ^= m_vSBox[v[i]];
u *= 3;
}
return u;
}
public static void CopyStream(Stream sSource, Stream sTarget)
{
Debug.Assert((sSource != null) && (sTarget != null));
@ -336,15 +471,21 @@ namespace KeePassLib.Utility
if(pbData == null) throw new ArgumentNullException("pbData");
if(pbData.Length == 0) return pbData;
MemoryStream msCompressed = new MemoryStream();
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress);
MemoryStream msSource = new MemoryStream(pbData, false);
MemUtil.CopyStream(msSource, gz);
gz.Close();
msSource.Close();
byte[] pbCompressed;
using(MemoryStream msSource = new MemoryStream(pbData, false))
{
using(MemoryStream msCompressed = new MemoryStream())
{
using(GZipStream gz = new GZipStream(msCompressed,
CompressionMode.Compress))
{
MemUtil.CopyStream(msSource, gz);
}
pbCompressed = msCompressed.ToArray();
}
}
byte[] pbCompressed = msCompressed.ToArray();
msCompressed.Close();
return pbCompressed;
}
@ -353,15 +494,21 @@ namespace KeePassLib.Utility
if(pbCompressed == null) throw new ArgumentNullException("pbCompressed");
if(pbCompressed.Length == 0) return pbCompressed;
MemoryStream msCompressed = new MemoryStream(pbCompressed, false);
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress);
MemoryStream msData = new MemoryStream();
MemUtil.CopyStream(gz, msData);
gz.Close();
msCompressed.Close();
byte[] pbData;
using(MemoryStream msData = new MemoryStream())
{
using(MemoryStream msCompressed = new MemoryStream(pbCompressed, false))
{
using(GZipStream gz = new GZipStream(msCompressed,
CompressionMode.Decompress))
{
MemUtil.CopyStream(gz, msData);
}
}
pbData = msData.ToArray();
}
byte[] pbData = msData.ToArray();
msData.Close();
return pbData;
}
@ -394,11 +541,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<T> Union<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue; // Prevent duplicates
d[ta] = true;
yield return ta;
}
foreach(T tb in b)
{
if(d.ContainsKey(tb)) continue; // Prevent duplicates
d[tb] = true;
yield return tb;
}
yield break;
}
public static IEnumerable<T> Intersect<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.Remove(ta)) // Prevent duplicates
yield return ta;
}
yield break;
}
public static IEnumerable<T> Except<T>(IEnumerable<T> a, IEnumerable<T> b,
IEqualityComparer<T> cmp)
{
if(a == null) throw new ArgumentNullException("a");
if(b == null) throw new ArgumentNullException("b");
Dictionary<T, bool> d = ((cmp != null) ?
(new Dictionary<T, bool>(cmp)) : (new Dictionary<T, bool>()));
foreach(T tb in b) { d[tb] = true; }
foreach(T ta in a)
{
if(d.ContainsKey(ta)) continue;
d[ta] = true; // Prevent duplicates
yield return ta;
}
yield break;
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -20,9 +20,12 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Windows.Forms;
#endif
using KeePassLib.Resources;
using KeePassLib.Serialization;
@ -94,7 +97,9 @@ namespace KeePassLib.Utility
get { return m_uCurrentMessageCount; }
}
#if !KeePassUAP
public static event EventHandler<MessageServiceEventArgs> MessageShowing;
#endif
private static string ObjectsToMessage(object[] vLines)
{
@ -158,7 +163,7 @@ namespace KeePassLib.Utility
return sbText.ToString();
}
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
internal static Form GetTopForm()
{
FormCollection fc = Application.OpenForms;
@ -168,7 +173,8 @@ namespace KeePassLib.Utility
}
#endif
private static DialogResult SafeShowMessageBox(string strText, string strTitle,
#if !KeePassUAP
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{
#if KeePassLibSD
@ -283,11 +289,13 @@ namespace KeePassLib.Utility
try
{
#if !KeePassLibSD
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true));
string strDetails = ObjectsToMessage(vLines, true);
#if KeePassLibSD
Clipboard.SetDataObject(strDetails);
#else
Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
Clipboard.Clear();
Clipboard.SetText(strDetails);
#endif
}
catch(Exception) { Debug.Assert(false); }
@ -321,7 +329,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 +339,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)
@ -358,21 +372,7 @@ namespace KeePassLib.Utility
public static void ShowLoadWarning(string strFilePath, Exception ex,
bool bFullException)
{
string str = string.Empty;
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileLoadFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
{
str += MessageService.NewParagraph;
if(!bFullException) str += ex.Message;
else str += ObjectsToMessage(new object[] { ex }, true);
}
ShowWarning(str);
ShowWarning(GetLoadWarningMessage(strFilePath, ex, bFullException));
}
public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
@ -392,18 +392,7 @@ namespace KeePassLib.Utility
return;
}
string str = string.Empty;
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
str += MessageService.NewParagraph + ex.Message;
if(bCorruptionWarning)
str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
string str = GetSaveWarningMessage(strFilePath, ex, bCorruptionWarning);
ShowWarning(str);
}
@ -414,6 +403,45 @@ namespace KeePassLib.Utility
ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
else ShowWarning(ex);
}
#endif // !KeePassUAP
internal static string GetLoadWarningMessage(string strFilePath,
Exception ex, bool bFullException)
{
string str = string.Empty;
if(!string.IsNullOrEmpty(strFilePath))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileLoadFailed;
if((ex != null) && !string.IsNullOrEmpty(ex.Message))
{
str += MessageService.NewParagraph;
if(!bFullException) str += ex.Message;
else str += ObjectsToMessage(new object[] { ex }, true);
}
return str;
}
internal static string GetSaveWarningMessage(string strFilePath,
Exception ex, bool bCorruptionWarning)
{
string str = string.Empty;
if(!string.IsNullOrEmpty(strFilePath))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed;
if((ex != null) && !string.IsNullOrEmpty(ex.Message))
str += MessageService.NewParagraph + ex.Message;
if(bCorruptionWarning)
str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
return str;
}
public static void ExternalIncrementMessageCount()
{

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,16 +21,20 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography;
#endif
using KeePassLib.Collections;
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Native;
using KeePassLib.Security;
using KeePassLib.Resources;
namespace KeePassLib.Utility
{
@ -212,41 +216,47 @@ namespace KeePassLib.Utility
{
get
{
if(m_lEncs == null)
{
m_lEncs = new List<StrEncodingInfo>();
if(m_lEncs != null) return m_lEncs;
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Default,
#if !KeePassLibSD
Encoding.Default.EncodingName,
List<StrEncodingInfo> l = new List<StrEncodingInfo>();
l.Add(new StrEncodingInfo(StrEncodingType.Default,
#if KeePassUAP
"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF }));
#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
}
return m_lEncs;
l.Add(new StrEncodingInfo(StrEncodingType.Ascii,
"ASCII", Encoding.ASCII, 1, null));
l.Add(new StrEncodingInfo(StrEncodingType.Utf7,
"Unicode (UTF-7)", Encoding.UTF7, 1, null));
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
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
m_lEncs = l;
return l;
}
}
@ -274,16 +284,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) + "?");
}
/// <summary>
/// Convert a string into a valid HTML sequence representing that string.
/// </summary>
@ -300,7 +315,7 @@ namespace KeePassLib.Utility
str = str.Replace("\'", @"&#39;");
str = NormalizeNewLines(str, false);
str = str.Replace("\n", @"<br />");
str = str.Replace("\n", @"<br />" + MessageService.NewLine);
return str;
}
@ -343,9 +358,9 @@ namespace KeePassLib.Utility
}
/// <summary>
/// Split up a command-line into application and argument.
/// Split up a command line into application and argument.
/// </summary>
/// <param name="strCmdLine">Command-line to split.</param>
/// <param name="strCmdLine">Command line to split.</param>
/// <param name="strApp">Application path.</param>
/// <param name="strArgs">Arguments.</param>
public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs)
@ -482,8 +497,10 @@ namespace KeePassLib.Utility
if(excp.StackTrace != null)
strText += excp.StackTrace + MessageService.NewLine;
#if !KeePassLibSD
#if !KeePassUAP
if(excp.TargetSite != null)
strText += excp.TargetSite.ToString() + MessageService.NewLine;
#endif
if(excp.Data != null)
{
@ -506,8 +523,10 @@ namespace KeePassLib.Utility
if(excp.InnerException.StackTrace != null)
strText += excp.InnerException.StackTrace + MessageService.NewLine;
#if !KeePassLibSD
#if !KeePassUAP
if(excp.InnerException.TargetSite != null)
strText += excp.InnerException.TargetSite.ToString();
#endif
if(excp.InnerException.Data != null)
{
@ -538,7 +557,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 +585,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 +613,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 +641,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,25 +727,40 @@ 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();
}
private static Regex m_rxNaturalSplit = null;
/* private static Regex g_rxNaturalSplit = null;
public static int CompareNaturally(string strX, string strY)
{
Debug.Assert(strX != null);
@ -665,34 +771,31 @@ namespace KeePassLib.Utility
if(NativeMethods.SupportsStrCmpNaturally)
return NativeMethods.StrCmpNaturally(strX, strY);
strX = strX.ToLower(); // Case-insensitive comparison
strY = strY.ToLower();
if(g_rxNaturalSplit == null)
g_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled);
if(m_rxNaturalSplit == null)
m_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled);
string[] vPartsX = g_rxNaturalSplit.Split(strX);
string[] vPartsY = g_rxNaturalSplit.Split(strY);
string[] vPartsX = m_rxNaturalSplit.Split(strX);
string[] vPartsY = m_rxNaturalSplit.Split(strY);
for(int i = 0; i < Math.Min(vPartsX.Length, vPartsY.Length); ++i)
int n = Math.Min(vPartsX.Length, vPartsY.Length);
for(int i = 0; i < n; ++i)
{
string strPartX = vPartsX[i], strPartY = vPartsY[i];
int iPartCompare;
#if KeePassLibSD
ulong uX = 0, uY = 0;
try
{
uX = ulong.Parse(strPartX);
uY = ulong.Parse(strPartY);
ulong uX = ulong.Parse(strPartX);
ulong uY = ulong.Parse(strPartY);
iPartCompare = uX.CompareTo(uY);
}
catch(Exception) { iPartCompare = strPartX.CompareTo(strPartY); }
catch(Exception) { iPartCompare = string.Compare(strPartX, strPartY, true); }
#else
ulong uX, uY;
if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY))
iPartCompare = uX.CompareTo(uY);
else iPartCompare = strPartX.CompareTo(strPartY);
else iPartCompare = string.Compare(strPartX, strPartY, true);
#endif
if(iPartCompare != 0) return iPartCompare;
@ -701,6 +804,106 @@ namespace KeePassLib.Utility
if(vPartsX.Length == vPartsY.Length) return 0;
if(vPartsX.Length < vPartsY.Length) return -1;
return 1;
} */
public static int CompareNaturally(string strX, string strY)
{
Debug.Assert(strX != null);
if(strX == null) throw new ArgumentNullException("strX");
Debug.Assert(strY != null);
if(strY == null) throw new ArgumentNullException("strY");
if(NativeMethods.SupportsStrCmpNaturally)
return NativeMethods.StrCmpNaturally(strX, strY);
int cX = strX.Length;
int cY = strY.Length;
if(cX == 0) return ((cY == 0) ? 0 : -1);
if(cY == 0) return 1;
char chFirstX = strX[0];
char chFirstY = strY[0];
bool bExpNum = ((chFirstX >= '0') && (chFirstX <= '9'));
bool bExpNumY = ((chFirstY >= '0') && (chFirstY <= '9'));
if(bExpNum != bExpNumY) return string.Compare(strX, strY, true);
int pX = 0;
int pY = 0;
while((pX < cX) && (pY < cY))
{
Debug.Assert(((strX[pX] >= '0') && (strX[pX] <= '9')) == bExpNum);
Debug.Assert(((strY[pY] >= '0') && (strY[pY] <= '9')) == bExpNum);
int pExclX = pX + 1;
while(pExclX < cX)
{
char ch = strX[pExclX];
bool bChNum = ((ch >= '0') && (ch <= '9'));
if(bChNum != bExpNum) break;
++pExclX;
}
int pExclY = pY + 1;
while(pExclY < cY)
{
char ch = strY[pExclY];
bool bChNum = ((ch >= '0') && (ch <= '9'));
if(bChNum != bExpNum) break;
++pExclY;
}
string strPartX = strX.Substring(pX, pExclX - pX);
string strPartY = strY.Substring(pY, pExclY - pY);
bool bStrCmp = true;
if(bExpNum)
{
// 2^64 - 1 = 18446744073709551615 has length 20
if((strPartX.Length <= 19) && (strPartY.Length <= 19))
{
ulong uX, uY;
if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY))
{
if(uX < uY) return -1;
if(uX > uY) return 1;
bStrCmp = false;
}
else { Debug.Assert(false); }
}
else
{
double dX, dY;
if(double.TryParse(strPartX, out dX) && double.TryParse(strPartY, out dY))
{
if(dX < dY) return -1;
if(dX > dY) return 1;
bStrCmp = false;
}
else { Debug.Assert(false); }
}
}
if(bStrCmp)
{
int c = string.Compare(strPartX, strPartY, true);
if(c != 0) return c;
}
bExpNum = !bExpNum;
pX = pExclX;
pY = pExclY;
}
if(pX >= cX)
{
Debug.Assert(pX == cX);
if(pY >= cY) { Debug.Assert(pY == cY); return 0; }
return -1;
}
Debug.Assert(pY == cY);
return 1;
}
public static string RemoveAccelerator(string strMenuText)
@ -724,6 +927,54 @@ namespace KeePassLib.Utility
return str;
}
public static string AddAccelerator(string strMenuText,
List<char> lAvailKeys)
{
if(strMenuText == null) { Debug.Assert(false); return null; }
if(lAvailKeys == null) { Debug.Assert(false); return strMenuText; }
int xa = -1, xs = 0;
for(int i = 0; i < strMenuText.Length; ++i)
{
char ch = strMenuText[i];
#if KeePassLibSD
char chUpper = char.ToUpper(ch);
#else
char chUpper = char.ToUpperInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chUpper);
if(xa >= 0) { xs = i; break; }
#if KeePassLibSD
char chLower = char.ToLower(ch);
#else
char chLower = char.ToLowerInvariant(ch);
#endif
xa = lAvailKeys.IndexOf(chLower);
if(xa >= 0) { xs = i; break; }
}
if(xa < 0) return strMenuText;
lAvailKeys.RemoveAt(xa);
return strMenuText.Insert(xs, @"&");
}
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");
@ -872,6 +1123,36 @@ namespace KeePassLib.Utility
}
}
public static string GetNewLineSeq(string str)
{
if(str == null) { Debug.Assert(false); return MessageService.NewLine; }
int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0;
char chLast = char.MinValue;
for(int i = 0; i < n; ++i)
{
char ch = str[i];
if(ch == '\r') ++nCr;
else if(ch == '\n')
{
++nLf;
if(chLast == '\r') ++nCrLf;
}
chLast = ch;
}
nCr -= nCrLf;
nLf -= nCrLf;
int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf));
if(nMax == 0) return MessageService.NewLine;
if(nCrLf == nMax) return "\r\n";
return ((nLf == nMax) ? "\n" : "\r");
}
public static string AlphaNumericOnly(string str)
{
if(string.IsNullOrEmpty(str)) return str;
@ -949,37 +1230,44 @@ namespace KeePassLib.Utility
public static string VersionToString(ulong uVersion)
{
return VersionToString(uVersion, false);
return VersionToString(uVersion, 1U);
}
[Obsolete]
public static string VersionToString(ulong uVersion,
bool bEnsureAtLeastTwoComp)
{
string str = string.Empty;
bool bMultiComp = false;
return VersionToString(uVersion, (bEnsureAtLeastTwoComp ? 2U : 1U));
}
public static string VersionToString(ulong uVersion, uint uMinComp)
{
StringBuilder sb = new StringBuilder();
uint uComp = 0;
for(int i = 0; i < 4; ++i)
{
ushort us = (ushort)(uVersion & 0xFFFFUL);
if(uVersion == 0UL) break;
if((us != 0) || (str.Length > 0))
{
if(str.Length > 0)
{
str = "." + str;
bMultiComp = true;
}
ushort us = (ushort)(uVersion >> 48);
str = us.ToString() + str;
}
if(sb.Length > 0) sb.Append('.');
uVersion >>= 16;
sb.Append(us.ToString(NumberFormatInfo.InvariantInfo));
++uComp;
uVersion <<= 16;
}
if(bEnsureAtLeastTwoComp && !bMultiComp && (str.Length > 0))
str += ".0";
while(uComp < uMinComp)
{
if(sb.Length > 0) sb.Append('.');
return str;
sb.Append('0');
++uComp;
}
return sb.ToString();
}
private static readonly byte[] m_pbOptEnt = { 0xA5, 0x74, 0x2E, 0xEC };
@ -994,7 +1282,7 @@ namespace KeePassLib.Utility
byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt,
DataProtectionScope.CurrentUser);
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pbEnc);
@ -1030,7 +1318,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,14 +1335,14 @@ 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;
}
return v;
}
private static readonly char[] m_vTagSep = new char[]{ ',', ';', ':' };
private static readonly char[] m_vTagSep = new char[] { ',', ';', ':' };
public static string TagsToString(List<string> vTags, bool bForDisplay)
{
if(vTags == null) throw new ArgumentNullException("vTags");
@ -1107,7 +1395,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 && !KeePassUAP)
return Convert.ToBase64String(pb, Base64FormattingOptions.None);
#else
return Convert.ToBase64String(pb);
@ -1225,9 +1513,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;
}
/// <summary>
@ -1243,7 +1555,7 @@ namespace KeePassLib.Utility
if(strMimeType == null) strMimeType = "application/octet-stream";
#if !KeePassLibSD
#if (!KeePassLibSD && !KeePassUAP)
return ("data:" + strMimeType + ";base64," + Convert.ToBase64String(
pbData, Base64FormattingOptions.None));
#else
@ -1273,14 +1585,15 @@ namespace KeePassLib.Utility
if(bBase64) return Convert.FromBase64String(strData);
MemoryStream ms = new MemoryStream();
Encoding enc = Encoding.ASCII;
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 +1643,72 @@ namespace KeePassLib.Utility
return null;
}
private static string[] m_vPrefSepChars = null;
/// <summary>
/// Find a character that does not occur within a given text.
/// </summary>
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;
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,7 +18,12 @@
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using KeePassLib.Interfaces;
namespace KeePassLib.Utility
{
@ -33,6 +38,26 @@ namespace KeePassLib.Utility
/// </summary>
public const int PwTimeLength = 7;
#if !KeePassLibSD
private static string m_strDtfStd = null;
private static string m_strDtfDate = null;
#endif
private static DateTime? m_odtUnixRoot = null;
public static DateTime UnixRoot
{
get
{
if(m_odtUnixRoot.HasValue) return m_odtUnixRoot.Value;
DateTime dtRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0,
DateTimeKind.Utc)).ToLocalTime();
m_odtUnixRoot = dtRoot;
return dtRoot;
}
}
/// <summary>
/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits,
/// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6
@ -138,17 +163,118 @@ namespace KeePassLib.Utility
{
DateTime dt;
#if !KeePassLibSD
if(DateTime.TryParse(strDisplay, out dt)) return dt;
#else
#if KeePassLibSD
try { dt = DateTime.Parse(strDisplay); return dt; }
catch(Exception) { }
#else
if(DateTime.TryParse(strDisplay, out dt)) return dt;
// For some custom formats specified using the Control Panel,
// DateTime.ToString returns the correct string, but
// DateTime.TryParse fails (e.g. for "//dd/MMM/yyyy");
// https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae
if((m_strDtfStd == null) || (m_strDtfDate == null))
{
DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7);
m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni);
m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni);
}
const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces;
if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt))
return dt;
if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt))
return dt;
#endif
Debug.Assert(false);
return DateTime.Now;
}
#if !KeePassLibSD
private static string DeriveCustomFormat(string strDT, DateTime dt)
{
string[] vPlh = new string[] {
// Names, sorted by length
"MMMM", "dddd",
"MMM", "ddd",
"gg", "g",
// Numbers, the ones with prefix '0' first
"yyyy", "yyy", "yy", "y",
"MM", "M",
"dd", "d",
"HH", "hh", "H", "h",
"mm", "m",
"ss", "s",
"tt", "t"
};
List<string> lValues = new List<string>();
foreach(string strPlh in vPlh)
{
string strEval = strPlh;
if(strEval.Length == 1) strEval = @"%" + strPlh; // Make custom
lValues.Add(dt.ToString(strEval));
}
StringBuilder sbAll = new StringBuilder();
sbAll.Append("dfFghHKmMstyz:/\"\'\\%");
sbAll.Append(strDT);
foreach(string strVEnum in lValues) { sbAll.Append(strVEnum); }
List<char> lCodes = new List<char>();
for(int i = 0; i < vPlh.Length; ++i)
{
char ch = StrUtil.GetUnusedChar(sbAll.ToString());
lCodes.Add(ch);
sbAll.Append(ch);
}
string str = strDT;
for(int i = 0; i < vPlh.Length; ++i)
{
string strValue = lValues[i];
if(string.IsNullOrEmpty(strValue)) continue;
str = str.Replace(strValue, new string(lCodes[i], 1));
}
StringBuilder sbFmt = new StringBuilder();
bool bInLiteral = false;
foreach(char ch in str)
{
int iCode = lCodes.IndexOf(ch);
// The escape character doesn't work correctly (e.g.
// "dd\\.MM\\.yyyy\\ HH\\:mm\\:ss" doesn't work, but
// "dd'.'MM'.'yyyy' 'HH':'mm':'ss" does); use '' instead
// if(iCode >= 0) sbFmt.Append(vPlh[iCode]);
// else // Literal
// {
// sbFmt.Append('\\');
// sbFmt.Append(ch);
// }
if(iCode >= 0)
{
if(bInLiteral) { sbFmt.Append('\''); bInLiteral = false; }
sbFmt.Append(vPlh[iCode]);
}
else // Literal
{
if(!bInLiteral) { sbFmt.Append('\''); bInLiteral = true; }
sbFmt.Append(ch);
}
}
if(bInLiteral) sbFmt.Append('\'');
return sbFmt.ToString();
}
#endif
public static string SerializeUtc(DateTime dt)
{
string str = dt.ToUniversalTime().ToString("s");
@ -167,17 +293,14 @@ namespace KeePassLib.Utility
return bResult;
}
private static DateTime? m_dtUnixRoot = null;
public static double SerializeUnix(DateTime dt)
{
return (dt - TimeUtil.UnixRoot).TotalSeconds;
}
public static DateTime ConvertUnixTime(double dtUnix)
{
try
{
if(!m_dtUnixRoot.HasValue)
m_dtUnixRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0,
DateTimeKind.Utc)).ToLocalTime();
return m_dtUnixRoot.Value.AddSeconds(dtUnix);
}
try { return TimeUtil.UnixRoot.AddSeconds(dtUnix); }
catch(Exception) { Debug.Assert(false); }
return DateTime.Now;
@ -218,5 +341,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);
}
}
}

View File

@ -1,6 +1,6 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 Dominik Reichl <dominik.reichl@t-online.de>
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,10 +19,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Text;
using KeePassLib.Native;
@ -34,13 +33,21 @@ namespace KeePassLib.Utility
/// </summary>
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
{
get { return Path.DirectorySeparatorChar; }
}
/// <summary>
/// Get the directory (path) of a file name. The returned string is
/// Get the directory (path) of a file name. The returned string may be
/// terminated by a directory separator character. Example:
/// passing <c>C:\\My Documents\\My File.kdb</c> in <paramref name="strFile" />
/// and <c>true</c> to <paramref name="bAppendTerminatingChar"/>
/// would produce this string: <c>C:\\My Documents\\</c>.
/// </summary>
/// <param name="strFile">Full path of a file.</param>
@ -51,8 +58,7 @@ namespace KeePassLib.Utility
/// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />).
/// This should only be set to <c>true</c>, if the returned path is directly
/// passed to some directory API.</param>
/// <returns>Directory of the file. The return value is an empty string
/// (<c>""</c>) if the input parameter is <c>null</c>.</returns>
/// <returns>Directory of the file.</returns>
public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar,
bool bEnsureValidDirSpec)
{
@ -60,14 +66,15 @@ namespace KeePassLib.Utility
if(strFile == null) throw new ArgumentNullException("strFile");
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return strFile; // None
if(nLastSep < 0) return string.Empty; // No directory
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
(strFile[2] == '\\')) // Length >= 3 and Windows root directory
bAppendTerminatingChar = true;
if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), false);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep),
(strFile[nLastSep] == '/'));
}
/// <summary>
@ -148,7 +155,7 @@ namespace KeePassLib.Utility
}
if(bUrl) return (strPath + '/');
return (strPath + Path.DirectorySeparatorChar);
return (strPath + UrlUtil.LocalDirSepChar);
}
/* /// <summary>
@ -211,13 +218,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,7 +245,7 @@ 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;
}
@ -297,8 +313,10 @@ namespace KeePassLib.Utility
return strTargetFile;
}
#if (!KeePassLibSD && !KeePassUAP)
if(NativeLib.IsUnix())
{
#endif
bool bBaseUnc = IsUncPath(strBaseFile);
bool bTargetUnc = IsUncPath(strTargetFile);
if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc))
@ -316,21 +334,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 && !KeePassUAP)
}
#if KeePassLibSD
return strTargetFile;
#else
try // Windows
{
const int nMaxPath = NativeMethods.MAX_PATH * 2;
@ -344,7 +360,8 @@ namespace KeePassLib.Utility
return str;
}
catch(Exception) { Debug.Assert(false); return strTargetFile; }
catch(Exception) { Debug.Assert(false); }
return strTargetFile;
#endif
}
@ -476,7 +493,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,16 +611,97 @@ namespace KeePassLib.Utility
string strDir;
if(NativeLib.IsUnix())
strDir = NativeMethods.GetUserRuntimeDir();
#if KeePassUAP
else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
#else
else strDir = Path.GetTempPath();
#endif
try
{
if(Directory.Exists(strDir) == false)
Directory.CreateDirectory(strDir);
if(!Directory.Exists(strDir)) Directory.CreateDirectory(strDir);
}
catch(Exception) { Debug.Assert(false); }
return strDir;
}
#if !KeePassLibSD
// Structurally mostly equivalent to UrlUtil.GetFileInfos
public static List<string> GetFilePaths(string strDir, string strPattern,
SearchOption opt)
{
List<string> l = new List<string>();
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<FileInfo> GetFileInfos(DirectoryInfo di, string strPattern,
SearchOption opt)
{
List<FileInfo> l = new List<FileInfo>();
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
}
}