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 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 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 it under the terms of the GNU General Public License as published by
@ -194,13 +194,6 @@ namespace KeePassLib.Collections
return true; 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) public AutoTypeAssociation GetAt(int iIndex)
{ {
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
@ -209,6 +202,22 @@ namespace KeePassLib.Collections
return m_lWindowAssocs[iIndex]; 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) public void RemoveAt(int iIndex)
{ {
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
@ -216,5 +225,20 @@ namespace KeePassLib.Collections
m_lWindowAssocs.RemoveAt(iIndex); 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 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 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 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.Interfaces;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
#if KeePassLibSD #if KeePassLibSD
using KeePassLibSD; using KeePassLibSD;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -283,11 +283,7 @@ namespace KeePassLib.Collections
public List<string> GetKeys() public List<string> GetKeys()
{ {
List<string> v = new List<string>(); return new List<string>(m_vStrings.Keys);
foreach(string strKey in m_vStrings.Keys) v.Add(strKey);
return v;
} }
public void EnableProtection(string strField, bool bProtect) public void EnableProtection(string strField, bool bProtect)
@ -299,7 +295,8 @@ namespace KeePassLib.Collections
{ {
byte[] pbData = ps.ReadUtf8(); byte[] pbData = ps.ReadUtf8();
Set(strField, new ProtectedString(bProtect, pbData)); 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 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 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 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> /// <summary>
/// Get an object of the list. /// Get an object of the list.
/// </summary> /// </summary>
@ -225,7 +233,7 @@ namespace KeePassLib.Collections
if(nCount <= 1) return; if(nCount <= 1) return;
int nIndex = m_vObjects.IndexOf(tObject); 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 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> /// <summary>
/// Move some of the objects in this list to the top/bottom. /// Move some of the objects in this list to the top/bottom.
/// </summary> /// </summary>

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Diagnostics; using System.Diagnostics;
@ -33,8 +34,8 @@ namespace KeePassLib.Collections
{ {
public sealed class PwObjectPool public sealed class PwObjectPool
{ {
private SortedDictionary<PwUuidComparable, IStructureItem> m_dict = private SortedDictionary<PwUuid, IStructureItem> m_dict =
new SortedDictionary<PwUuidComparable, IStructureItem>(); new SortedDictionary<PwUuid, IStructureItem>();
public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries) public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries)
{ {
@ -42,16 +43,16 @@ namespace KeePassLib.Collections
PwObjectPool p = new PwObjectPool(); 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) GroupHandler gh = delegate(PwGroup pg)
{ {
p.m_dict[new PwUuidComparable(pg.Uuid)] = pg; p.m_dict[pg.Uuid] = pg;
return true; return true;
}; };
EntryHandler eh = delegate(PwEntry pe) EntryHandler eh = delegate(PwEntry pe)
{ {
p.m_dict[new PwUuidComparable(pe.Uuid)] = pe; p.m_dict[pe.Uuid] = pe;
return true; return true;
}; };
@ -63,13 +64,13 @@ namespace KeePassLib.Collections
public IStructureItem Get(PwUuid pwUuid) public IStructureItem Get(PwUuid pwUuid)
{ {
IStructureItem pItem; IStructureItem pItem;
m_dict.TryGetValue(new PwUuidComparable(pwUuid), out pItem); m_dict.TryGetValue(pwUuid, out pItem);
return pItem; return pItem;
} }
public bool ContainsOnlyType(Type t) 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; if(kvp.Value.GetType() != t) return false;
} }
@ -77,4 +78,154 @@ namespace KeePassLib.Collections
return true; 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 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 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 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 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 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 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.Text;
using System.IO; using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
namespace KeePassLib.Cryptography.Cipher namespace KeePassLib.Cryptography.Cipher
{ {
@ -70,7 +68,7 @@ namespace KeePassLib.Cryptography.Cipher
// Return if a cipher with that ID is registered already. // Return if a cipher with that ID is registered already.
for(int i = 0; i < m_vCiphers.Count; ++i) 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; return;
m_vCiphers.Add(csEngine); m_vCiphers.Add(csEngine);
@ -86,7 +84,7 @@ namespace KeePassLib.Cryptography.Cipher
{ {
foreach(ICipherEngine iEngine in m_vCiphers) foreach(ICipherEngine iEngine in m_vCiphers)
{ {
if(iEngine.CipherUuid.EqualsValue(uuidCipher)) if(iEngine.CipherUuid.Equals(uuidCipher))
return iEngine; return iEngine;
} }
@ -104,7 +102,7 @@ namespace KeePassLib.Cryptography.Cipher
{ {
for(int i = 0; i < m_vCiphers.Count; ++i) 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; return i;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -26,7 +26,7 @@ using KeePassLib.Utility;
namespace KeePassLib.Cryptography.Cipher namespace KeePassLib.Cryptography.Cipher
{ {
public sealed class Salsa20Cipher public sealed class Salsa20Cipher : IDisposable
{ {
private uint[] m_state = new uint[16]; private uint[] m_state = new uint[16];
private uint[] m_x = new uint[16]; // Working buffer 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 byte[] m_output = new byte[64];
private int m_outputPos = 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 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574
}; };
@ -45,6 +45,17 @@ namespace KeePassLib.Cryptography.Cipher
} }
~Salsa20Cipher() ~Salsa20Cipher()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool bDisposing)
{ {
// Clear sensitive data // Clear sensitive data
Array.Clear(m_state, 0, m_state.Length); Array.Clear(m_state, 0, m_state.Length);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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.Text;
using System.IO; using System.IO;
using System.Security; using System.Security;
using System.Security.Cryptography;
using System.Diagnostics; using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Resources; using KeePassLib.Resources;
namespace KeePassLib.Cryptography.Cipher namespace KeePassLib.Cryptography.Cipher
@ -34,8 +37,10 @@ namespace KeePassLib.Cryptography.Cipher
/// </summary> /// </summary>
public sealed class StandardAesEngine : ICipherEngine public sealed class StandardAesEngine : ICipherEngine
{ {
#if !KeePassUAP
private const CipherMode m_rCipherMode = CipherMode.CBC; private const CipherMode m_rCipherMode = CipherMode.CBC;
private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7; private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7;
#endif
private static PwUuid m_uuidAes = null; private static PwUuid m_uuidAes = null;
@ -48,11 +53,9 @@ namespace KeePassLib.Cryptography.Cipher
get get
{ {
if(m_uuidAes == null) if(m_uuidAes == null)
{
m_uuidAes = new PwUuid(new byte[]{ m_uuidAes = new PwUuid(new byte[]{
0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50, 0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50,
0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF }); 0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF });
}
return m_uuidAes; return m_uuidAes;
} }
@ -86,12 +89,12 @@ namespace KeePassLib.Cryptography.Cipher
if(bEncrypt) if(bEncrypt)
{ {
Debug.Assert(stream.CanWrite); 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 else // Decrypt
{ {
Debug.Assert(stream.CanRead); 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); 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 if(r.BlockSize != 128) // AES block size
{ {
Debug.Assert(false); Debug.Assert(false);
r.BlockSize = 128; r.BlockSize = 128;
} }
byte[] pbLocalIV = new byte[16];
Array.Copy(pbIV, pbLocalIV, 16);
r.IV = pbLocalIV; r.IV = pbLocalIV;
byte[] pbLocalKey = new byte[32];
Array.Copy(pbKey, pbLocalKey, 32);
r.KeySize = 256; r.KeySize = 256;
r.Key = pbLocalKey; r.Key = pbLocalKey;
r.Mode = m_rCipherMode; r.Mode = m_rCipherMode;
r.Padding = m_rCipherPadding; r.Padding = m_rCipherPadding;
@ -125,6 +130,7 @@ namespace KeePassLib.Cryptography.Cipher
return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write : return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write :
CryptoStreamMode.Read); CryptoStreamMode.Read);
#endif
} }
public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV) public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV)

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,12 +18,14 @@
*/ */
using System; using System;
using System.Security;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.Windows.Forms; using System.IO;
#if !KeePassUAP
using System.Drawing; using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
#endif
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -31,8 +33,8 @@ using KeePassLib.Utility;
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
/// <summary> /// <summary>
/// Cryptographically strong random number generator. The returned values /// Cryptographically strong random number generator. The returned
/// are unpredictable and cannot be reproduced. /// values are unpredictable and cannot be reproduced.
/// <c>CryptoRandom</c> is a singleton class. /// <c>CryptoRandom</c> is a singleton class.
/// </summary> /// </summary>
public sealed class CryptoRandom public sealed class CryptoRandom
@ -42,6 +44,7 @@ namespace KeePassLib.Cryptography
private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider(); private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider();
private ulong m_uGeneratedBytesCount = 0; private ulong m_uGeneratedBytesCount = 0;
private static object g_oSyncRoot = new object();
private object m_oSyncRoot = new object(); private object m_oSyncRoot = new object();
private static CryptoRandom m_pInstance = null; private static CryptoRandom m_pInstance = null;
@ -49,10 +52,18 @@ namespace KeePassLib.Cryptography
{ {
get 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 cr;
return m_pInstance;
} }
} }
@ -100,10 +111,10 @@ namespace KeePassLib.Cryptography
byte[] pbNewData = pbEntropy; byte[] pbNewData = pbEntropy;
if(pbEntropy.Length >= 64) if(pbEntropy.Length >= 64)
{ {
#if !KeePassLibSD #if KeePassLibSD
SHA512Managed shaNew = new SHA512Managed();
#else
SHA256Managed shaNew = new SHA256Managed(); SHA256Managed shaNew = new SHA256Managed();
#else
SHA512Managed shaNew = new SHA512Managed();
#endif #endif
pbNewData = shaNew.ComputeHash(pbEntropy); pbNewData = shaNew.ComputeHash(pbEntropy);
} }
@ -115,11 +126,11 @@ namespace KeePassLib.Cryptography
ms.Write(pbNewData, 0, pbNewData.Length); ms.Write(pbNewData, 0, pbNewData.Length);
byte[] pbFinal = ms.ToArray(); byte[] pbFinal = ms.ToArray();
#if !KeePassLibSD #if KeePassLibSD
SHA256Managed shaPool = new SHA256Managed();
#else
Debug.Assert(pbFinal.Length == (64 + pbNewData.Length)); Debug.Assert(pbFinal.Length == (64 + pbNewData.Length));
SHA512Managed shaPool = new SHA512Managed(); SHA512Managed shaPool = new SHA512Managed();
#else
SHA256Managed shaPool = new SHA256Managed();
#endif #endif
m_pbEntropyPool = shaPool.ComputeHash(pbFinal); m_pbEntropyPool = shaPool.ComputeHash(pbFinal);
} }
@ -138,11 +149,17 @@ namespace KeePassLib.Cryptography
ms.Write(pb, 0, pb.Length); ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD #if !KeePassLibSD
Point pt = Cursor.Position; // In try-catch for systems without GUI;
pb = MemUtil.UInt32ToBytes((uint)pt.X); // https://sourceforge.net/p/keepass/discussion/329221/thread/20335b73/
ms.Write(pb, 0, pb.Length); try
pb = MemUtil.UInt32ToBytes((uint)pt.Y); {
ms.Write(pb, 0, pb.Length); 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 #endif
pb = MemUtil.UInt32ToBytes((uint)rWeak.Next()); pb = MemUtil.UInt32ToBytes((uint)rWeak.Next());
@ -151,22 +168,35 @@ namespace KeePassLib.Cryptography
pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID());
ms.Write(pb, 0, pb.Length); ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD
try try
{ {
pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount); pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount);
ms.Write(pb, 0, pb.Length); 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); pb = MemUtil.UInt64ToBytes((ulong)Environment.WorkingSet);
ms.Write(pb, 0, pb.Length); ms.Write(pb, 0, pb.Length);
#endif
}
catch(Exception) { Debug.Assert(false); }
Version v = Environment.OSVersion.Version; #if KeePassUAP
int nv = (v.Major << 28) + (v.MajorRevision << 24) + pb = DiagnosticsExt.GetProcessEntropy();
(v.Minor << 20) + (v.MinorRevision << 16) + ms.Write(pb, 0, pb.Length);
(v.Revision << 12) + v.Build; #elif !KeePassLibSD
pb = MemUtil.UInt32ToBytes((uint)nv); Process p = null;
ms.Write(pb, 0, pb.Length); try
{
p = Process.GetCurrentProcess();
Process p = Process.GetCurrentProcess();
pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64()); pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64());
ms.Write(pb, 0, pb.Length); ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)p.HandleCount); pb = MemUtil.UInt32ToBytes((uint)p.HandleCount);
@ -198,7 +228,12 @@ namespace KeePassLib.Cryptography
// pb = MemUtil.UInt32ToBytes((uint)p.SessionId); // pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
// ms.Write(pb, 0, pb.Length); // 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 #endif
pb = Guid.NewGuid().ToByteArray(); pb = Guid.NewGuid().ToByteArray();
@ -266,7 +301,7 @@ namespace KeePassLib.Cryptography
long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32); long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32);
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy); Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy);
#else #else
Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy); Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,7 +19,10 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography.Cipher; using KeePassLib.Cryptography.Cipher;
@ -113,7 +116,7 @@ namespace KeePassLib.Cryptography
{ {
SHA256Managed sha256 = new SHA256Managed(); SHA256Managed sha256 = new SHA256Managed();
byte[] pbKey32 = sha256.ComputeHash(pbKey); 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 0x97, 0x20, 0x5D, 0x2A }; // Unique constant
m_salsa20 = new Salsa20Cipher(pbKey32, pbIV); m_salsa20 = new Salsa20Cipher(pbKey32, pbIV);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Utility; using KeePassLib.Utility;
@ -87,12 +90,9 @@ namespace KeePassLib.Cryptography
if(m_hash == null) { Debug.Assert(false); return; } if(m_hash == null) { Debug.Assert(false); return; }
// Validate hash algorithm // Validate hash algorithm
if((!m_hash.CanReuseTransform) || (!m_hash.CanTransformMultipleBlocks) || if(!m_hash.CanReuseTransform || !m_hash.CanTransformMultipleBlocks)
(m_hash.InputBlockSize != 1) || (m_hash.OutputBlockSize != 1))
{ {
#if DEBUG Debug.Assert(false);
MessageService.ShowWarning("Broken HashAlgorithm object in HashingStreamEx.");
#endif
m_hash = null; m_hash = null;
} }
} }
@ -102,8 +102,14 @@ namespace KeePassLib.Cryptography
m_sBaseStream.Flush(); m_sBaseStream.Flush();
} }
#if KeePassUAP
protected override void Dispose(bool disposing)
{
if(!disposing) return;
#else
public override void Close() public override void Close()
{ {
#endif
if(m_hash != null) if(m_hash != null)
{ {
try try

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.Text; using System.Text;
#if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
using KeePassLib.Utility; using KeePassLib.Utility;
@ -39,7 +43,7 @@ namespace KeePassLib.Cryptography
uint uCodeDigits, bool bAddChecksum, int iTruncationOffset) uint uCodeDigits, bool bAddChecksum, int iTruncationOffset)
{ {
byte[] pbText = MemUtil.UInt64ToBytes(uFactor); byte[] pbText = MemUtil.UInt64ToBytes(uFactor);
Array.Reverse(pbText); // Big-Endian Array.Reverse(pbText); // To big-endian
HMACSHA1 hsha1 = new HMACSHA1(pbSecret); HMACSHA1 hsha1 = new HMACSHA1(pbSecret);
byte[] pbHash = hsha1.ComputeHash(pbText); byte[] pbHash = hsha1.ComputeHash(pbText);
@ -58,7 +62,8 @@ namespace KeePassLib.Cryptography
uOtp = ((uOtp * 10) + CalculateChecksum(uOtp, uCodeDigits)); uOtp = ((uOtp * 10) + CalculateChecksum(uOtp, uCodeDigits));
uint uDigits = (bAddChecksum ? (uCodeDigits + 1) : 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, 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 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 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 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 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 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 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 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 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 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) foreach(CustomPwGenerator pwg in m_vGens)
{ {
if(uuid.EqualsValue(pwg.Uuid)) return pwg; if(uuid.Equals(pwg.Uuid)) return pwg;
} }
return null; return null;
@ -90,7 +90,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
for(int i = 0; i < m_vGens.Count; ++i) 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; return -1;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -67,6 +67,17 @@ namespace KeePassLib.Cryptography.PasswordGenerator
pcsUsed.Add(ch); 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 == '[') else if(ch == '[')
{ {
pcsCustom.Clear(); pcsCustom.Clear();

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 Invalid = "\t\r\n";
public const string LookAlike = @"O0l1I|"; public const string LookAlike = @"O0l1I|";
internal const string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
private const int CharTabSize = (0x10000 / 8); private const int CharTabSize = (0x10000 / 8);
private List<char> m_vChars = new List<char>(); private List<char> m_vChars = new List<char>();
private byte[] m_vTab = new byte[CharTabSize]; private byte[] m_vTab = new byte[CharTabSize];
private string m_strHighAnsi = string.Empty; private static string m_strHighAnsi = null;
private string m_strSpecial = string.Empty; 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> /// <summary>
/// Create a new, empty character set collection object. /// Create a new, empty character set collection object.
/// </summary> /// </summary>
public PwCharSet() public PwCharSet()
{ {
this.Initialize(true); Initialize(true);
} }
public PwCharSet(string strCharSet) public PwCharSet(string strCharSet)
{ {
this.Initialize(true); Initialize(true);
this.Add(strCharSet); Add(strCharSet);
} }
private PwCharSet(bool bFullInitialize) private PwCharSet(bool bFullInitialize)
{ {
this.Initialize(bFullInitialize); Initialize(bFullInitialize);
} }
private void Initialize(bool bFullInitialize) private void Initialize(bool bFullInitialize)
{ {
this.Clear(); Clear();
if(bFullInitialize == false) return; if(!bFullInitialize) return;
StringBuilder sbHighAnsi = new StringBuilder(); if(m_strHighAnsi == null)
for(char ch = '~'; ch < 255; ++ch) {
sbHighAnsi.Append(ch); StringBuilder sbHighAnsi = new StringBuilder();
m_strHighAnsi = sbHighAnsi.ToString(); // [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); m_strHighAnsi = sbHighAnsi.ToString();
pcs.AddRange('!', '/'); }
pcs.AddRange(':', '@');
pcs.AddRange('[', '`'); if(m_strSpecial == null)
pcs.Remove(@"-_ "); {
pcs.Remove(PwCharSet.Brackets); PwCharSet pcs = new PwCharSet(false);
m_strSpecial = pcs.ToString(); pcs.AddRange('!', '/');
pcs.AddRange(':', '@');
pcs.AddRange('[', '`');
pcs.Add(@"|~");
pcs.Remove(@"-_ ");
pcs.Remove(PwCharSet.Brackets);
m_strSpecial = pcs.ToString();
}
} }
/// <summary> /// <summary>
@ -118,9 +154,6 @@ namespace KeePassLib.Cryptography.PasswordGenerator
} }
} }
public string SpecialChars { get { return m_strSpecial; } }
public string HighAnsiChars { get { return m_strHighAnsi; } }
/// <summary> /// <summary>
/// Remove all characters from this set. /// Remove all characters from this set.
/// </summary> /// </summary>
@ -142,7 +175,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
foreach(char ch in strCharacters) foreach(char ch in strCharacters)
{ {
if(this.Contains(ch) == false) return false; if(!Contains(ch)) return false;
} }
return true; return true;
@ -156,7 +189,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
{ {
if(ch == char.MinValue) { Debug.Assert(false); return; } if(ch == char.MinValue) { Debug.Assert(false); return; }
if(this.Contains(ch) == false) if(!Contains(ch))
{ {
m_vChars.Add(ch); m_vChars.Add(ch);
m_vTab[ch / 8] |= (byte)(1 << (ch % 8)); m_vTab[ch / 8] |= (byte)(1 << (ch % 8));
@ -175,20 +208,20 @@ namespace KeePassLib.Cryptography.PasswordGenerator
m_vChars.Capacity = m_vChars.Count + strCharSet.Length; m_vChars.Capacity = m_vChars.Count + strCharSet.Length;
foreach(char ch in strCharSet) foreach(char ch in strCharSet)
this.Add(ch); Add(ch);
} }
public void Add(string strCharSet1, string strCharSet2) public void Add(string strCharSet1, string strCharSet2)
{ {
this.Add(strCharSet1); Add(strCharSet1);
this.Add(strCharSet2); Add(strCharSet2);
} }
public void Add(string strCharSet1, string strCharSet2, string strCharSet3) public void Add(string strCharSet1, string strCharSet2, string strCharSet3)
{ {
this.Add(strCharSet1); Add(strCharSet1);
this.Add(strCharSet2); Add(strCharSet2);
this.Add(strCharSet3); Add(strCharSet3);
} }
public void AddRange(char chMin, char chMax) public void AddRange(char chMin, char chMax)
@ -196,9 +229,9 @@ namespace KeePassLib.Cryptography.PasswordGenerator
m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1; m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1;
for(char ch = chMin; ch < chMax; ++ch) for(char ch = chMin; ch < chMax; ++ch)
this.Add(ch); Add(ch);
this.Add(chMax); Add(chMax);
} }
public bool AddCharSet(char chCharSetIdentifier) public bool AddCharSet(char chCharSetIdentifier)
@ -207,29 +240,29 @@ namespace KeePassLib.Cryptography.PasswordGenerator
switch(chCharSetIdentifier) switch(chCharSetIdentifier)
{ {
case 'a': this.Add(PwCharSet.LowerCase, PwCharSet.Digits); break; case 'a': Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
case 'A': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase, case 'A': Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
PwCharSet.Digits); break; PwCharSet.Digits); break;
case 'U': this.Add(PwCharSet.UpperCase, PwCharSet.Digits); break; case 'U': Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
case 'c': this.Add(PwCharSet.LowerConsonants); break; case 'c': Add(PwCharSet.LowerConsonants); break;
case 'C': this.Add(PwCharSet.LowerConsonants, case 'C': Add(PwCharSet.LowerConsonants,
PwCharSet.UpperConsonants); break; PwCharSet.UpperConsonants); break;
case 'z': this.Add(PwCharSet.UpperConsonants); break; case 'z': Add(PwCharSet.UpperConsonants); break;
case 'd': this.Add(PwCharSet.Digits); break; // Digit case 'd': Add(PwCharSet.Digits); break; // Digit
case 'h': this.Add(PwCharSet.LowerHex); break; case 'h': Add(PwCharSet.LowerHex); break;
case 'H': this.Add(PwCharSet.UpperHex); break; case 'H': Add(PwCharSet.UpperHex); break;
case 'l': this.Add(PwCharSet.LowerCase); break; case 'l': Add(PwCharSet.LowerCase); break;
case 'L': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break; case 'L': Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
case 'u': this.Add(PwCharSet.UpperCase); break; case 'u': Add(PwCharSet.UpperCase); break;
case 'p': this.Add(PwCharSet.Punctuation); break; case 'p': Add(PwCharSet.Punctuation); break;
case 'b': this.Add(PwCharSet.Brackets); break; case 'b': Add(PwCharSet.Brackets); break;
case 's': this.Add(PwCharSet.PrintableAsciiSpecial); break; case 's': Add(PwCharSet.PrintableAsciiSpecial); break;
case 'S': this.Add(PwCharSet.UpperCase, PwCharSet.LowerCase); case 'S': Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
this.Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break; Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
case 'v': this.Add(PwCharSet.LowerVowels); break; case 'v': Add(PwCharSet.LowerVowels); break;
case 'V': this.Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break; case 'V': Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
case 'Z': this.Add(PwCharSet.UpperVowels); break; case 'Z': Add(PwCharSet.UpperVowels); break;
case 'x': this.Add(m_strHighAnsi); break; case 'x': Add(m_strHighAnsi); break;
default: bResult = false; break; default: bResult = false; break;
} }
@ -238,7 +271,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
public bool Remove(char ch) 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); return m_vChars.Remove(ch);
} }
@ -261,10 +294,10 @@ namespace KeePassLib.Cryptography.PasswordGenerator
Debug.Assert(strCharacters != null); Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters"); if(strCharacters == null) throw new ArgumentNullException("strCharacters");
if(this.Contains(strCharacters) == false) if(!Contains(strCharacters))
return false; return false;
return this.Remove(strCharacters); return Remove(strCharacters);
} }
/// <summary> /// <summary>
@ -284,16 +317,16 @@ namespace KeePassLib.Cryptography.PasswordGenerator
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.Append(this.RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_'); sb.Append(RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_'); sb.Append(RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_'); sb.Append(RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
sb.Append(this.RemoveIfAllExist(m_strSpecial) ? 'S' : '_'); sb.Append(RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_'); sb.Append(RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
sb.Append(this.RemoveIfAllExist(@"-") ? 'm' : '_'); sb.Append(RemoveIfAllExist(@"-") ? 'm' : '_');
sb.Append(this.RemoveIfAllExist(@"_") ? 'u' : '_'); sb.Append(RemoveIfAllExist(@"_") ? 'u' : '_');
sb.Append(this.RemoveIfAllExist(@" ") ? 's' : '_'); sb.Append(RemoveIfAllExist(@" ") ? 's' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_'); sb.Append(RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
sb.Append(this.RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_'); sb.Append(RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_');
return sb.ToString(); return sb.ToString();
} }
@ -303,16 +336,16 @@ namespace KeePassLib.Cryptography.PasswordGenerator
if(strRanges == null) { Debug.Assert(false); return; } if(strRanges == null) { Debug.Assert(false); return; }
if(strRanges.Length < 10) { Debug.Assert(false); return; } if(strRanges.Length < 10) { Debug.Assert(false); return; }
if(strRanges[0] != '_') this.Add(PwCharSet.UpperCase); if(strRanges[0] != '_') Add(PwCharSet.UpperCase);
if(strRanges[1] != '_') this.Add(PwCharSet.LowerCase); if(strRanges[1] != '_') Add(PwCharSet.LowerCase);
if(strRanges[2] != '_') this.Add(PwCharSet.Digits); if(strRanges[2] != '_') Add(PwCharSet.Digits);
if(strRanges[3] != '_') this.Add(m_strSpecial); if(strRanges[3] != '_') Add(m_strSpecial);
if(strRanges[4] != '_') this.Add(PwCharSet.Punctuation); if(strRanges[4] != '_') Add(PwCharSet.Punctuation);
if(strRanges[5] != '_') this.Add('-'); if(strRanges[5] != '_') Add('-');
if(strRanges[6] != '_') this.Add('_'); if(strRanges[6] != '_') Add('_');
if(strRanges[7] != '_') this.Add(' '); if(strRanges[7] != '_') Add(' ');
if(strRanges[8] != '_') this.Add(PwCharSet.Brackets); if(strRanges[8] != '_') Add(PwCharSet.Brackets);
if(strRanges[9] != '_') this.Add(m_strHighAnsi); if(strRanges[9] != '_') Add(m_strHighAnsi);
} }
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 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); if((ch >= 'A') && (ch <= 'Z')) pcs.Add(PwCharSet.UpperCase);
else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase); else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase);
else if((ch >= '0') && (ch <= '9')) pcs.Add(PwCharSet.Digits); 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('-');
else if(ch == '_') pcs.Add('_'); else if(ch == '_') pcs.Add('_');
else if(ch == '\"') pcs.Add(pcs.SpecialChars); else if(PwCharSet.Brackets.IndexOf(ch) >= 0)
else if(ch == '\\') pcs.Add(pcs.SpecialChars); pcs.Add(PwCharSet.Brackets);
else if((@"()[]{}<>").IndexOf(ch) >= 0) pcs.Add(PwCharSet.Brackets); else if(PwCharSet.HighAnsiChars.IndexOf(ch) >= 0)
else if((ch >= '~') && (ch <= 255)) pcs.Add(pcs.HighAnsiChars); pcs.Add(PwCharSet.HighAnsiChars);
else pcs.Add(ch); else pcs.Add(ch);
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -20,521 +20,115 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Globalization;
using System.Diagnostics; using System.Diagnostics;
using KeePassLib.Utility; using KeePassLib.Utility;
#if !KeePassLibSD
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
/// <summary>
/// Bloom filter-based popular password checking.
/// </summary>
public static class PopularPasswords 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 internal static int MaxLength
// Hash functions: 32 {
// Phi (bits unset ratio) estimation: 0.505455388896019 get
// Exact Phi: 0.505111694335938 {
// False positives ratio: 1.67583063859565E-10 Debug.Assert(m_dicts.Count > 0); // Should be initialized
private static readonly ulong[] PpcTable = {
0x60383D3A85560B9BUL, 0x2578CE9D37C6AEB7UL, 0xF509A5743FD03228UL, int iMaxLen = 0;
0x19B7455E8933EE56UL, 0x5EA419ADCFD9C20EUL, 0xEA618EFC0B37A162UL, foreach(int iLen in m_dicts.Keys)
0xE0FD4D1FFF1CE415UL, 0x7A649E0301BB6060UL, 0x80D9CD9F9EEB603DUL, {
0x47D6010D0D6E6CDEUL, 0x2552708C589EB554UL, 0x073F1A3DB3267502UL, if(iLen > iMaxLen) iMaxLen = iLen;
0x3313FEC2A2FEA475UL, 0x4593665C44934FEBUL, 0x410A301A23660395UL, }
0x6AD06DA533FF5659UL, 0x423DAF86F3E41F4AUL, 0x82F035A971C6FD18UL,
0xB5E9139F28C93223UL, 0x1D07C3F4160585CAUL, 0x24B01EDB6B23E2C5UL, return iMaxLen;
0xD52F25B724F936C9UL, 0x8018392517836928UL, 0x3AA4C0F8E181EDA2UL, }
0x8D93683EF7D52529UL, 0x6164BB6208114460UL, 0x737A04D8FEF3D88FUL, }
0x3400097098D5C2CBUL, 0x3C2B9ABE5C455B2EUL, 0x3A3819973AB32DA2UL,
0x38ACB428510AF40BUL, 0x83320D5114B74771UL, 0xC25BEC333B90DCD1UL, internal static bool ContainsLength(int nLength)
0x0E9F412FBA3813D1UL, 0x047E31E3098EB2B8UL, 0xBB686AC643F1741FUL, {
0x0BE22E9C0EF0E8F2UL, 0x65AA9504E5F40D31UL, 0xE018DF5D64C62AC7UL, Dictionary<string, bool> dDummy;
0x17020E9A7EFA12EDUL, 0xFC12A7C16006DE82UL, 0x8DE4747E3745346DUL, return m_dicts.TryGetValue(nLength, out dDummy);
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
};
public static bool IsPopularPassword(char[] vPassword) 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 == 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); public static void Add(byte[] pbData, bool bGZipped)
Array.Clear(pbUtf8, 0, pbUtf8.Length); {
try
foreach(int iIndex in vIndices)
{ {
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) if(!char.IsWhiteSpace(strData[strData.Length - 1]))
{ strData += "\n";
return (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) ||
((ch >= '0') && (ch <= '9')) || (ch == '_') || (ch == '!'));
}
private static int[] GetTableIndices(byte[] pbPasswordUtf8, int nTableSize) StringBuilder sb = new StringBuilder();
{ for(int i = 0; i < strData.Length; ++i)
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))
{ {
string strPassword = sbPassword.ToString(); char ch = strData[i];
strPassword = strPassword.ToLower();
if(strPassword.Length > 3) if(char.IsWhiteSpace(ch))
{ {
if(vPasswords.IndexOf(strPassword) < 0) int cc = sb.Length;
vPasswords.Add(strPassword); 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);
}
} }
else sb.Append(char.ToLower(ch));
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);
} }
} }
catch(Exception) { Debug.Assert(false); }
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());
} }
#endif
} }
} }
#endif

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,9 +19,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Diagnostics;
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
@ -32,13 +33,286 @@ namespace KeePassLib.Cryptography
/// </summary> /// </summary>
public static class QualityEstimation public static class QualityEstimation
{ {
private enum CharSpaceBits : uint private static class PatternID
{ {
Control = 32, public const char LowerAlpha = 'L';
Alpha = 26, public const char UpperAlpha = 'U';
Number = 10, public const char Digit = 'D';
Special = 33, public const char Special = 'S';
High = 112 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> /// <summary>
@ -46,84 +320,95 @@ namespace KeePassLib.Cryptography
/// </summary> /// </summary>
/// <param name="vPasswordChars">Password to check.</param> /// <param name="vPasswordChars">Password to check.</param>
/// <returns>Estimated bit-strength of the password.</returns> /// <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) public static uint EstimatePasswordBits(char[] vPasswordChars)
{ {
Debug.Assert(vPasswordChars != null); if(vPasswordChars == null) { Debug.Assert(false); return 0; }
if(vPasswordChars == null) throw new ArgumentNullException("vPasswordChars"); if(vPasswordChars.Length == 0) return 0;
bool bChLower = false, bChUpper = false, bChNumber = false; EnsureInitialized();
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;
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; QePatternInstance piChar = new QePatternInstance(i, 1,
else if((tch >= 'A') && (tch <= 'Z')) bChUpper = true; GetCharType(vPasswordChars[i]));
else if((tch >= 'a') && (tch <= 'z')) bChLower = true; vPatterns[i].Add(piChar);
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;
double dblDiffFactor = 1.0; FindRepetitions(vPasswordChars, vPatterns);
if(i >= 1) 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; double dblCost = ComputePathCost(s.Path, vPasswordChars,
if(vDifferences.TryGetValue(iDiff, out uDiffCount)) ecPattern, mcData);
{ if(dblCost < dblMinCost) dblMinCost = dblCost;
++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);
} }
else else
{ {
vCharCounts.Add(tch, 1); List<QePatternInstance> lSubs = vPatterns[s.Position];
dblEffectiveLength += dblDiffFactor; 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; return (uint)Math.Ceiling(dblMinCost);
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);
} }
/// <summary> /// <summary>
@ -141,5 +426,343 @@ namespace KeePassLib.Cryptography
return uResult; 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 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 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 it under the terms of the GNU General Public License as published by
@ -20,21 +20,32 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Security; using System.Security;
using System.Security.Cryptography;
using System.Text; 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.Cryptography.Cipher;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Utility;
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
#if (KeePassUAP && KeePassLibSD)
#error KeePassUAP and KeePassLibSD are mutually exclusive.
#endif
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
/* #pragma warning disable 1591 /* /// <summary>
/// <summary>
/// Return values of the <c>SelfTest.Perform</c> method. /// Return values of the <c>SelfTest.Perform</c> method.
/// </summary> /// </summary>
public enum SelfTestResult public enum SelfTestResult
@ -43,8 +54,7 @@ namespace KeePassLib.Cryptography
RijndaelEcbError = 1, RijndaelEcbError = 1,
Salsa20Error = 2, Salsa20Error = 2,
NativeKeyTransformationError = 3 NativeKeyTransformationError = 3
} } */
#pragma warning restore 1591 */
/// <summary> /// <summary>
/// Class containing self-test methods. /// Class containing self-test methods.
@ -73,15 +83,21 @@ namespace KeePassLib.Cryptography
Debug.Assert((int)PwIcon.World == 1); Debug.Assert((int)PwIcon.World == 1);
Debug.Assert((int)PwIcon.Warning == 2); Debug.Assert((int)PwIcon.Warning == 2);
Debug.Assert((int)PwIcon.BlackBerry == 68); Debug.Assert((int)PwIcon.BlackBerry == 68);
#if KeePassUAP
SelfTestEx.Perform();
#endif
} }
internal static void TestFipsComplianceProblems() internal static void TestFipsComplianceProblems()
{ {
#if !KeePassUAP
try { new RijndaelManaged(); } try { new RijndaelManaged(); }
catch(Exception exAes) catch(Exception exAes)
{ {
throw new SecurityException("AES/Rijndael: " + exAes.Message); throw new SecurityException("AES/Rijndael: " + exAes.Message);
} }
#endif
try { new SHA256Managed(); } try { new SHA256Managed(); }
catch(Exception exSha256) catch(Exception exSha256)
@ -106,6 +122,13 @@ namespace KeePassLib.Cryptography
for(i = 0; i < 16; ++i) pbTestData[i] = 0; for(i = 0; i < 16; ++i) pbTestData[i] = 0;
pbTestData[0] = 0x04; 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(); RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size if(r.BlockSize != 128) // AES block size
@ -121,6 +144,7 @@ namespace KeePassLib.Cryptography
ICryptoTransform iCrypt = r.CreateEncryptor(); ICryptoTransform iCrypt = r.CreateEncryptor();
iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0); iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0);
#endif
if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT)) if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
throw new SecurityException(KLRes.EncAlgorithmAes + "."); throw new SecurityException(KLRes.EncAlgorithmAes + ".");
@ -146,7 +170,7 @@ namespace KeePassLib.Cryptography
Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV); Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV);
c.Encrypt(pb, pb.Length, false); c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected)) if(!MemUtil.ArraysEqual(pb, pbExpected))
throw new SecurityException("Salsa20."); throw new SecurityException("Salsa20-1");
#if DEBUG #if DEBUG
// Extended test in debug mode // Extended test in debug mode
@ -163,13 +187,24 @@ namespace KeePassLib.Cryptography
int nPos = Salsa20ToPos(c, r, pb.Length, 65536); int nPos = Salsa20ToPos(c, r, pb.Length, 65536);
c.Encrypt(pb, pb.Length, false); c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected2)) if(!MemUtil.ArraysEqual(pb, pbExpected2))
throw new SecurityException("Salsa20-2."); throw new SecurityException("Salsa20-2");
nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008); nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008);
Array.Clear(pb, 0, pb.Length); Array.Clear(pb, 0, pb.Length);
c.Encrypt(pb, pb.Length, true); c.Encrypt(pb, pb.Length, true);
if(!MemUtil.ArraysEqual(pb, pbExpected3)) 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 #endif
} }
@ -200,12 +235,12 @@ namespace KeePassLib.Cryptography
byte[] pbManaged = new byte[32]; byte[] pbManaged = new byte[32];
Array.Copy(pbOrgKey, pbManaged, 32); Array.Copy(pbOrgKey, pbManaged, 32);
if(CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds) == false) if(!CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds))
throw new SecurityException("Managed transform."); throw new SecurityException("Managed transform.");
byte[] pbNative = new byte[32]; byte[] pbNative = new byte[32];
Array.Copy(pbOrgKey, pbNative, 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") return; // Native library not available ("success")
if(!MemUtil.ArraysEqual(pbManaged, pbNative)) if(!MemUtil.ArraysEqual(pbManaged, pbNative))
@ -224,35 +259,64 @@ namespace KeePassLib.Cryptography
if(!MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), pb)) if(!MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), pb))
throw new InvalidOperationException("GZip"); throw new InvalidOperationException("GZip");
pb = Encoding.ASCII.GetBytes("012345678901234567890a"); Encoding enc = StrUtil.Utf8;
byte[] pbN = Encoding.ASCII.GetBytes("9012"); pb = enc.GetBytes("012345678901234567890a");
byte[] pbN = enc.GetBytes("9012");
if(MemUtil.IndexOf<byte>(pb, pbN) != 9) if(MemUtil.IndexOf<byte>(pb, pbN) != 9)
throw new InvalidOperationException("MemUtil-1"); throw new InvalidOperationException("MemUtil-1");
pbN = Encoding.ASCII.GetBytes("01234567890123"); pbN = enc.GetBytes("01234567890123");
if(MemUtil.IndexOf<byte>(pb, pbN) != 0) if(MemUtil.IndexOf<byte>(pb, pbN) != 0)
throw new InvalidOperationException("MemUtil-2"); throw new InvalidOperationException("MemUtil-2");
pbN = Encoding.ASCII.GetBytes("a"); pbN = enc.GetBytes("a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 21) if(MemUtil.IndexOf<byte>(pb, pbN) != 21)
throw new InvalidOperationException("MemUtil-3"); throw new InvalidOperationException("MemUtil-3");
pbN = Encoding.ASCII.GetBytes("0a"); pbN = enc.GetBytes("0a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 20) if(MemUtil.IndexOf<byte>(pb, pbN) != 20)
throw new InvalidOperationException("MemUtil-4"); throw new InvalidOperationException("MemUtil-4");
pbN = Encoding.ASCII.GetBytes("1"); pbN = enc.GetBytes("1");
if(MemUtil.IndexOf<byte>(pb, pbN) != 1) if(MemUtil.IndexOf<byte>(pb, pbN) != 1)
throw new InvalidOperationException("MemUtil-5"); throw new InvalidOperationException("MemUtil-5");
pbN = Encoding.ASCII.GetBytes("b"); pbN = enc.GetBytes("b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0) if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-6"); throw new InvalidOperationException("MemUtil-6");
pbN = Encoding.ASCII.GetBytes("012b"); pbN = enc.GetBytes("012b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0) if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-7"); 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 #endif
} }
private static void TestHmacOtp() private static void TestHmacOtp()
{ {
#if (DEBUG && !KeePassLibSD) #if (DEBUG && !KeePassLibSD)
byte[] pbSecret = Encoding.ASCII.GetBytes("12345678901234567890"); byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890");
string[] vExp = new string[]{ "755224", "287082", "359152", string[] vExp = new string[]{ "755224", "287082", "359152",
"969429", "338314", "254676", "287922", "162583", "399871", "969429", "338314", "254676", "287922", "162583", "399871",
"520489" }; "520489" };
@ -268,7 +332,9 @@ namespace KeePassLib.Cryptography
private static void TestProtectedObjects() private static void TestProtectedObjects()
{ {
#if DEBUG #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); ProtectedBinary pb = new ProtectedBinary(true, pbData);
if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-1"); if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-1");
@ -277,8 +343,8 @@ namespace KeePassLib.Cryptography
throw new SecurityException("ProtectedBinary-2"); throw new SecurityException("ProtectedBinary-2");
if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-3"); if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-3");
byte[] pbData2 = Encoding.ASCII.GetBytes("Test Test Test Test"); byte[] pbData2 = enc.GetBytes("Test Test Test Test");
byte[] pbData3 = Encoding.ASCII.GetBytes("Test Test Test Test Test"); byte[] pbData3 = enc.GetBytes("Test Test Test Test Test");
ProtectedBinary pb2 = new ProtectedBinary(true, pbData2); ProtectedBinary pb2 = new ProtectedBinary(true, pbData2);
ProtectedBinary pb3 = new ProtectedBinary(true, pbData3); ProtectedBinary pb3 = new ProtectedBinary(true, pbData3);
if(!pb.Equals(pb2)) throw new SecurityException("ProtectedBinary-4"); if(!pb.Equals(pb2)) throw new SecurityException("ProtectedBinary-4");
@ -301,8 +367,7 @@ namespace KeePassLib.Cryptography
throw new SecurityException("ProtectedString-3"); throw new SecurityException("ProtectedString-3");
ps = new ProtectedString(true, "Test"); ps = new ProtectedString(true, "Test");
ProtectedString ps2 = new ProtectedString(true, ProtectedString ps2 = new ProtectedString(true, enc.GetBytes("Test"));
StrUtil.Utf8.GetBytes("Test"));
if(ps.IsEmpty) throw new SecurityException("ProtectedString-4"); if(ps.IsEmpty) throw new SecurityException("ProtectedString-4");
pbData = ps.ReadUtf8(); pbData = ps.ReadUtf8();
pbData2 = ps2.ReadUtf8(); pbData2 = ps2.ReadUtf8();
@ -318,6 +383,41 @@ namespace KeePassLib.Cryptography
throw new SecurityException("ProtectedString-8"); throw new SecurityException("ProtectedString-8");
if(!ps.IsProtected) throw new SecurityException("ProtectedString-9"); if(!ps.IsProtected) throw new SecurityException("ProtectedString-9");
if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10"); 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 #endif
} }
@ -358,16 +458,74 @@ namespace KeePassLib.Cryptography
throw new InvalidOperationException("StrUtil-V3"); throw new InvalidOperationException("StrUtil-V3");
if(StrUtil.VersionToString(0x00FF000000000000UL) != "255") if(StrUtil.VersionToString(0x00FF000000000000UL) != "255")
throw new InvalidOperationException("StrUtil-V4"); throw new InvalidOperationException("StrUtil-V4");
if(StrUtil.VersionToString(0x00FF000000000000UL, true) != "255.0") if(StrUtil.VersionToString(0x00FF000000000000UL, 2) != "255.0")
throw new InvalidOperationException("StrUtil-V5"); 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"); 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 #endif
} }
private static void TestUrlUtil() private static void TestUrlUtil()
{ {
#if DEBUG #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") != if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") !=
"domain") "domain")
throw new InvalidOperationException("UrlUtil-H1"); throw new InvalidOperationException("UrlUtil-H1");
@ -396,6 +554,13 @@ namespace KeePassLib.Cryptography
str = UrlUtil.MakeAbsolutePath(strBase, strRel); str = UrlUtil.MakeAbsolutePath(strBase, strRel);
if(!str.Equals(strDoc)) throw new InvalidOperationException("UrlUtil-R2"); 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 #endif
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 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 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 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 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -39,18 +39,18 @@ namespace KeePassLib.Interfaces
} }
/// <summary> /// <summary>
/// The date/time when the object was last accessed. /// The date/time when the object was last modified.
/// </summary> /// </summary>
DateTime LastAccessTime DateTime LastModificationTime
{ {
get; get;
set; set;
} }
/// <summary> /// <summary>
/// The date/time when the object was last modified. /// The date/time when the object was last accessed.
/// </summary> /// </summary>
DateTime LastModificationTime DateTime LastAccessTime
{ {
get; get;
set; set;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -18,11 +18,17 @@
*/ */
using System; using System;
using System.Text;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; 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; using System.Security.Cryptography;
#endif
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Resources; using KeePassLib.Resources;
@ -118,8 +124,15 @@ namespace KeePassLib.Keys
foreach(IUserKey pKey in m_vUserKeys) 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)) if(tUserKeyType.IsInstanceOfType(pKey))
return true; return true;
#endif
} }
return false; return false;
@ -138,8 +151,15 @@ namespace KeePassLib.Keys
foreach(IUserKey pKey in m_vUserKeys) 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)) if(tUserKeyType.IsInstanceOfType(pKey))
return pKey; return pKey;
#endif
} }
return null; return null;
@ -154,21 +174,32 @@ namespace KeePassLib.Keys
ValidateUserKeys(); ValidateUserKeys();
// Concatenate user key data // Concatenate user key data
MemoryStream ms = new MemoryStream(); List<byte[]> lData = new List<byte[]>();
int cbData = 0;
foreach(IUserKey pKey in m_vUserKeys) foreach(IUserKey pKey in m_vUserKeys)
{ {
ProtectedBinary b = pKey.KeyData; ProtectedBinary b = pKey.KeyData;
if(b != null) if(b != null)
{ {
byte[] pbKeyData = b.ReadData(); byte[] pbKeyData = b.ReadData();
ms.Write(pbKeyData, 0, pbKeyData.Length); lData.Add(pbKeyData);
MemUtil.ZeroByteArray(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(); SHA256Managed sha256 = new SHA256Managed();
byte[] pbHash = sha256.ComputeHash(ms.ToArray()); byte[] pbHash = sha256.ComputeHash(pbAllData);
ms.Close(); MemUtil.ZeroByteArray(pbAllData);
return pbHash; return pbHash;
} }
@ -179,8 +210,8 @@ namespace KeePassLib.Keys
byte[] pbThis = CreateRawCompositeKey32(); byte[] pbThis = CreateRawCompositeKey32();
byte[] pbOther = ckOther.CreateRawCompositeKey32(); byte[] pbOther = ckOther.CreateRawCompositeKey32();
bool bResult = MemUtil.ArraysEqual(pbThis, pbOther); bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
Array.Clear(pbOther, 0, pbOther.Length); MemUtil.ZeroByteArray(pbOther);
Array.Clear(pbThis, 0, pbThis.Length); MemUtil.ZeroByteArray(pbThis);
return bResult; return bResult;
} }
@ -256,20 +287,34 @@ namespace KeePassLib.Keys
byte[] pbNewKey = new byte[32]; byte[] pbNewKey = new byte[32];
Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length); Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length);
// Try to use the native library first try
if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds)) {
// 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); return (new SHA256Managed()).ComputeHash(pbNewKey);
}
if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds) == false) finally { MemUtil.ZeroByteArray(pbNewKey); }
return null;
SHA256Managed sha256 = new SHA256Managed();
return sha256.ComputeHash(pbNewKey);
} }
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
ulong uNumRounds) 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]; byte[] pbIV = new byte[16];
Array.Clear(pbIV, 0, pbIV.Length); Array.Clear(pbIV, 0, pbIV.Length);
@ -301,6 +346,7 @@ namespace KeePassLib.Keys
iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0); iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0);
iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16); iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16);
} }
#endif
return true; return true;
} }
@ -325,9 +371,6 @@ namespace KeePassLib.Keys
if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds)) if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds))
return uRounds; return uRounds;
byte[] pbIV = new byte[16];
Array.Clear(pbIV, 0, pbIV.Length);
byte[] pbKey = new byte[32]; byte[] pbKey = new byte[32];
byte[] pbNewKey = new byte[32]; byte[] pbNewKey = new byte[32];
for(int i = 0; i < pbKey.Length; ++i) for(int i = 0; i < pbKey.Length; ++i)
@ -336,6 +379,14 @@ namespace KeePassLib.Keys
pbNewKey[i] = (byte)i; 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(); RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size if(r.BlockSize != 128) // AES block size
{ {
@ -358,18 +409,21 @@ namespace KeePassLib.Keys
Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!"); Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!");
return PwDefs.DefaultKeyEncryptionRounds; return PwDefs.DefaultKeyEncryptionRounds;
} }
#endif
DateTime dtStart = DateTime.Now;
TimeSpan ts;
double dblReqMillis = uMilliseconds;
uRounds = 0; uRounds = 0;
int tStart = Environment.TickCount;
while(true) while(true)
{ {
for(ulong j = 0; j < uStep; ++j) 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, 0, 16, pbNewKey, 0);
iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16); iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16);
#endif
} }
uRounds += uStep; uRounds += uStep;
@ -379,8 +433,8 @@ namespace KeePassLib.Keys
break; break;
} }
ts = DateTime.Now - dtStart; uint tElapsed = (uint)(Environment.TickCount - tStart);
if(ts.TotalMilliseconds > dblReqMillis) break; if(tElapsed > uMilliseconds) break;
} }
return uRounds; return uRounds;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,12 +19,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys namespace KeePassLib.Keys
{ {

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,14 +18,18 @@
*/ */
using System; using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics; 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.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Serialization; using KeePassLib.Serialization;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -60,19 +64,47 @@ namespace KeePassLib.Keys
public KcpKeyFile(string strKeyFile) 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) 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); byte[] pbFileData = IOConnection.ReadFile(iocFile);
if(pbFileData == null) throw new FileNotFoundException(); 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); byte[] pbKey = LoadXmlKeyFile(pbFileData);
if(pbKey == null) pbKey = LoadKeyFile(pbFileData); if(pbKey == null) pbKey = LoadKeyFile(pbFileData);
@ -124,7 +156,7 @@ namespace KeePassLib.Keys
try try
{ {
string strHex = Encoding.ASCII.GetString(pbFileData, 0, 64); string strHex = StrUtil.Utf8.GetString(pbFileData, 0, 64);
if(!StrUtil.IsHexString(strHex, true)) return null; if(!StrUtil.IsHexString(strHex, true)) return null;
byte[] pbKey = MemUtil.HexStringToByteArray(strHex); byte[] pbKey = MemUtil.HexStringToByteArray(strHex);
@ -235,7 +267,18 @@ namespace KeePassLib.Keys
Debug.Assert(pbKeyData != null); Debug.Assert(pbKeyData != null);
if(pbKeyData == null) throw new ArgumentNullException("pbKeyData"); 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.WriteStartDocument();
xtw.WriteWhitespace("\r\n"); xtw.WriteWhitespace("\r\n");
@ -266,6 +309,8 @@ namespace KeePassLib.Keys
xtw.WriteWhitespace("\r\n"); xtw.WriteWhitespace("\r\n");
xtw.WriteEndDocument(); // End KeyFile xtw.WriteEndDocument(); // End KeyFile
xtw.Close(); xtw.Close();
sOut.Close();
} }
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,9 +18,12 @@
*/ */
using System; using System;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -68,6 +71,10 @@ namespace KeePassLib.Keys
Debug.Assert(pbPasswordUtf8 != null); Debug.Assert(pbPasswordUtf8 != null);
if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8"); if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8");
#if (DEBUG && !KeePassLibSD)
Debug.Assert(ValidatePassword(pbPasswordUtf8));
#endif
SHA256Managed sha256 = new SHA256Managed(); SHA256Managed sha256 = new SHA256Managed();
byte[] pbRaw = sha256.ComputeHash(pbPasswordUtf8); byte[] pbRaw = sha256.ComputeHash(pbPasswordUtf8);
@ -80,5 +87,19 @@ namespace KeePassLib.Keys
// m_psPassword = null; // m_psPassword = null;
// m_pbKeyData = 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 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 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 it under the terms of the GNU General Public License as published by
@ -18,9 +18,13 @@
*/ */
using System; using System;
using System.Security; using System.Diagnostics;
using System.Security.Cryptography;
using System.IO; using System.IO;
using System.Security;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography; using KeePassLib.Cryptography;
using KeePassLib.Resources; using KeePassLib.Resources;
@ -37,7 +41,7 @@ namespace KeePassLib.Keys
private ProtectedBinary m_pbKeyData = null; private ProtectedBinary m_pbKeyData = null;
// Constant initialization vector (unique for KeePass) // 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, 0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6 0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
}; };
@ -67,10 +71,14 @@ namespace KeePassLib.Keys
byte[] pbKey = LoadUserKey(false); byte[] pbKey = LoadUserKey(false);
if(pbKey == null) pbKey = CreateUserKey(); 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); m_pbKeyData = new ProtectedBinary(true, pbKey);
Array.Clear(pbKey, 0, pbKey.Length); MemUtil.ZeroByteArray(pbKey);
} }
// public void Clear() // public void Clear()
@ -80,8 +88,12 @@ namespace KeePassLib.Keys
private static string GetUserKeyFilePath(bool bCreate) private static string GetUserKeyFilePath(bool bCreate)
{ {
#if KeePassUAP
string strUserDir = EnvironmentExt.AppDataRoamingFolderPath;
#else
string strUserDir = Environment.GetFolderPath( string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData); Environment.SpecialFolder.ApplicationData);
#endif
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
strUserDir += PwDefs.ShortProductName; strUserDir += PwDefs.ShortProductName;
@ -90,10 +102,10 @@ namespace KeePassLib.Keys
Directory.CreateDirectory(strUserDir); Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); 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; byte[] pbKey = null;
@ -105,13 +117,10 @@ namespace KeePassLib.Keys
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy, pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser); DataProtectionScope.CurrentUser);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
} }
catch(Exception exLoad) catch(Exception)
{ {
if(bShowWarning) MessageService.ShowWarning(exLoad); if(bThrow) throw;
pbKey = null; pbKey = null;
} }
#endif #endif
@ -121,28 +130,23 @@ namespace KeePassLib.Keys
private static byte[] CreateUserKey() private static byte[] CreateUserKey()
{ {
byte[] pbKey = null; #if KeePassLibSD
return null;
#else
string strFilePath = GetUserKeyFilePath(true);
#if !KeePassLibSD byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
try byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
{ m_pbEntropy, DataProtectionScope.CurrentUser);
string strFilePath = GetUserKeyFilePath(true);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64); File.WriteAllBytes(strFilePath, pbProtectedKey);
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
m_pbEntropy, DataProtectionScope.CurrentUser);
File.WriteAllBytes(strFilePath, pbProtectedKey); byte[] pbKey = LoadUserKey(true);
Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey));
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
Array.Clear(pbRandomKey, 0, pbRandomKey.Length);
pbKey = LoadUserKey(true);
}
catch(Exception) { pbKey = null; }
#endif
MemUtil.ZeroByteArray(pbRandomKey);
return pbKey; return pbKey;
#endif
} }
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics; 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; using KeePassLib.Utility;
@ -44,6 +53,61 @@ namespace KeePassLib.Native
set { m_bAllowNative = value; } 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> /// <summary>
/// Determine if the native library is installed. /// Determine if the native library is installed.
/// </summary> /// </summary>
@ -87,9 +151,13 @@ namespace KeePassLib.Native
{ {
if(m_platID.HasValue) return m_platID.Value; if(m_platID.HasValue) return m_platID.Value;
#if KeePassUAP
m_platID = EnvironmentExt.OSVersion.Platform;
#else
m_platID = Environment.OSVersion.Platform; m_platID = Environment.OSVersion.Platform;
#endif
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
// Mono returns PlatformID.Unix on Mac OS X, workaround this // Mono returns PlatformID.Unix on Mac OS X, workaround this
if(m_platID.Value == PlatformID.Unix) if(m_platID.Value == PlatformID.Unix)
{ {
@ -102,7 +170,55 @@ namespace KeePassLib.Native
return m_platID.Value; 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) public static string RunConsoleApp(string strAppPath, string strParams)
{ {
return RunConsoleApp(strAppPath, strParams, null); return RunConsoleApp(strAppPath, strParams, null);
@ -110,40 +226,134 @@ namespace KeePassLib.Native
public static string RunConsoleApp(string strAppPath, string strParams, public static string RunConsoleApp(string strAppPath, string strParams,
string strStdInput) 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 == null) throw new ArgumentNullException("strAppPath");
if(strAppPath.Length == 0) throw new ArgumentException("strAppPath"); if(strAppPath.Length == 0) throw new ArgumentException("strAppPath");
try bool bStdOut = ((f & AppRunFlags.GetStdOutput) != AppRunFlags.None);
RunProcessDelegate fnRun = delegate()
{ {
ProcessStartInfo psi = new ProcessStartInfo(); try
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)
{ {
p.StandardInput.Write(strStdInput); ProcessStartInfo psi = new ProcessStartInfo();
p.StandardInput.Close();
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(); IAsyncResult ar = fnRun.BeginInvoke(null, null);
p.WaitForExit();
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); } catch(Exception) { Debug.Assert(false); }
return null;
} }
#endif #endif
@ -157,7 +367,10 @@ namespace KeePassLib.Native
public static bool TransformKey256(byte[] pBuf256, byte[] pKey256, public static bool TransformKey256(byte[] pBuf256, byte[] pKey256,
ulong uRounds) 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); KeyValuePair<IntPtr, IntPtr> kvp = PrepareArrays256(pBuf256, pKey256);
bool bResult = false; bool bResult = false;
@ -170,26 +383,31 @@ namespace KeePassLib.Native
if(bResult) GetBuffers256(kvp, pBuf256, pKey256); if(bResult) GetBuffers256(kvp, pBuf256, pKey256);
NativeLib.FreeArrays(kvp); FreeArrays(kvp);
return bResult; return bResult;
#endif
} }
/// <summary> /// <summary>
/// Benchmark key transformation. /// Benchmark key transformation.
/// </summary> /// </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> /// <param name="puRounds">Number of transformations done.</param>
/// <returns>Returns <c>true</c>, if the benchmark was successful.</returns> /// <returns>Returns <c>true</c>, if the benchmark was successful.</returns>
public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds) public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds)
{ {
puRounds = 0; puRounds = 0;
if(m_bAllowNative == false) return false; #if KeePassUAP
return false;
#else
if(!m_bAllowNative) return false;
try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); } try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); }
catch(Exception) { return false; } catch(Exception) { return false; }
return true; return true;
#endif
} }
private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256, private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256,

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -27,7 +27,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Dominik Reichl")] [assembly: AssemblyCompany("Dominik Reichl")]
[assembly: AssemblyProduct("KeePassLib")] [assembly: AssemblyProduct("KeePassLib")]
[assembly: AssemblyCopyright("Copyright © 2003-2012 Dominik Reichl")] [assembly: AssemblyCopyright("Copyright © 2003-2016 Dominik Reichl")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@ -38,5 +38,5 @@ using System.Runtime.InteropServices;
[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")] [assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")]
// Assembly version information // Assembly version information
[assembly: AssemblyVersion("2.20.1.*")] [assembly: AssemblyVersion("2.34.0.*")]
[assembly: AssemblyFileVersion("2.20.1.0")] [assembly: AssemblyFileVersion("2.34.0.0")]

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,9 +18,12 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
#if !KeePassUAP
using System.Drawing; using System.Drawing;
using System.IO; #endif
using KeePassLib.Utility; using KeePassLib.Utility;
@ -33,7 +36,13 @@ namespace KeePassLib
{ {
private PwUuid m_pwUuid; private PwUuid m_pwUuid;
private byte[] m_pbImageDataPng; 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 public PwUuid Uuid
{ {
@ -45,32 +54,73 @@ namespace KeePassLib
get { return m_pbImageDataPng; } get { return m_pbImageDataPng; }
} }
[Obsolete("Use GetImage instead.")]
public Image Image 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) public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng)
{ {
Debug.Assert(pwUuid != null); Debug.Assert(pwUuid != null);
if(pwUuid == null) throw new ArgumentNullException("pwUuid"); if(pwUuid == null) throw new ArgumentNullException("pwUuid");
Debug.Assert(pwUuid != PwUuid.Zero); Debug.Assert(!pwUuid.Equals(PwUuid.Zero));
if(pwUuid == PwUuid.Zero) throw new ArgumentException("pwUuid == 0"); if(pwUuid.Equals(PwUuid.Zero)) throw new ArgumentException("pwUuid == 0.");
Debug.Assert(pbImageDataPng != null); Debug.Assert(pbImageDataPng != null);
if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng"); if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng");
m_pwUuid = pwUuid; m_pwUuid = pwUuid;
m_pbImageDataPng = pbImageDataPng; m_pbImageDataPng = pbImageDataPng;
#if !KeePassLibSD
// MemoryStream ms = new MemoryStream(m_pbImageDataPng, false); // MemoryStream ms = new MemoryStream(m_pbImageDataPng, false);
// m_pCachedImage = Image.FromStream(ms); // m_imgOrg = Image.FromStream(ms);
// ms.Close(); // ms.Close();
m_pCachedImage = GfxUtil.LoadImage(m_pbImageDataPng); try { m_imgOrg = GfxUtil.LoadImage(m_pbImageDataPng); }
#else catch(Exception) { Debug.Assert(false); }
m_pCachedImage = null;
#endif 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,12 +19,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml.Serialization;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.Xml.Serialization;
using KeePassLib.Delegates; using KeePassLib.Delegates;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Serialization;
namespace KeePassLib namespace KeePassLib
{ {
@ -54,20 +55,20 @@ namespace KeePassLib
/// e.g. 2.19 = 0x02130000. /// e.g. 2.19 = 0x02130000.
/// It is highly recommended to use <c>FileVersion64</c> instead. /// It is highly recommended to use <c>FileVersion64</c> instead.
/// </summary> /// </summary>
public const uint Version32 = 0x02140100; public const uint Version32 = 0x02220000;
/// <summary> /// <summary>
/// Version, encoded as 64-bit unsigned integer /// Version, encoded as 64-bit unsigned integer
/// (component-wise, 16 bits per component). /// (component-wise, 16 bits per component).
/// </summary> /// </summary>
public const ulong FileVersion64 = 0x0002001400010000UL; public const ulong FileVersion64 = 0x0002002200000000UL;
/// <summary> /// <summary>
/// Version, encoded as string. /// Version, encoded as string.
/// </summary> /// </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> /// <summary>
/// Product website URL. Terminated by a forward slash. /// Product website URL. Terminated by a forward slash.
@ -93,7 +94,8 @@ namespace KeePassLib
/// URL to a TXT file (eventually compressed) that contains information /// URL to a TXT file (eventually compressed) that contains information
/// about the latest KeePass version available on the website. /// about the latest KeePass version available on the website.
/// </summary> /// </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> /// <summary>
/// URL to the root path of the online KeePass help. Terminated by /// 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> /// <summary>
/// Search parameters for group and entry searches. /// Search parameters for group and entry searches.
/// </summary> /// </summary>
@ -317,7 +319,11 @@ namespace KeePassLib
set { m_bSearchInTags = value; } set { m_bSearchInTags = value; }
} }
#if KeePassUAP
private StringComparison m_scType = StringComparison.OrdinalIgnoreCase;
#else
private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase; private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase;
#endif
/// <summary> /// <summary>
/// String comparison type. Specifies the condition when the specified /// String comparison type. Specifies the condition when the specified
/// text matches a group/entry string. /// text matches a group/entry string.
@ -405,9 +411,9 @@ namespace KeePassLib
return (SearchParameters)this.MemberwiseClone(); 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> /// <summary>
/// Memory protection configuration structure (for default fields). /// Memory protection configuration structure (for default fields).
/// </summary> /// </summary>
@ -437,7 +443,7 @@ namespace KeePassLib
return false; return false;
} }
} }
#pragma warning restore 1591 // Missing XML comments warning // #pragma warning restore 1591 // Missing XML comments warning
public sealed class ObjectTouchedEventArgs : EventArgs public sealed class ObjectTouchedEventArgs : EventArgs
{ {
@ -458,4 +464,24 @@ namespace KeePassLib
m_bParentsTouched = bParentsTouched; 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 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -20,8 +20,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Xml;
#if !KeePassUAP
using System.Drawing; using System.Drawing;
#endif
using KeePassLib.Collections; using KeePassLib.Collections;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
@ -83,7 +85,7 @@ namespace KeePassLib
{ {
get { return m_pParentGroup; } get { return m_pParentGroup; }
/// Plugins: use <c>PwGroup.AddEntry</c> instead. // Plugins: use <c>PwGroup.AddEntry</c> instead.
internal set { m_pParentGroup = value; } internal set { m_pParentGroup = value; }
} }
@ -199,15 +201,6 @@ namespace KeePassLib
set { m_tCreation = value; } 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> /// <summary>
/// The date/time when this entry was last modified. /// The date/time when this entry was last modified.
/// </summary> /// </summary>
@ -217,6 +210,15 @@ namespace KeePassLib
set { m_tLastMod = value; } 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> /// <summary>
/// The date/time when this entry expires. Use the <c>Expires</c> property /// The date/time when this entry expires. Use the <c>Expires</c> property
/// to specify if the entry does actually expire or not. /// 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> /// <summary>
/// Clone the current entry. The returned entry is an exact value copy /// Clone the current entry. The returned entry is an exact value copy
/// of the current entry (including UUID and parent group reference). /// of the current entry (including UUID and parent group reference).
@ -413,7 +423,7 @@ namespace KeePassLib
bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) != bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) !=
PwCompareOptions.None); 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((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
{ {
if(m_pParentGroup != pe.m_pParentGroup) return false; if(m_pParentGroup != pe.m_pParentGroup) return false;
@ -456,7 +466,7 @@ namespace KeePassLib
} }
if(m_pwIcon != pe.m_pwIcon) return false; 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_clrForeground != pe.m_clrForeground) return false;
if(m_clrBackground != pe.m_clrBackground) 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"); 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 // 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; m_uuid = peTemplate.m_uuid;
if(bAssignLocationChanged) if(bAssignLocationChanged)
@ -692,7 +704,7 @@ namespace KeePassLib
for(uint u = 0; u < m_listHistory.UCount; ++u) for(uint u = 0; u < m_listHistory.UCount; ++u)
{ {
PwEntry pe = m_listHistory.GetAt(u); PwEntry pe = m_listHistory.GetAt(u);
if(pe.LastModificationTime < dtMin) if(TimeUtil.Compare(pe.LastModificationTime, dtMin, true) < 0)
{ {
idxRemove = u; idxRemove = u;
dtMin = pe.LastModificationTime; 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> public sealed class PwEntryComparer : IComparer<PwEntry>
@ -868,6 +898,7 @@ namespace KeePassLib
string strB = b.Strings.ReadSafe(m_strFieldName); string strB = b.Strings.ReadSafe(m_strFieldName);
if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB); if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB);
return string.Compare(strA, strB, m_bCaseInsensitive); return string.Compare(strA, strB, m_bCaseInsensitive);
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -65,6 +65,8 @@ namespace KeePassLib
/// </summary> /// </summary>
public enum PwMergeMethod public enum PwMergeMethod
{ {
// Do not change the explicitly assigned values, otherwise
// serialization (e.g. of Ecas triggers) breaks
None = 0, None = 0,
OverwriteExisting = 1, OverwriteExisting = 1,
KeepExisting = 2, KeepExisting = 2,
@ -161,6 +163,26 @@ namespace KeePassLib
Manual = 2 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> /// <summary>
/// Comparison modes for in-memory protected objects. /// Comparison modes for in-memory protected objects.
/// </summary> /// </summary>
@ -202,6 +224,96 @@ namespace KeePassLib
IgnoreHistory = 0x10, IgnoreHistory = 0x10,
IgnoreLastBackup = 0x20, IgnoreLastBackup = 0x20,
// For groups:
PropertiesOnly = 0x40,
IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod) 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 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 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 it under the terms of the GNU General Public License as published by
@ -137,7 +137,7 @@ namespace KeePassLib
{ {
get { return m_pParentGroup; } 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; } internal set { Debug.Assert(value != this); m_pParentGroup = value; }
} }
@ -329,6 +329,14 @@ namespace KeePassLib
m_pwIcon = pwIcon; m_pwIcon = pwIcon;
} }
#if DEBUG
// For display in debugger
public override string ToString()
{
return (@"PwGroup '" + m_strName + @"'");
}
#endif
/// <summary> /// <summary>
/// Deeply clone the current group. The returned group will be an exact /// Deeply clone the current group. The returned group will be an exact
/// value copy of the current object (including UUID, etc.). /// value copy of the current object (including UUID, etc.).
@ -352,9 +360,9 @@ namespace KeePassLib
pg.m_pwCustomIconID = m_pwCustomIconID; pg.m_pwCustomIconID = m_pwCustomIconID;
pg.m_tCreation = m_tCreation; pg.m_tCreation = m_tCreation;
pg.m_tExpire = m_tExpire;
pg.m_tLastAccess = m_tLastAccess;
pg.m_tLastMod = m_tLastMod; pg.m_tLastMod = m_tLastMod;
pg.m_tLastAccess = m_tLastAccess;
pg.m_tExpire = m_tExpire;
pg.m_bExpires = m_bExpires; pg.m_bExpires = m_bExpires;
pg.m_uUsageCount = m_uUsageCount; pg.m_uUsageCount = m_uUsageCount;
@ -363,6 +371,9 @@ namespace KeePassLib
pg.m_strDefaultAutoTypeSequence = m_strDefaultAutoTypeSequence; pg.m_strDefaultAutoTypeSequence = m_strDefaultAutoTypeSequence;
pg.m_bEnableAutoType = m_bEnableAutoType;
pg.m_bEnableSearching = m_bEnableSearching;
pg.m_pwLastTopVisibleEntry = m_pwLastTopVisibleEntry; pg.m_pwLastTopVisibleEntry = m_pwLastTopVisibleEntry;
return pg; return pg;
@ -385,6 +396,76 @@ namespace KeePassLib
return pg; 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> /// <summary>
/// Assign properties to the current group based on a template group. /// Assign properties to the current group based on a template group.
/// </summary> /// </summary>
@ -398,10 +479,12 @@ namespace KeePassLib
{ {
Debug.Assert(pgTemplate != null); if(pgTemplate == null) throw new ArgumentNullException("pgTemplate"); 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 // 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; m_uuid = pgTemplate.m_uuid;
if(bAssignLocationChanged) if(bAssignLocationChanged)
@ -422,6 +505,9 @@ namespace KeePassLib
m_strDefaultAutoTypeSequence = pgTemplate.m_strDefaultAutoTypeSequence; m_strDefaultAutoTypeSequence = pgTemplate.m_strDefaultAutoTypeSequence;
m_bEnableAutoType = pgTemplate.m_bEnableAutoType;
m_bEnableSearching = pgTemplate.m_bEnableSearching;
m_pwLastTopVisibleEntry = pgTemplate.m_pwLastTopVisibleEntry; m_pwLastTopVisibleEntry = pgTemplate.m_pwLastTopVisibleEntry;
} }
@ -573,8 +659,6 @@ namespace KeePassLib
/// <summary> /// <summary>
/// Pack all groups into one flat linked list of references (recursively). /// 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> /// </summary>
/// <returns>Flat list of all groups.</returns> /// <returns>Flat list of all groups.</returns>
public LinkedList<PwGroup> GetFlatGroupList() public LinkedList<PwGroup> GetFlatGroupList()
@ -671,6 +755,7 @@ namespace KeePassLib
/// <param name="sp">Specifies the search method.</param> /// <param name="sp">Specifies the search method.</param>
/// <param name="listStorage">Entry list in which the search results will /// <param name="listStorage">Entry list in which the search results will
/// be stored.</param> /// be stored.</param>
/// <param name="slStatus">Optional status reporting object.</param>
public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage, public void SearchEntries(SearchParameters sp, PwObjectList<PwEntry> listStorage,
IStatusLogger slStatus) IStatusLogger slStatus)
{ {
@ -764,9 +849,11 @@ namespace KeePassLib
Regex rx = null; Regex rx = null;
if(sp.RegularExpression) if(sp.RegularExpression)
{ {
RegexOptions ro = RegexOptions.Compiled; RegexOptions ro = RegexOptions.None; // RegexOptions.Compiled
if((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) || if((sp.ComparisonMode == StringComparison.CurrentCultureIgnoreCase) ||
#if !KeePassUAP
(sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) || (sp.ComparisonMode == StringComparison.InvariantCultureIgnoreCase) ||
#endif
(sp.ComparisonMode == StringComparison.OrdinalIgnoreCase)) (sp.ComparisonMode == StringComparison.OrdinalIgnoreCase))
{ {
ro |= RegexOptions.IgnoreCase; ro |= RegexOptions.IgnoreCase;
@ -938,6 +1025,30 @@ namespace KeePassLib
return vTags; 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, public void FindEntriesByTag(string strTag, PwObjectList<PwEntry> listStorage,
bool bSearchRecursive) bool bSearchRecursive)
{ {
@ -972,7 +1083,7 @@ namespace KeePassLib
public PwGroup FindGroup(PwUuid uuid, bool bSearchRecursive) public PwGroup FindGroup(PwUuid uuid, bool bSearchRecursive)
{ {
// Do not assert on PwUuid.Zero // Do not assert on PwUuid.Zero
if(m_uuid.EqualsValue(uuid)) return this; if(m_uuid.Equals(uuid)) return this;
if(bSearchRecursive) if(bSearchRecursive)
{ {
@ -987,7 +1098,7 @@ namespace KeePassLib
{ {
foreach(PwGroup pg in m_listGroups) foreach(PwGroup pg in m_listGroups)
{ {
if(pg.m_uuid.EqualsValue(uuid)) if(pg.m_uuid.Equals(uuid))
return pg; return pg;
} }
} }
@ -1051,7 +1162,7 @@ namespace KeePassLib
{ {
foreach(PwEntry pe in m_listEntries) foreach(PwEntry pe in m_listEntries)
{ {
if(pe.Uuid.EqualsValue(uuid)) return pe; if(pe.Uuid.Equals(uuid)) return pe;
} }
if(bSearchRecursive) if(bSearchRecursive)
@ -1081,6 +1192,8 @@ namespace KeePassLib
/// </summary> /// </summary>
/// <param name="strSeparator">String that separates the group /// <param name="strSeparator">String that separates the group
/// names.</param> /// names.</param>
/// <param name="bIncludeTopMostGroup">Specifies whether the returned
/// path starts with the topmost group.</param>
/// <returns>Full path of the group.</returns> /// <returns>Full path of the group.</returns>
public string GetFullPath(string strSeparator, bool bIncludeTopMostGroup) public string GetFullPath(string strSeparator, bool bIncludeTopMostGroup)
{ {
@ -1151,6 +1264,7 @@ namespace KeePassLib
} }
} }
#if !KeePassLibSD
/// <summary> /// <summary>
/// Find/create a subtree of groups. /// Find/create a subtree of groups.
/// </summary> /// </summary>
@ -1164,11 +1278,23 @@ namespace KeePassLib
public PwGroup FindCreateSubTree(string strTree, char[] vSeparators, public PwGroup FindCreateSubTree(string strTree, char[] vSeparators,
bool bAllowCreate) 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; Debug.Assert(strTree != null); if(strTree == null) return this;
if(strTree.Length == 0) 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; if((vGroups == null) || (vGroups.Length == 0)) return this;
PwGroup pgContainer = this; PwGroup pgContainer = this;
@ -1199,6 +1325,7 @@ namespace KeePassLib
return pgContainer; return pgContainer;
} }
#endif
/// <summary> /// <summary>
/// Get the level of the group (i.e. the number of parent groups). /// Get the level of the group (i.e. the number of parent groups).
@ -1422,6 +1549,69 @@ namespace KeePassLib
} }
m_listGroups.Clear(); 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> public sealed class PwGroupComparer : IComparer<PwGroup>

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,6 +18,7 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Xml; using System.Xml;
using System.Diagnostics; using System.Diagnostics;
@ -27,10 +28,10 @@ namespace KeePassLib
{ {
// [ImmutableObject(true)] // [ImmutableObject(true)]
/// <summary> /// <summary>
/// Represents an UUID of a password entry or group. Once created, <c>PwUuid</c> /// Represents an UUID of a password entry or group. Once created,
/// objects aren't modifyable anymore (immutable). /// <c>PwUuid</c> objects aren't modifyable anymore (immutable).
/// </summary> /// </summary>
public sealed class PwUuid public sealed class PwUuid : IComparable<PwUuid>, IEquatable<PwUuid>
{ {
/// <summary> /// <summary>
/// Standard size in bytes of a UUID. /// Standard size in bytes of a UUID.
@ -40,9 +41,9 @@ namespace KeePassLib
/// <summary> /// <summary>
/// Zero UUID (all bytes are zero). /// Zero UUID (all bytes are zero).
/// </summary> /// </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> /// <summary>
/// Get the 16 UUID bytes. /// Get the 16 UUID bytes.
@ -52,14 +53,6 @@ namespace KeePassLib
get { return m_pbUuid; } get { return m_pbUuid; }
} }
/// <summary>
/// Construct a new UUID object. Its value is initialized to zero.
/// </summary>
private PwUuid()
{
SetZero();
}
/// <summary> /// <summary>
/// Construct a new UUID object. /// Construct a new UUID object.
/// </summary> /// </summary>
@ -88,38 +81,95 @@ namespace KeePassLib
/// otherwise it returns <c>false</c>.</returns> /// otherwise it returns <c>false</c>.</returns>
private void CreateNew() private void CreateNew()
{ {
Debug.Assert(m_pbUuid == null); // Only call from constructor
while(true) while(true)
{ {
m_pbUuid = Guid.NewGuid().ToByteArray(); 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(); throw new InvalidOperationException();
}
// Zero is a reserved value -- do not generate Zero // Zero is a reserved value -- do not generate Zero
if(this.EqualsValue(PwUuid.Zero) == false) if(!Equals(PwUuid.Zero)) break;
break; Debug.Assert(false);
} }
} }
/// <summary> private void SetValue(byte[] uuidBytes)
/// Compare this UUID with another. {
/// </summary> Debug.Assert((uuidBytes != null) && (uuidBytes.Length == (int)UuidSize));
/// <param name="uuid">Second UUID object.</param> if(uuidBytes == null) throw new ArgumentNullException("uuidBytes");
/// <returns>Returns <c>true</c> if both PwUuid object contain the same if(uuidBytes.Length != (int)UuidSize) throw new ArgumentException();
/// value, otherwise <c>false</c> is returned.</returns>
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) public bool EqualsValue(PwUuid uuid)
{ {
Debug.Assert(uuid != null); return Equals(uuid);
if(uuid == null) throw new ArgumentNullException("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; 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> /// <summary>
/// Convert the UUID to its string representation. /// Convert the UUID to its string representation.
/// </summary> /// </summary>
@ -129,29 +179,15 @@ namespace KeePassLib
return MemUtil.ByteArrayToHexString(m_pbUuid); return MemUtil.ByteArrayToHexString(m_pbUuid);
} }
/// <summary> #if DEBUG
/// Set the UUID value. The input parameter will not be modified. public override string ToString()
/// </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)
{ {
Debug.Assert((uuidBytes != null) && (uuidBytes.Length == UuidSize)); return ToHexString();
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);
} }
#endif
} }
[Obsolete]
public sealed class PwUuidComparable : IComparable<PwUuidComparable> public sealed class PwUuidComparable : IComparable<PwUuidComparable>
{ {
private byte[] m_pbUuid = new byte[PwUuid.UuidSize]; 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_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed);
m_strEncAlgorithmAes = TryGetEx(dictNew, "EncAlgorithmAes", m_strEncAlgorithmAes); m_strEncAlgorithmAes = TryGetEx(dictNew, "EncAlgorithmAes", m_strEncAlgorithmAes);
m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard); m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard);
m_strExpect100Continue = TryGetEx(dictNew, "Expect100Continue", m_strExpect100Continue);
m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError); m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError);
m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText); m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText);
m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted); m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted);
@ -44,21 +45,28 @@ namespace KeePassLib.Resources
m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported); m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported);
m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed); m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed);
m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp); m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp);
m_strGeneral = TryGetEx(dictNew, "General", m_strGeneral);
m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey); m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey);
m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint); m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint);
m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding); m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding);
m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint); m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint);
m_strKeyFileDbSel = TryGetEx(dictNew, "KeyFileDbSel", m_strKeyFileDbSel);
m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid); m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid);
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat); 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_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId); m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError); m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError);
m_strUserAgent = TryGetEx(dictNew, "UserAgent", m_strUserAgent);
} }
private static readonly string[] m_vKeyNames = { private static readonly string[] m_vKeyNames = {
"CryptoStreamFailed", "CryptoStreamFailed",
"EncAlgorithmAes", "EncAlgorithmAes",
"ErrorInClipboard", "ErrorInClipboard",
"Expect100Continue",
"FatalError", "FatalError",
"FatalErrorText", "FatalErrorText",
"FileCorrupted", "FileCorrupted",
@ -74,15 +82,21 @@ namespace KeePassLib.Resources
"FileVersionUnsupported", "FileVersionUnsupported",
"FinalKeyCreationFailed", "FinalKeyCreationFailed",
"FrameworkNotImplExcp", "FrameworkNotImplExcp",
"General",
"InvalidCompositeKey", "InvalidCompositeKey",
"InvalidCompositeKeyHint", "InvalidCompositeKeyHint",
"InvalidDataWhileDecoding", "InvalidDataWhileDecoding",
"KeePass1xHint", "KeePass1xHint",
"KeyFileDbSel",
"MasterSeedLengthInvalid", "MasterSeedLengthInvalid",
"OldFormat", "OldFormat",
"Passive",
"PreAuth",
"Timeout",
"TryAgainSecs", "TryAgainSecs",
"UnknownHeaderId", "UnknownHeaderId",
"UserAccountKeyError" "UserAccountKeyError",
"UserAgent"
}; };
public static string[] GetKeyNames() public static string[] GetKeyNames()
@ -123,6 +137,17 @@ namespace KeePassLib.Resources
get { return m_strErrorInClipboard; } 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 = private static string m_strFatalError =
@"Fatal Error"; @"Fatal Error";
/// <summary> /// <summary>
@ -288,6 +313,17 @@ namespace KeePassLib.Resources
get { return m_strFrameworkNotImplExcp; } 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 = private static string m_strInvalidCompositeKey =
@"The composite key is invalid!"; @"The composite key is invalid!";
/// <summary> /// <summary>
@ -332,6 +368,17 @@ namespace KeePassLib.Resources
get { return m_strKeePass1xHint; } 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 = private static string m_strMasterSeedLengthInvalid =
@"The length of the master key seed is invalid!"; @"The length of the master key seed is invalid!";
/// <summary> /// <summary>
@ -354,6 +401,39 @@ namespace KeePassLib.Resources
get { return m_strOldFormat; } 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 = private static string m_strTryAgainSecs =
@"Please try it again in a few seconds."; @"Please try it again in a few seconds.";
/// <summary> /// <summary>
@ -386,5 +466,16 @@ namespace KeePassLib.Resources
{ {
get { return m_strUserAccountKeyError; } 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 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 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 it under the terms of the GNU General Public License as published by
@ -18,10 +18,16 @@
*/ */
using System; using System;
using System.Security.Cryptography;
using System.Diagnostics; using System.Diagnostics;
using System.Threading;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography; using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
#if KeePassLibSD #if KeePassLibSD
@ -30,6 +36,17 @@ using KeePassLibSD;
namespace KeePassLib.Security namespace KeePassLib.Security
{ {
[Flags]
public enum PbCryptFlags
{
None = 0,
Encrypt = 1,
Decrypt = 2
}
public delegate void PbCryptDelegate(byte[] pbData, PbCryptFlags cf,
long lID);
/// <summary> /// <summary>
/// Represents a protected binary, i.e. a byte array that is encrypted /// Represents a protected binary, i.e. a byte array that is encrypted
/// in memory. A <c>ProtectedBinary</c> object is immutable and /// in memory. A <c>ProtectedBinary</c> object is immutable and
@ -37,26 +54,98 @@ namespace KeePassLib.Security
/// </summary> /// </summary>
public sealed class ProtectedBinary : IEquatable<ProtectedBinary> 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 private static PbCryptDelegate g_fExtCrypt = null;
// higher. /// <summary>
private static bool m_bProtectionSupported; /// 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 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 // 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 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 object m_objSync = new object();
private static byte[] g_pbKey32 = null;
/// <summary> /// <summary>
/// A flag specifying whether the <c>ProtectedBinary</c> object has /// A flag specifying whether the <c>ProtectedBinary</c> object has
/// turned on in-memory protection or not. /// turned on memory protection or not.
/// </summary> /// </summary>
public bool IsProtected public bool IsProtected
{ {
@ -71,23 +160,9 @@ namespace KeePassLib.Security
get { return m_uDataLen; } 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> /// <summary>
/// Construct a new, empty protected binary data object. Protection /// Construct a new, empty protected binary data object.
/// is disabled. /// Protection is disabled.
/// </summary> /// </summary>
public ProtectedBinary() public ProtectedBinary()
{ {
@ -116,34 +191,103 @@ namespace KeePassLib.Security
/// <param name="bEnableProtection">Enable protection or not.</param> /// <param name="bEnableProtection">Enable protection or not.</param>
/// <param name="xbProtected"><c>XorredBuffer</c> object used to /// <param name="xbProtected"><c>XorredBuffer</c> object used to
/// initialize the <c>ProtectedBinary</c> object.</param> /// 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) 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(); byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb); Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
} }
private void Init(bool bEnableProtection, byte[] pbData) private void Init(bool bEnableProtection, byte[] pbData)
{ {
if(pbData == null) throw new ArgumentNullException("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_bProtected = bEnableProtection;
m_uDataLen = (uint)pbData.Length; m_uDataLen = (uint)pbData.Length;
int nBlocks = (int)m_uDataLen / PmBlockSize; const int bs = ProtectedBinary.BlockSize;
if((nBlocks * PmBlockSize) < (int)m_uDataLen) ++nBlocks; int nBlocks = (int)m_uDataLen / bs;
Debug.Assert((nBlocks * PmBlockSize) >= (int)m_uDataLen); 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); Array.Copy(pbData, m_pbData, (int)m_uDataLen);
// Data size must be > 0, otherwise 'Protect' throws Encrypt();
if(m_bProtected && m_bProtectionSupported && (m_uDataLen > 0)) }
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); 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> /// <summary>
@ -160,16 +304,12 @@ namespace KeePassLib.Security
byte[] pbReturn = new byte[m_uDataLen]; byte[] pbReturn = new byte[m_uDataLen];
if(m_bProtected && m_bProtectionSupported) lock(m_objSync)
{ {
lock(m_objSync) Decrypt();
{ Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess); Encrypt();
Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
}
} }
else Array.Copy(m_pbData, pbReturn, (int)m_uDataLen);
return pbReturn; return pbReturn;
} }
@ -179,9 +319,6 @@ namespace KeePassLib.Security
/// of bytes generated by a random stream. /// of bytes generated by a random stream.
/// </summary> /// </summary>
/// <param name="crsRandomSource">Random number source.</param> /// <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) public byte[] ReadXorredData(CryptoRandomStream crsRandomSource)
{ {
Debug.Assert(crsRandomSource != null); Debug.Assert(crsRandomSource != null);
@ -191,7 +328,7 @@ namespace KeePassLib.Security
uint uLen = (uint)pbData.Length; uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen); Debug.Assert(randomPad.Length == pbData.Length);
for(uint i = 0; i < uLen; ++i) for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i]; pbData[i] ^= randomPad[i];
@ -199,8 +336,11 @@ namespace KeePassLib.Security
return pbData; return pbData;
} }
private int? m_hash = null;
public override int GetHashCode() public override int GetHashCode()
{ {
if(m_hash.HasValue) return m_hash.Value;
int h = (m_bProtected ? 0x7B11D289 : 0); int h = (m_bProtected ? 0x7B11D289 : 0);
byte[] pb = ReadData(); byte[] pb = ReadData();
@ -211,6 +351,7 @@ namespace KeePassLib.Security
} }
MemUtil.ZeroByteArray(pb); MemUtil.ZeroByteArray(pb);
m_hash = h;
return h; return h;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -18,8 +18,8 @@
*/ */
using System; using System;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
using KeePassLib.Cryptography; using KeePassLib.Cryptography;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -47,7 +47,7 @@ namespace KeePassLib.Security
private bool m_bIsProtected; private bool m_bIsProtected;
private static ProtectedString m_psEmpty = new ProtectedString(); private static readonly ProtectedString m_psEmpty = new ProtectedString();
public static ProtectedString Empty public static ProtectedString Empty
{ {
get { return m_psEmpty; } get { return m_psEmpty; }
@ -55,7 +55,7 @@ namespace KeePassLib.Security
/// <summary> /// <summary>
/// A flag specifying whether the <c>ProtectedString</c> object /// 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> /// </summary>
public bool IsProtected public bool IsProtected
{ {
@ -112,10 +112,9 @@ namespace KeePassLib.Security
/// to the value supplied in the parameters. /// to the value supplied in the parameters.
/// </summary> /// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>, /// <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> /// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="strValue">The initial string value. This /// <param name="strValue">The initial string value.</param>
/// parameter won't be modified.</param>
public ProtectedString(bool bEnableProtection, string strValue) public ProtectedString(bool bEnableProtection, string strValue)
{ {
Init(bEnableProtection, strValue); Init(bEnableProtection, strValue);
@ -126,7 +125,7 @@ namespace KeePassLib.Security
/// to the value supplied in the parameters (UTF-8 encoded string). /// to the value supplied in the parameters (UTF-8 encoded string).
/// </summary> /// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>, /// <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> /// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="vUtf8Value">The initial string value, encoded as /// <param name="vUtf8Value">The initial string value, encoded as
/// UTF-8 byte array. This parameter won't be modified; the caller /// 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 /// <param name="xbProtected"><c>XorredBuffer</c> object containing the
/// string in UTF-8 representation. The UTF-8 string must not /// string in UTF-8 representation. The UTF-8 string must not
/// be <c>null</c>-terminated.</param> /// 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) public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected)
{ {
Debug.Assert(xbProtected != null);
if(xbProtected == null) throw new ArgumentNullException("xbProtected"); if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText(); byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb); Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
if(bEnableProtection) MemUtil.ZeroByteArray(pb);
} }
private void Init(bool bEnableProtection, string str) private void Init(bool bEnableProtection, string str)
@ -222,8 +221,6 @@ namespace KeePassLib.Security
/// </summary> /// </summary>
/// <param name="crsRandomSource">Random number source.</param> /// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected string.</returns> /// <returns>Protected string.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource) public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
{ {
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource"); Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
@ -232,7 +229,7 @@ namespace KeePassLib.Security
uint uLen = (uint)pbData.Length; uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen); Debug.Assert(randomPad.Length == pbData.Length);
for(uint i = 0; i < uLen; ++i) for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i]; pbData[i] ^= randomPad[i];
@ -246,7 +243,103 @@ namespace KeePassLib.Security
byte[] pb = ReadUtf8(); byte[] pb = ReadUtf8();
ProtectedString ps = new ProtectedString(bProtect, pb); 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; return ps;
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,8 +19,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO; using System.IO;
using System.Text;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -29,7 +29,7 @@ namespace KeePassLib.Serialization
public sealed class BinaryReaderEx public sealed class BinaryReaderEx
{ {
private Stream m_s; private Stream m_s;
private Encoding m_enc; // private Encoding m_enc; // See constructor
private string m_strReadExcp; private string m_strReadExcp;
public string ReadExceptionText public string ReadExceptionText
@ -56,7 +56,7 @@ namespace KeePassLib.Serialization
if(input == null) throw new ArgumentNullException("input"); if(input == null) throw new ArgumentNullException("input");
m_s = input; m_s = input;
m_enc = encoding; // m_enc = encoding; // Not used yet
m_strReadExcp = strReadExceptionText; m_strReadExcp = strReadExceptionText;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using KeePassLib.Cryptography; using KeePassLib.Cryptography;
using KeePassLib.Resources; using KeePassLib.Resources;
@ -154,13 +154,15 @@ namespace KeePassLib.Serialization
byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16); byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16);
string strTime = TimeUtil.SerializeUtc(DateTime.Now); string strTime = TimeUtil.SerializeUtc(DateTime.Now);
#if !KeePassLibSD
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime, 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.UserName, Environment.MachineName,
Environment.UserDomainName); Environment.UserDomainName);
#else
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime,
string.Empty, string.Empty, string.Empty);
#endif #endif
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -242,8 +244,8 @@ namespace KeePassLib.Serialization
if(bDisposing) Thread.Sleep(50); if(bDisposing) Thread.Sleep(50);
} }
if(bDisposing && !bFileDeleted) // if(bDisposing && !bFileDeleted)
IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception // IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception
m_iocLockFile = null; m_iocLockFile = null;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,14 +19,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
using System.Security.AccessControl; using System.Security.AccessControl;
#endif #endif
using KeePassLib.Native;
using KeePassLib.Resources;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePassLib.Serialization namespace KeePassLib.Serialization
@ -41,6 +43,16 @@ namespace KeePassLib.Serialization
private const string StrTempSuffix = ".tmp"; 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) public FileTransactionEx(IOConnectionInfo iocBaseFile)
{ {
Initialize(iocBaseFile, true); Initialize(iocBaseFile, true);
@ -58,6 +70,30 @@ namespace KeePassLib.Serialization
m_bTransacted = bTransacted; m_bTransacted = bTransacted;
m_iocBase = iocBaseFile.CloneDeep(); 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) if(m_bTransacted)
{ {
m_iocTemp = m_iocBase.CloneDeep(); m_iocTemp = m_iocBase.CloneDeep();
@ -91,11 +127,18 @@ namespace KeePassLib.Serialization
{ {
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path); bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
FileSecurity bkSecurity = null; FileSecurity bkSecurity = null;
bool bEfsEncrypted = false; bool bEfsEncrypted = false;
#endif #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(IOConnection.FileExists(m_iocBase))
{ {
#if !KeePassLibSD #if !KeePassLibSD
@ -103,15 +146,18 @@ namespace KeePassLib.Serialization
{ {
try try
{ {
#if !KeePassUAP
FileAttributes faBase = File.GetAttributes(m_iocBase.Path); FileAttributes faBase = File.GetAttributes(m_iocBase.Path);
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0); bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
#endif
DateTime tCreation = File.GetCreationTime(m_iocBase.Path); DateTime tCreation = File.GetCreationTime(m_iocBase.Path);
bkSecurity = File.GetAccessControl(m_iocBase.Path);
File.SetCreationTime(m_iocTemp.Path, tCreation); 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 #endif
@ -120,7 +166,7 @@ namespace KeePassLib.Serialization
IOConnection.RenameFile(m_iocTemp, m_iocBase); IOConnection.RenameFile(m_iocTemp, m_iocBase);
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
if(m_iocBase.IsLocalFile()) if(m_iocBase.IsLocalFile())
{ {
try try
@ -140,5 +186,15 @@ namespace KeePassLib.Serialization
if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); // Hide again 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 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 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 it under the terms of the GNU General Public License as published by
@ -18,11 +18,14 @@
*/ */
using System; using System;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text; using System.Text;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -104,9 +107,9 @@ namespace KeePassLib.Serialization
m_bVerify = bVerify; m_bVerify = bVerify;
UTF8Encoding utf8 = StrUtil.Utf8; 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(); throw new InvalidOperationException();
m_brInput = new BinaryReader(sBaseStream, utf8); m_brInput = new BinaryReader(sBaseStream, utf8);
@ -115,7 +118,7 @@ namespace KeePassLib.Serialization
} }
else // Writing mode else // Writing mode
{ {
if(m_sBaseStream.CanWrite == false) if(!m_sBaseStream.CanWrite)
throw new InvalidOperationException(); throw new InvalidOperationException();
m_bwOutput = new BinaryWriter(sBaseStream, utf8); m_bwOutput = new BinaryWriter(sBaseStream, utf8);
@ -129,8 +132,14 @@ namespace KeePassLib.Serialization
if(m_bWriting) m_bwOutput.Flush(); if(m_bWriting) m_bwOutput.Flush();
} }
#if KeePassUAP
protected override void Dispose(bool disposing)
{
if(!disposing) return;
#else
public override void Close() public override void Close()
{ {
#endif
if(m_sBaseStream != null) if(m_sBaseStream != null)
{ {
if(m_bWriting == false) // Reading mode if(m_bWriting == false) // Reading mode
@ -178,7 +187,7 @@ namespace KeePassLib.Serialization
if(m_nBufferPos == m_pbBuffer.Length) if(m_nBufferPos == m_pbBuffer.Length)
{ {
if(ReadHashedBlock() == false) 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); int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nRemaining);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,42 +19,250 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Diagnostics;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Security.Cryptography.X509Certificates; using System.Reflection;
using System.Diagnostics; using System.Text;
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
using System.Net.Cache; using System.Net.Cache;
using System.Net.Security; using System.Net.Security;
#endif #endif
#if !KeePassUAP
using System.Security.Cryptography.X509Certificates;
#endif
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Utility; using KeePassLib.Utility;
namespace KeePassLib.Serialization namespace KeePassLib.Serialization
{ {
#if !KeePassLibSD #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) protected override WebRequest GetWebRequest(Uri address)
{ {
WebRequest request = base.GetWebRequest(address); WebRequest request = base.GetWebRequest(address);
IOConnection.ConfigureWebRequest(request); IOConnection.ConfigureWebRequest(request, m_ioc);
return request; return request;
} }
} }
#endif #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 public static class IOConnection
{ {
#if !KeePassLibSD #if !KeePassLibSD
private static ProxyServerType m_pstProxyType = ProxyServerType.System; private static ProxyServerType m_pstProxyType = ProxyServerType.System;
private static string m_strProxyAddr = string.Empty; private static string m_strProxyAddr = string.Empty;
private static string m_strProxyPort = 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_strProxyUserName = string.Empty;
private static string m_strProxyPassword = 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 #endif
// Web request methods // Web request methods
@ -64,41 +272,81 @@ namespace KeePassLib.Serialization
// Web request headers // Web request headers
public const string WrhMoveFileTo = "MoveFileTo"; public const string WrhMoveFileTo = "MoveFileTo";
public static event EventHandler<IOAccessEventArgs> IOAccessPre;
#if !KeePassLibSD #if !KeePassLibSD
#if !KeePassUAP
// Allow self-signed certificates, expired certificates, etc. // Allow self-signed certificates, expired certificates, etc.
private static bool ValidateServerCertificate(object sender, private static bool AcceptCertificate(object sender,
X509Certificate certificate, X509Chain chain, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) SslPolicyErrors sslPolicyErrors)
{ {
return true; return true;
} }
#endif
public static void SetProxy(ProxyServerType pst, string strAddr, internal static void SetProxy(ProxyServerType pst, string strAddr,
string strPort, string strUserName, string strPassword) string strPort, ProxyAuthType pat, string strUserName,
string strPassword)
{ {
m_pstProxyType = pst; m_pstProxyType = pst;
m_strProxyAddr = (strAddr ?? string.Empty); m_strProxyAddr = (strAddr ?? string.Empty);
m_strProxyPort = (strPort ?? string.Empty); m_strProxyPort = (strPort ?? string.Empty);
m_patProxyAuthType = pat;
m_strProxyUserName = (strUserName ?? string.Empty); m_strProxyUserName = (strUserName ?? string.Empty);
m_strProxyPassword = (strPassword ?? 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 if(request == null) { Debug.Assert(false); return; } // No throw
// WebDAV support IocProperties p = ((ioc != null) ? ioc.Properties : null);
if(request is HttpWebRequest) if(p == null) { Debug.Assert(false); p = new IocProperties(); }
{
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);
// }
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 // Not implemented and ignored in Mono < 2.10
try try
{ {
@ -106,6 +354,7 @@ namespace KeePassLib.Serialization
} }
catch(NotImplementedException) { } catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
#endif
try try
{ {
@ -113,10 +362,20 @@ namespace KeePassLib.Serialization
if(GetWebProxy(out prx)) request.Proxy = prx; if(GetWebProxy(out prx)) request.Proxy = prx;
} }
catch(Exception) { Debug.Assert(false); } 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) internal static void ConfigureWebClient(WebClient wc)
{ {
#if !KeePassUAP
// Not implemented and ignored in Mono < 2.10 // Not implemented and ignored in Mono < 2.10
try try
{ {
@ -124,6 +383,7 @@ namespace KeePassLib.Serialization
} }
catch(NotImplementedException) { } catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
#endif
try try
{ {
@ -134,64 +394,163 @@ namespace KeePassLib.Serialization
} }
private static bool GetWebProxy(out IWebProxy prx) 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; prx = null;
if(m_pstProxyType == ProxyServerType.None) if(m_pstProxyType == ProxyServerType.None)
return true; // Use null proxy return true; // Use null proxy
if(m_pstProxyType == ProxyServerType.Manual) if(m_pstProxyType == ProxyServerType.Manual)
{ {
try 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)); prx = new WebProxy(m_strProxyAddr, int.Parse(m_strProxyPort));
else prx = new WebProxy(m_strProxyAddr); else prx = new WebProxy(m_strProxyAddr);
if((m_strProxyUserName.Length > 0) || (m_strProxyPassword.Length > 0)) return (prx != null);
prx.Credentials = new NetworkCredential(m_strProxyUserName,
m_strProxyPassword);
return true; // Use manual proxy
} }
catch(Exception exProxy) #if KeePassUAP
catch(Exception) { Debug.Assert(false); }
#else
catch(Exception ex)
{ {
string strInfo = m_strProxyAddr; string strInfo = m_strProxyAddr;
if(m_strProxyPort.Length > 0) strInfo += ":" + m_strProxyPort; if(m_strProxyPort.Length > 0)
MessageService.ShowWarning(strInfo, exProxy.Message); strInfo += ":" + m_strProxyPort;
MessageService.ShowWarning(strInfo, ex.Message);
} }
#endif
return false; // Use default return false; // Use default
} }
if((m_strProxyUserName.Length == 0) && (m_strProxyPassword.Length == 0)) Debug.Assert(m_pstProxyType == ProxyServerType.System);
return false; // Use default proxy, no auth
try try
{ {
prx = WebRequest.DefaultWebProxy; // First try system, then default (from config)
if(prx == null) prx = WebRequest.GetSystemWebProxy(); #if !KeePassUAP
if(prx == null) throw new InvalidOperationException(); prx = WebRequest.GetSystemWebProxy();
#endif
if(prx == null) prx = WebRequest.DefaultWebProxy;
prx.Credentials = new NetworkCredential(m_strProxyUserName, return (prx != null);
m_strProxyPassword);
return true;
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
return false; return false;
} }
private static void PrepareWebAccess() private static void AssignCredentials(IWebProxy prx)
{ {
ServicePointManager.ServerCertificateValidationCallback = if(prx == null) return; // No assert
ValidateServerCertificate;
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) private static IOWebClient CreateWebClient(IOConnectionInfo ioc)
{ {
PrepareWebAccess(); PrepareWebAccess(ioc);
IOWebClient wc = new IOWebClient(); IOWebClient wc = new IOWebClient(ioc);
ConfigureWebClient(wc); ConfigureWebClient(wc);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
@ -204,10 +563,10 @@ namespace KeePassLib.Serialization
private static WebRequest CreateWebRequest(IOConnectionInfo ioc) private static WebRequest CreateWebRequest(IOConnectionInfo ioc)
{ {
PrepareWebAccess(); PrepareWebAccess(ioc);
WebRequest req = WebRequest.Create(ioc.Path); WebRequest req = WebRequest.Create(ioc.Path);
ConfigureWebRequest(req); ConfigureWebRequest(req, ioc);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password); req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
@ -219,6 +578,8 @@ namespace KeePassLib.Serialization
public static Stream OpenRead(IOConnectionInfo ioc) public static Stream OpenRead(IOConnectionInfo ioc)
{ {
RaiseIOAccessPreEvent(ioc, IOAccessType.Read);
if(StrUtil.IsDataUri(ioc.Path)) if(StrUtil.IsDataUri(ioc.Path))
{ {
byte[] pbData = StrUtil.DataUriToData(ioc.Path); byte[] pbData = StrUtil.DataUriToData(ioc.Path);
@ -227,11 +588,14 @@ namespace KeePassLib.Serialization
if(ioc.IsLocalFile()) return OpenReadLocal(ioc); 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 #else
public static Stream OpenRead(IOConnectionInfo ioc) public static Stream OpenRead(IOConnectionInfo ioc)
{ {
RaiseIOAccessPreEvent(ioc, IOAccessType.Read);
return OpenReadLocal(ioc); return OpenReadLocal(ioc);
} }
#endif #endif
@ -247,22 +611,26 @@ namespace KeePassLib.Serialization
{ {
if(ioc == null) { Debug.Assert(false); return null; } if(ioc == null) { Debug.Assert(false); return null; }
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
if(ioc.IsLocalFile()) return OpenWriteLocal(ioc); if(ioc.IsLocalFile()) return OpenWriteLocal(ioc);
Uri uri = new Uri(ioc.Path); Uri uri = new Uri(ioc.Path);
Stream s;
// Mono does not set HttpWebRequest.Method to POST for writes, // Mono does not set HttpWebRequest.Method to POST for writes,
// so one needs to set the method to PUT explicitly // so one needs to set the method to PUT explicitly
if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp, if(NativeLib.IsUnix() && IsHttpWebRequest(uri))
StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps, s = CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
StrUtil.CaseIgnoreCmp))) else s = CreateWebClient(ioc).OpenWrite(uri);
return CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
return CreateWebClient(ioc).OpenWrite(uri); return IocStream.WrapIfRequired(s);
} }
#else #else
public static Stream OpenWrite(IOConnectionInfo ioc) public static Stream OpenWrite(IOConnectionInfo ioc)
{ {
RaiseIOAccessPreEvent(ioc, IOAccessType.Write);
return OpenWriteLocal(ioc); return OpenWriteLocal(ioc);
} }
#endif #endif
@ -282,6 +650,8 @@ namespace KeePassLib.Serialization
{ {
if(ioc == null) { Debug.Assert(false); return false; } if(ioc == null) { Debug.Assert(false); return false; }
RaiseIOAccessPreEvent(ioc, IOAccessType.Exists);
if(ioc.IsLocalFile()) return File.Exists(ioc.Path); if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
#if !KeePassLibSD #if !KeePassLibSD
@ -317,15 +687,18 @@ namespace KeePassLib.Serialization
public static void DeleteFile(IOConnectionInfo ioc) public static void DeleteFile(IOConnectionInfo ioc)
{ {
RaiseIOAccessPreEvent(ioc, IOAccessType.Delete);
if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; } if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; }
#if !KeePassLibSD #if !KeePassLibSD
WebRequest req = CreateWebRequest(ioc); WebRequest req = CreateWebRequest(ioc);
if(req != null) if(req != null)
{ {
if(req is HttpWebRequest) req.Method = "DELETE"; if(IsHttpWebRequest(req)) req.Method = "DELETE";
else if(req is FtpWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile; else if(IsFtpWebRequest(req))
else if(req is FileWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile;
else if(IsFileWebRequest(req))
{ {
File.Delete(UrlUtil.FileUrlToPath(ioc.Path)); File.Delete(UrlUtil.FileUrlToPath(ioc.Path));
return; return;
@ -348,23 +721,39 @@ namespace KeePassLib.Serialization
/// <param name="iocTo">Target file path.</param> /// <param name="iocTo">Target file path.</param>
public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo) public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo)
{ {
RaiseIOAccessPreEvent(iocFrom, iocTo, IOAccessType.Move);
if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; } if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; }
#if !KeePassLibSD #if !KeePassLibSD
WebRequest req = CreateWebRequest(iocFrom); WebRequest req = CreateWebRequest(iocFrom);
if(req != null) if(req != null)
{ {
if(req is HttpWebRequest) if(IsHttpWebRequest(req))
{ {
#if KeePassUAP
throw new NotSupportedException();
#else
req.Method = "MOVE"; req.Method = "MOVE";
req.Headers.Set("Destination", iocTo.Path); // Full URL supported 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; 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), File.Move(UrlUtil.FileUrlToPath(iocFrom.Path),
UrlUtil.FileUrlToPath(iocTo.Path)); UrlUtil.FileUrlToPath(iocTo.Path));
@ -372,11 +761,17 @@ namespace KeePassLib.Serialization
} }
else else
{ {
#if KeePassUAP
throw new NotSupportedException();
#else
req.Method = WrmMoveFile; req.Method = WrmMoveFile;
req.Headers.Set(WrhMoveFileTo, iocTo.Path); req.Headers.Set(WrhMoveFileTo, iocTo.Path);
#endif
} }
#if !KeePassUAP // Unreachable code
DisposeResponse(req.GetResponse(), true); DisposeResponse(req.GetResponse(), true);
#endif
} }
#endif #endif
@ -408,7 +803,7 @@ namespace KeePassLib.Serialization
} }
#endif #endif
private static void DisposeResponse(WebResponse wr, bool bGetStream) internal static void DisposeResponse(WebResponse wr, bool bGetStream)
{ {
if(wr == null) return; if(wr == null) return;
@ -449,5 +844,67 @@ namespace KeePassLib.Serialization
return null; 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,11 +19,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Utility; using KeePassLib.Utility;
@ -119,22 +119,67 @@ namespace KeePassLib.Serialization
set { m_ioCredSaveMode = value; } 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 /* public IOFileFormatHint FileFormatHint
{ {
get { return m_ioHint; } get { return m_ioHint; }
set { m_ioHint = value; } 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() 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> /// <summary>
/// Serialize the current connection info to a string. Credentials /// Serialize the current connection info to a string. Credentials
/// are only serialized if the <c>SaveCredentials</c> property /// are serialized based on the <c>CredSaveMode</c> property.
/// is <c>true</c>.
/// </summary> /// </summary>
/// <param name="iocToCompile">Input object to be serialized.</param> /// <param name="iocToCompile">Input object to be serialized.</param>
/// <returns>Serialized object as string.</returns> /// <returns>Serialized object as string.</returns>
@ -146,31 +191,9 @@ namespace KeePassLib.Serialization
string strUrl = iocToCompile.Path; string strUrl = iocToCompile.Path;
string strUser = TransformUnreadable(iocToCompile.UserName, true); string strUser = TransformUnreadable(iocToCompile.UserName, true);
string strPassword = TransformUnreadable(iocToCompile.Password, 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(); if(chSep == char.MinValue) throw new FormatException();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -276,14 +299,14 @@ namespace KeePassLib.Serialization
string str = m_strUrl; string str = m_strUrl;
if(m_strUser.Length > 0) if(m_strUser.Length > 0)
str += " (" + m_strUser + ")"; str += (" (" + m_strUser + ")");
return str; return str;
} }
public bool IsEmpty() public bool IsEmpty()
{ {
return (m_strUrl.Length > 0); return (m_strUrl.Length == 0);
} }
public static IOConnectionInfo FromPath(string strPath) public static IOConnectionInfo FromPath(string strPath)
@ -306,7 +329,7 @@ namespace KeePassLib.Serialization
public bool IsLocalFile() public bool IsLocalFile()
{ {
// Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs // Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs
return (m_strUrl.IndexOf(@"://") < 0); return (m_strUrl.IndexOf("://") < 0);
} }
public void ClearCredentials(bool bDependingOnRememberMode) 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,18 +19,17 @@
using System; using System;
using System.Collections.Generic; 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.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
#if !KeePassUAP
using System.Drawing;
#endif
using KeePassLib; using KeePassLib;
using KeePassLib.Collections; using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Security; using KeePassLib.Security;
@ -100,11 +99,15 @@ namespace KeePassLib.Serialization
xrs.IgnoreProcessingInstructions = true; xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true; xrs.IgnoreWhitespace = true;
#if KeePassUAP
xrs.DtdProcessing = DtdProcessing.Prohibit;
#else
#if !KeePassLibSD #if !KeePassLibSD
xrs.ProhibitDtd = true; xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there
// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only
#endif #endif
xrs.ValidationType = ValidationType.None; xrs.ValidationType = ValidationType.None;
#endif
return xrs; return xrs;
} }
@ -451,10 +454,10 @@ namespace KeePassLib.Serialization
(ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry); (ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry);
Debug.Assert(tl != null); Debug.Assert(tl != null);
if(xr.Name == ElemLastModTime) if(xr.Name == ElemCreationTime)
tl.LastModificationTime = ReadTime(xr);
else if(xr.Name == ElemCreationTime)
tl.CreationTime = ReadTime(xr); tl.CreationTime = ReadTime(xr);
else if(xr.Name == ElemLastModTime)
tl.LastModificationTime = ReadTime(xr);
else if(xr.Name == ElemLastAccessTime) else if(xr.Name == ElemLastAccessTime)
tl.LastAccessTime = ReadTime(xr); tl.LastAccessTime = ReadTime(xr);
else if(xr.Name == ElemExpiryTime) else if(xr.Name == ElemExpiryTime)
@ -560,7 +563,8 @@ namespace KeePassLib.Serialization
return KdbContext.Meta; return KdbContext.Meta;
else if((ctx == KdbContext.CustomIcon) && (xr.Name == ElemCustomIconItem)) 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_pwDatabase.CustomIcons.Add(new PwCustomIcon(
m_uuidCustomIconID, m_pbCustomIconData)); m_uuidCustomIconID, m_pbCustomIconData));
else { Debug.Assert(false); } else { Debug.Assert(false); }
@ -587,7 +591,7 @@ namespace KeePassLib.Serialization
} }
else if((ctx == KdbContext.Group) && (xr.Name == ElemGroup)) 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_ctxGroup.Uuid = new PwUuid(true); // No assert (import)
m_ctxGroups.Pop(); m_ctxGroups.Pop();
@ -608,7 +612,7 @@ namespace KeePassLib.Serialization
else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry)) else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry))
{ {
// Create new UUID if absent // 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) m_ctxEntry.Uuid = new PwUuid(true); // No assert (import)
if(m_bEntryInHistory) if(m_bEntryInHistory)
@ -716,6 +720,9 @@ namespace KeePassLib.Serialization
string str = ReadString(xr); string str = ReadString(xr);
int n; int n;
if(StrUtil.TryParseIntInvariant(str, out n)) return n;
// Backward compatibility
if(StrUtil.TryParseInt(str, out n)) return n; if(StrUtil.TryParseInt(str, out n)) return n;
Debug.Assert(false); Debug.Assert(false);
@ -727,6 +734,9 @@ namespace KeePassLib.Serialization
string str = ReadString(xr); string str = ReadString(xr);
uint u; uint u;
if(StrUtil.TryParseUIntInvariant(str, out u)) return u;
// Backward compatibility
if(StrUtil.TryParseUInt(str, out u)) return u; if(StrUtil.TryParseUInt(str, out u)) return u;
Debug.Assert(false); Debug.Assert(false);
@ -738,6 +748,9 @@ namespace KeePassLib.Serialization
string str = ReadString(xr); string str = ReadString(xr);
long l; long l;
if(StrUtil.TryParseLongInvariant(str, out l)) return l;
// Backward compatibility
if(StrUtil.TryParseLong(str, out l)) return l; if(StrUtil.TryParseLong(str, out l)) return l;
Debug.Assert(false); Debug.Assert(false);
@ -749,6 +762,9 @@ namespace KeePassLib.Serialization
string str = ReadString(xr); string str = ReadString(xr);
ulong u; ulong u;
if(StrUtil.TryParseULongInvariant(str, out u)) return u;
// Backward compatibility
if(StrUtil.TryParseULong(str, out u)) return u; if(StrUtil.TryParseULong(str, out u)) return u;
Debug.Assert(false); Debug.Assert(false);
@ -793,7 +809,19 @@ namespace KeePassLib.Serialization
if(strRef != null) if(strRef != null)
{ {
ProtectedBinary pb = BinPoolGet(strRef); 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); }
} }
else { Debug.Assert(false); } else { Debug.Assert(false); }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,13 +19,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Security; using System.Security;
using System.Security.Cryptography; using System.Text;
using System.Xml; using System.Xml;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
#if !KeePassLibSD #if !KeePassLibSD
using System.IO.Compression; using System.IO.Compression;
#else #else
@ -127,6 +130,22 @@ namespace KeePassLib.Serialization
} }
else m_randomStream = null; // No random stream for plain-text files 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); ReadXmlStreamed(readerStream, hashedStream);
// ReadXmlDom(readerStream); // ReadXmlDom(readerStream);
@ -159,6 +178,12 @@ namespace KeePassLib.Serialization
// the history maintenance settings) // the history maintenance settings)
m_pwDatabase.MaintainBackups(); // Don't mark database as modified 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; m_pbHashOfHeader = null;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,20 +19,22 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics; using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Globalization; using System.Globalization;
using System.Drawing.Imaging; using System.IO;
using System.Security;
using System.Text;
using System.Xml;
#if !KeePassLibSD #if !KeePassUAP
using System.IO.Compression; using System.Drawing;
#else using System.Security.Cryptography;
#endif
#if KeePassLibSD
using KeePassLibSD; using KeePassLibSD;
#else
using System.IO.Compression;
#endif #endif
using KeePassLib.Collections; using KeePassLib.Collections;
@ -121,7 +123,24 @@ namespace KeePassLib.Serialization
writerStream = hashedStream; writerStream = hashedStream;
else { Debug.Assert(false); throw new FormatException("KdbFormat"); } 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); WriteDocument(pgDataSource);
m_xmlWriter.Flush(); m_xmlWriter.Flush();
@ -241,10 +260,6 @@ namespace KeePassLib.Serialization
BinPoolBuild(pgRoot); BinPoolBuild(pgRoot);
m_xmlWriter.Formatting = Formatting.Indented;
m_xmlWriter.IndentChar = '\t';
m_xmlWriter.Indentation = 1;
m_xmlWriter.WriteStartDocument(true); m_xmlWriter.WriteStartDocument(true);
m_xmlWriter.WriteStartElement(ElemDocNode); m_xmlWriter.WriteStartElement(ElemDocNode);
@ -363,7 +378,7 @@ namespace KeePassLib.Serialization
WriteObject(ElemNotes, pg.Notes, true); WriteObject(ElemNotes, pg.Notes, true);
WriteObject(ElemIcon, (int)pg.IconId); WriteObject(ElemIcon, (int)pg.IconId);
if(pg.CustomIconUuid != PwUuid.Zero) if(!pg.CustomIconUuid.Equals(PwUuid.Zero))
WriteObject(ElemCustomIconID, pg.CustomIconUuid); WriteObject(ElemCustomIconID, pg.CustomIconUuid);
WriteList(ElemTimes, pg); WriteList(ElemTimes, pg);
@ -388,7 +403,7 @@ namespace KeePassLib.Serialization
WriteObject(ElemUuid, pe.Uuid); WriteObject(ElemUuid, pe.Uuid);
WriteObject(ElemIcon, (int)pe.IconId); WriteObject(ElemIcon, (int)pe.IconId);
if(pe.CustomIconUuid != PwUuid.Zero) if(!pe.CustomIconUuid.Equals(PwUuid.Zero))
WriteObject(ElemCustomIconID, pe.CustomIconUuid); WriteObject(ElemCustomIconID, pe.CustomIconUuid);
WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false); WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false);
@ -454,8 +469,8 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteStartElement(name); m_xmlWriter.WriteStartElement(name);
WriteObject(ElemLastModTime, times.LastModificationTime);
WriteObject(ElemCreationTime, times.CreationTime); WriteObject(ElemCreationTime, times.CreationTime);
WriteObject(ElemLastModTime, times.LastModificationTime);
WriteObject(ElemLastAccessTime, times.LastAccessTime); WriteObject(ElemLastAccessTime, times.LastAccessTime);
WriteObject(ElemExpiryTime, times.ExpiryTime); WriteObject(ElemExpiryTime, times.ExpiryTime);
WriteObject(ElemExpires, times.Expires); WriteObject(ElemExpires, times.Expires);
@ -577,7 +592,7 @@ namespace KeePassLib.Serialization
Debug.Assert(name != null); Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name); m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString()); m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo));
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
} }
@ -586,7 +601,7 @@ namespace KeePassLib.Serialization
Debug.Assert(name != null); Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name); m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString()); m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo));
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
} }
@ -595,7 +610,7 @@ namespace KeePassLib.Serialization
Debug.Assert(name != null); Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name); m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString()); m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo));
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
} }
@ -604,7 +619,7 @@ namespace KeePassLib.Serialization
Debug.Assert(name != null); Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name); m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString()); m_xmlWriter.WriteString(value.ToString(NumberFormatInfo.InvariantInfo));
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
} }
@ -686,7 +701,8 @@ namespace KeePassLib.Serialization
// page area // page area
if(char.IsSymbol(ch) || char.IsSurrogate(ch)) 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 // Map character to correct position in code page
chMapped = (char)((int)cat * 32 + ch); chMapped = (char)((int)cat * 32 + ch);
} }
@ -698,7 +714,11 @@ namespace KeePassLib.Serialization
// in the low ANSI range (up to 255) when calling // in the low ANSI range (up to 255) when calling
// ToLower on them with invariant culture (see // ToLower on them with invariant culture (see
// http://lists.ximian.com/pipermail/mono-patches/2002-February/086106.html ) // 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,15 +19,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Xml; using System.Diagnostics;
using System.Text;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Diagnostics; using System.Text;
using System.Xml;
#if !KeePassLibSD
using System.IO.Compression;
#endif
using KeePassLib.Collections; using KeePassLib.Collections;
using KeePassLib.Cryptography; using KeePassLib.Cryptography;
@ -63,12 +59,12 @@ namespace KeePassLib.Serialization
/// <summary> /// <summary>
/// File identifier, first 32-bit value. /// File identifier, first 32-bit value.
/// </summary> /// </summary>
private const uint FileSignature1 = 0x9AA2D903; internal const uint FileSignature1 = 0x9AA2D903;
/// <summary> /// <summary>
/// File identifier, second 32-bit value. /// File identifier, second 32-bit value.
/// </summary> /// </summary>
private const uint FileSignature2 = 0xB54BFB67; internal const uint FileSignature2 = 0xB54BFB67;
/// <summary> /// <summary>
/// File version of files saved by the current <c>KdbxFile</c> class. /// File version of files saved by the current <c>KdbxFile</c> class.
@ -82,11 +78,11 @@ namespace KeePassLib.Serialization
private const uint FileVersionCriticalMask = 0xFFFF0000; private const uint FileVersionCriticalMask = 0xFFFF0000;
// KeePass 1.x signature // KeePass 1.x signature
private const uint FileSignatureOld1 = 0x9AA2D903; internal const uint FileSignatureOld1 = 0x9AA2D903;
private const uint FileSignatureOld2 = 0xB54BFB65; internal const uint FileSignatureOld2 = 0xB54BFB65;
// KeePass 2.x pre-release (alpha and beta) signature // KeePass 2.x pre-release (alpha and beta) signature
private const uint FileSignaturePreRelease1 = 0x9AA2D903; internal const uint FileSignaturePreRelease1 = 0x9AA2D903;
private const uint FileSignaturePreRelease2 = 0xB54BFB66; internal const uint FileSignaturePreRelease2 = 0xB54BFB66;
private const string ElemDocNode = "KeePassFile"; private const string ElemDocNode = "KeePassFile";
private const string ElemMeta = "Meta"; private const string ElemMeta = "Meta";
@ -191,7 +187,7 @@ namespace KeePassLib.Serialization
private PwDatabase m_pwDatabase; // Not null, see constructor private PwDatabase m_pwDatabase; // Not null, see constructor
private XmlTextWriter m_xmlWriter = null; private XmlWriter m_xmlWriter = null;
private CryptoRandomStream m_randomStream = null; private CryptoRandomStream m_randomStream = null;
private KdbxFormat m_format = KdbxFormat.Default; private KdbxFormat m_format = KdbxFormat.Default;
private IStatusLogger m_slLogger = null; private IStatusLogger m_slLogger = null;
@ -324,7 +320,8 @@ namespace KeePassLib.Serialization
if(BinPoolFind(pb) != null) return; // Exists already 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) private string BinPoolFind(ProtectedBinary pb)
@ -366,7 +363,9 @@ namespace KeePassLib.Serialization
string strDesc = UrlUtil.StripExtension(strName); string strDesc = UrlUtil.StripExtension(strName);
strPath += strDesc; strPath += strDesc;
if(iTry > 1) strPath += " (" + iTry.ToString() + ")"; if(iTry > 1)
strPath += " (" + iTry.ToString(NumberFormatInfo.InvariantInfo) +
")";
if(!string.IsNullOrEmpty(strExt)) strPath += "." + strExt; if(!string.IsNullOrEmpty(strExt)) strPath += "." + strExt;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,15 +19,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.ComponentModel; using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics; using System.Diagnostics;
using System.Xml.Serialization;
using System.Globalization; using System.Globalization;
using System.IO; using System.Text;
using System.Security.Cryptography; using System.Xml.Serialization;
#if !KeePassUAP
using System.Drawing; using System.Drawing;
using System.Security.Cryptography;
using System.Windows.Forms;
#endif
using KeePassLib.Utility; using KeePassLib.Utility;
@ -42,8 +44,8 @@ namespace KeePassLib.Translation
private const string m_strControlRelative = @"%c"; private const string m_strControlRelative = @"%c";
internal const NumberStyles m_nsParser = NumberStyles.AllowLeadingSign | internal const NumberStyles m_nsParser = (NumberStyles.AllowLeadingSign |
NumberStyles.AllowDecimalPoint; NumberStyles.AllowDecimalPoint);
internal static readonly CultureInfo m_lclInv = CultureInfo.InvariantCulture; internal static readonly CultureInfo m_lclInv = CultureInfo.InvariantCulture;
private string m_strPosX = string.Empty; private string m_strPosX = string.Empty;
@ -112,7 +114,7 @@ namespace KeePassLib.Translation
else { Debug.Assert(false); } else { Debug.Assert(false); }
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
internal void ApplyTo(Control c) internal void ApplyTo(Control c)
{ {
Debug.Assert(c != null); if(c == null) return; Debug.Assert(c != null); if(c == null) return;
@ -267,7 +269,7 @@ namespace KeePassLib.Translation
return m_strMemberName.CompareTo(kpOther.Name); return m_strMemberName.CompareTo(kpOther.Name);
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
private static readonly Type[] m_vTextControls = new Type[] { private static readonly Type[] m_vTextControls = new Type[] {
typeof(MenuStrip), typeof(PictureBox), typeof(ListView), typeof(MenuStrip), typeof(PictureBox), typeof(ListView),
typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser), typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser),
@ -309,8 +311,8 @@ namespace KeePassLib.Translation
if(c is Form) if(c is Form)
{ {
WriteCpiParam(sb, c.ClientSize.Width.ToString()); WriteCpiParam(sb, c.ClientSize.Width.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.ClientSize.Height.ToString()); WriteCpiParam(sb, c.ClientSize.Height.ToString(KpccLayout.m_lclInv));
} }
else // Normal control else // Normal control
{ {

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,11 +19,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Text;
using System.Xml.Serialization;
#if !KeePassUAP
using System.Windows.Forms;
#endif
namespace KeePassLib.Translation namespace KeePassLib.Translation
{ {
@ -66,6 +68,7 @@ namespace KeePassLib.Translation
} }
} }
#if (!KeePassLibSD && !KeePassUAP)
private Form m_formEnglish = null; private Form m_formEnglish = null;
[XmlIgnore] [XmlIgnore]
public Form FormEnglish public Form FormEnglish
@ -74,7 +77,6 @@ namespace KeePassLib.Translation
set { m_formEnglish = value; } set { m_formEnglish = value; }
} }
#if !KeePassLibSD
public void ApplyTo(Form form) public void ApplyTo(Form form)
{ {
Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("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 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 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
#if !KeePassUAP
using System.Windows.Forms; using System.Windows.Forms;
using System.Diagnostics; #endif
namespace KeePassLib.Translation namespace KeePassLib.Translation
{ {
@ -66,7 +69,7 @@ namespace KeePassLib.Translation
return dict; return dict;
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
public void ApplyTo(ToolStripItemCollection tsic) public void ApplyTo(ToolStripItemCollection tsic)
{ {
if(tsic == null) throw new ArgumentNullException("tsic"); if(tsic == null) throw new ArgumentNullException("tsic");

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,24 +19,27 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.ComponentModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Text;
using System.Xml; using System.Xml;
using System.Xml.Serialization; using System.Xml.Serialization;
using System.Windows.Forms;
using System.ComponentModel; #if !KeePassUAP
using System.Drawing; 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.Interfaces;
using KeePassLib.Utility; using KeePassLib.Utility;
#if !KeePassLibSD
using System.IO.Compression;
#else
using ICSharpCode.SharpZipLib.GZip;
#endif
namespace KeePassLib.Translation namespace KeePassLib.Translation
{ {
[XmlRoot("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) IXmlSerializerEx xs)
{ {
if(xs == null) throw new ArgumentNullException("xs"); if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
#if !KeePassLibSD #if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Compress); GZipStream gz = new GZipStream(sOut, CompressionMode.Compress);
#else #else
GZipOutputStream gz = new GZipOutputStream(fs); GZipOutputStream gz = new GZipOutputStream(sOut);
#endif #endif
XmlWriterSettings xws = new XmlWriterSettings(); XmlWriterSettings xws = new XmlWriterSettings();
@ -118,27 +128,36 @@ namespace KeePassLib.Translation
xw.Close(); xw.Close();
gz.Close(); gz.Close();
fs.Close(); sOut.Close();
} }
public static KPTranslation LoadFromFile(string strFile, public static KPTranslation Load(string strFile, IXmlSerializerEx xs)
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"); if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFile, FileMode.Open,
FileAccess.Read, FileShare.Read);
#if !KeePassLibSD #if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Decompress); GZipStream gz = new GZipStream(s, CompressionMode.Decompress);
#else #else
GZipInputStream gz = new GZipInputStream(fs); GZipInputStream gz = new GZipInputStream(s);
#endif #endif
KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation); KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation);
gz.Close(); gz.Close();
fs.Close(); s.Close();
return kpTrl; return kpTrl;
} }
@ -153,7 +172,7 @@ namespace KeePassLib.Translation
return new Dictionary<string, string>(); return new Dictionary<string, string>();
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
public void ApplyTo(Form form) public void ApplyTo(Form form)
{ {
if(form == null) throw new ArgumentNullException("form"); if(form == null) throw new ArgumentNullException("form");

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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 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 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 it under the terms of the GNU General Public License as published by
@ -19,9 +19,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
#if !KeePassLibSD #if !KeePassLibSD
using System.IO.Compression; using System.IO.Compression;
@ -38,8 +38,7 @@ namespace KeePassLib.Utility
public static void Open(string strPrefix) 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(); AppLogEx.Close();
@ -49,7 +48,7 @@ namespace KeePassLib.Utility
try try
{ {
string strDirSep = string.Empty; string strDirSep = string.Empty;
strDirSep += Path.DirectorySeparatorChar; strDirSep += UrlUtil.LocalDirSepChar;
string strTemp = UrlUtil.GetTempPath(); string strTemp = UrlUtil.GetTempPath();
if(!strTemp.EndsWith(strDirSep)) if(!strTemp.EndsWith(strDirSep))
@ -64,7 +63,7 @@ namespace KeePassLib.Utility
strTime = strTime.Replace(':', '-'); strTime = strTime.Replace(':', '-');
strPath += strTime + "-" + Environment.TickCount.ToString( strPath += strTime + "-" + Environment.TickCount.ToString(
CultureInfo.InvariantCulture) + ".log.gz"; NumberFormatInfo.InvariantInfo) + ".log.gz";
FileStream fsOut = new FileStream(strPath, FileMode.Create, FileStream fsOut = new FileStream(strPath, FileMode.Create,
FileAccess.Write, FileShare.None); FileAccess.Write, FileShare.None);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 it under the terms of the GNU General Public License as published by
@ -19,28 +19,74 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics; 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 namespace KeePassLib.Utility
{ {
public static class GfxUtil 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) public static Image LoadImage(byte[] pb)
{ {
if(pb == null) throw new ArgumentNullException("pb"); if(pb == null) throw new ArgumentNullException("pb");
MemoryStream ms = new MemoryStream(pb, false); MemoryStream ms = new MemoryStream(pb, false);
try { return LoadImagePriv(ms); } try { return Image.FromStream(ms); }
catch(Exception) 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; 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(); } finally { ms.Close(); }
} }
@ -72,7 +118,12 @@ namespace KeePassLib.Utility
using(Graphics g = Graphics.FromImage(bmp)) using(Graphics g = Graphics.FromImage(bmp))
{ {
g.Clear(Color.Transparent); g.Clear(Color.Transparent);
#if !KeePassLibSD
g.DrawImageUnscaled(imgSrc, 0, 0);
#else
g.DrawImage(imgSrc, 0, 0); g.DrawImage(imgSrc, 0, 0);
#endif
} }
return bmp; return bmp;
@ -80,16 +131,299 @@ namespace KeePassLib.Utility
finally { if(imgSrc != null) imgSrc.Dispose(); } finally { if(imgSrc != null) imgSrc.Dispose(); }
} }
private static Image TryLoadIco(byte[] pb)
{
#if !KeePassLibSD #if !KeePassLibSD
MemoryStream ms = new MemoryStream(pb, false); private static Image ExtractBestImageFromIco(byte[] pb)
try { return (new Icon(ms)).ToBitmap(); } {
catch(Exception) { } List<GfxImage> l = UnpackIco(pb);
finally { ms.Close(); } if((l == null) || (l.Count == 0)) return null;
#endif
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 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 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 it under the terms of the GNU General Public License as published by
@ -18,15 +18,16 @@
*/ */
using System; using System;
using System.Text; using System.Collections.Generic;
using System.Security.Cryptography;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
#if !KeePassLibSD #if KeePassLibSD
using System.IO.Compression;
#else
using KeePassLibSD; using KeePassLibSD;
#else
using System.IO.Compression;
#endif #endif
namespace KeePassLib.Utility namespace KeePassLib.Utility
@ -36,6 +37,73 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
public static class MemUtil 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> /// <summary>
/// Convert a hexadecimal string to a byte array. The input string must be /// Convert a hexadecimal string to a byte array. The input string must be
/// even (i.e. its length is a multiple of 2). /// even (i.e. its length is a multiple of 2).
@ -119,27 +187,84 @@ namespace KeePassLib.Utility
return sb.ToString(); 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> /// <summary>
/// Set all bytes in a byte array to zero. /// Set all bytes in a byte array to zero.
/// </summary> /// </summary>
/// <param name="pbArray">Input array. All bytes of this array will be set /// <param name="pbArray">Input array. All bytes of this array
/// to zero.</param> /// will be set to zero.</param>
#if KeePassLibSD
[MethodImpl(MethodImplOptions.NoInlining)]
#else
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
#endif
public static void ZeroByteArray(byte[] pbArray) public static void ZeroByteArray(byte[] pbArray)
{ {
Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray"); Debug.Assert(pbArray != null);
if(pbArray == null) throw new ArgumentNullException("pbArray");
// for(int i = 0; i < pbArray.Length; ++i)
// pbArray[i] = 0;
Array.Clear(pbArray, 0, pbArray.Length); Array.Clear(pbArray, 0, pbArray.Length);
} }
/// <summary> /// <summary>
/// Convert 2 bytes to a 16-bit unsigned integer using Little-Endian /// Convert 2 bytes to a 16-bit unsigned integer (little-endian).
/// encoding.
/// </summary> /// </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) public static ushort BytesToUInt16(byte[] pb)
{ {
Debug.Assert((pb != null) && (pb.Length == 2)); Debug.Assert((pb != null) && (pb.Length == 2));
@ -150,44 +275,35 @@ namespace KeePassLib.Utility
} }
/// <summary> /// <summary>
/// Convert 4 bytes to a 32-bit unsigned integer using Little-Endian /// Convert 4 bytes to a 32-bit unsigned integer (little-endian).
/// encoding.
/// </summary> /// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>32-bit unsigned integer.</returns>
public static uint BytesToUInt32(byte[] pb) public static uint BytesToUInt32(byte[] pb)
{ {
Debug.Assert((pb != null) && (pb.Length == 4)); Debug.Assert((pb != null) && (pb.Length == 4));
if(pb == null) throw new ArgumentNullException("pb"); 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) | return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) |
((uint)pb[3] << 24); ((uint)pb[3] << 24));
} }
/// <summary> /// <summary>
/// Convert 8 bytes to a 64-bit unsigned integer using Little-Endian /// Convert 8 bytes to a 64-bit unsigned integer (little-endian).
/// encoding.
/// </summary> /// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>64-bit unsigned integer.</returns>
public static ulong BytesToUInt64(byte[] pb) public static ulong BytesToUInt64(byte[] pb)
{ {
Debug.Assert((pb != null) && (pb.Length == 8)); Debug.Assert((pb != null) && (pb.Length == 8));
if(pb == null) throw new ArgumentNullException("pb"); if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 8) throw new ArgumentException(); 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[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> /// <summary>
/// Convert a 16-bit unsigned integer to 2 bytes using Little-Endian /// Convert a 16-bit unsigned integer to 2 bytes (little-endian).
/// encoding.
/// </summary> /// </summary>
/// <param name="uValue">16-bit input word.</param>
/// <returns>Two bytes representing the 16-bit value.</returns>
public static byte[] UInt16ToBytes(ushort uValue) public static byte[] UInt16ToBytes(ushort uValue)
{ {
byte[] pb = new byte[2]; byte[] pb = new byte[2];
@ -202,11 +318,8 @@ namespace KeePassLib.Utility
} }
/// <summary> /// <summary>
/// Convert a 32-bit unsigned integer to 4 bytes using Little-Endian /// Convert a 32-bit unsigned integer to 4 bytes (little-endian).
/// encoding.
/// </summary> /// </summary>
/// <param name="uValue">32-bit input word.</param>
/// <returns>Four bytes representing the 32-bit value.</returns>
public static byte[] UInt32ToBytes(uint uValue) public static byte[] UInt32ToBytes(uint uValue)
{ {
byte[] pb = new byte[4]; byte[] pb = new byte[4];
@ -223,11 +336,8 @@ namespace KeePassLib.Utility
} }
/// <summary> /// <summary>
/// Convert a 64-bit unsigned integer to 8 bytes using Little-Endian /// Convert a 64-bit unsigned integer to 8 bytes (little-endian).
/// encoding.
/// </summary> /// </summary>
/// <param name="uValue">64-bit input word.</param>
/// <returns>Eight bytes representing the 64-bit value.</returns>
public static byte[] UInt64ToBytes(ulong uValue) public static byte[] UInt64ToBytes(ulong uValue)
{ {
byte[] pb = new byte[8]; byte[] pb = new byte[8];
@ -277,6 +387,31 @@ namespace KeePassLib.Utility
pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i]; pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i];
} }
/// <summary>
/// Fast hash that can be used e.g. for hash tables.
/// The algorithm might change in the future; do not store
/// the hashes for later use.
/// </summary>
public static uint Hash32(byte[] v, int iStart, int iLength)
{
uint u = 0x326F637B;
if(v == null) { Debug.Assert(false); return u; }
if(iStart < 0) { Debug.Assert(false); return u; }
if(iLength < 0) { Debug.Assert(false); return u; }
int m = iStart + iLength;
if(m > v.Length) { Debug.Assert(false); return u; }
for(int i = iStart; i < m; ++i)
{
u ^= m_vSBox[v[i]];
u *= 3;
}
return u;
}
public static void CopyStream(Stream sSource, Stream sTarget) public static void CopyStream(Stream sSource, Stream sTarget)
{ {
Debug.Assert((sSource != null) && (sTarget != null)); Debug.Assert((sSource != null) && (sTarget != null));
@ -336,15 +471,21 @@ namespace KeePassLib.Utility
if(pbData == null) throw new ArgumentNullException("pbData"); if(pbData == null) throw new ArgumentNullException("pbData");
if(pbData.Length == 0) return pbData; if(pbData.Length == 0) return pbData;
MemoryStream msCompressed = new MemoryStream(); byte[] pbCompressed;
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress); using(MemoryStream msSource = new MemoryStream(pbData, false))
MemoryStream msSource = new MemoryStream(pbData, false); {
MemUtil.CopyStream(msSource, gz); using(MemoryStream msCompressed = new MemoryStream())
gz.Close(); {
msSource.Close(); using(GZipStream gz = new GZipStream(msCompressed,
CompressionMode.Compress))
{
MemUtil.CopyStream(msSource, gz);
}
pbCompressed = msCompressed.ToArray();
}
}
byte[] pbCompressed = msCompressed.ToArray();
msCompressed.Close();
return pbCompressed; return pbCompressed;
} }
@ -353,15 +494,21 @@ namespace KeePassLib.Utility
if(pbCompressed == null) throw new ArgumentNullException("pbCompressed"); if(pbCompressed == null) throw new ArgumentNullException("pbCompressed");
if(pbCompressed.Length == 0) return pbCompressed; if(pbCompressed.Length == 0) return pbCompressed;
MemoryStream msCompressed = new MemoryStream(pbCompressed, false); byte[] pbData;
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress); using(MemoryStream msData = new MemoryStream())
MemoryStream msData = new MemoryStream(); {
MemUtil.CopyStream(gz, msData); using(MemoryStream msCompressed = new MemoryStream(pbCompressed, false))
gz.Close(); {
msCompressed.Close(); using(GZipStream gz = new GZipStream(msCompressed,
CompressionMode.Decompress))
{
MemUtil.CopyStream(gz, msData);
}
}
pbData = msData.ToArray();
}
byte[] pbData = msData.ToArray();
msData.Close();
return pbData; return pbData;
} }
@ -394,11 +541,81 @@ namespace KeePassLib.Utility
if(v == null) throw new ArgumentNullException("v"); if(v == null) throw new ArgumentNullException("v");
if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset");
if(iLength < 0) throw new ArgumentOutOfRangeException("iLength"); 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]; T[] r = new T[iLength];
Array.Copy(v, iOffset, r, 0, iLength); Array.Copy(v, iOffset, r, 0, iLength);
return r; 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 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 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 it under the terms of the GNU General Public License as published by
@ -20,9 +20,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
#if !KeePassUAP
using System.Windows.Forms;
#endif
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Serialization; using KeePassLib.Serialization;
@ -94,7 +97,9 @@ namespace KeePassLib.Utility
get { return m_uCurrentMessageCount; } get { return m_uCurrentMessageCount; }
} }
#if !KeePassUAP
public static event EventHandler<MessageServiceEventArgs> MessageShowing; public static event EventHandler<MessageServiceEventArgs> MessageShowing;
#endif
private static string ObjectsToMessage(object[] vLines) private static string ObjectsToMessage(object[] vLines)
{ {
@ -158,7 +163,7 @@ namespace KeePassLib.Utility
return sbText.ToString(); return sbText.ToString();
} }
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
internal static Form GetTopForm() internal static Form GetTopForm()
{ {
FormCollection fc = Application.OpenForms; FormCollection fc = Application.OpenForms;
@ -168,7 +173,8 @@ namespace KeePassLib.Utility
} }
#endif #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) MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{ {
#if KeePassLibSD #if KeePassLibSD
@ -283,11 +289,13 @@ namespace KeePassLib.Utility
try try
{ {
#if !KeePassLibSD string strDetails = ObjectsToMessage(vLines, true);
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true)); #if KeePassLibSD
Clipboard.SetDataObject(strDetails);
#else #else
Clipboard.SetDataObject(ObjectsToMessage(vLines, true)); Clipboard.Clear();
Clipboard.SetText(strDetails);
#endif #endif
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
@ -321,7 +329,8 @@ namespace KeePassLib.Utility
return dr; 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; ++m_uCurrentMessageCount;
@ -330,24 +339,29 @@ namespace KeePassLib.Utility
if(MessageService.MessageShowing != null) if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, m_mbiQuestion)); strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, m_mbiQuestion, bDefaultToYes ? MessageBoxButtons.YesNo, mbi, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2); MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount; --m_uCurrentMessageCount;
return (dr == DialogResult.Yes); 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) 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) 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) public static void ShowLoadWarning(string strFilePath, Exception ex)
@ -358,21 +372,7 @@ namespace KeePassLib.Utility
public static void ShowLoadWarning(string strFilePath, Exception ex, public static void ShowLoadWarning(string strFilePath, Exception ex,
bool bFullException) bool bFullException)
{ {
string str = string.Empty; ShowWarning(GetLoadWarningMessage(strFilePath, ex, bFullException));
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);
} }
public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex) public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
@ -392,18 +392,7 @@ namespace KeePassLib.Utility
return; return;
} }
string str = string.Empty; string str = GetSaveWarningMessage(strFilePath, ex, bCorruptionWarning);
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;
ShowWarning(str); ShowWarning(str);
} }
@ -414,6 +403,45 @@ namespace KeePassLib.Utility
ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning); ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
else ShowWarning(ex); 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() public static void ExternalIncrementMessageCount()
{ {

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager 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 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 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Globalization;
using System.Drawing;
using System.IO; using System.IO;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
#if !KeePassUAP
using System.Drawing;
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
using KeePassLib.Collections; using KeePassLib.Collections;
using KeePassLib.Cryptography.PasswordGenerator;
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Resources;
namespace KeePassLib.Utility namespace KeePassLib.Utility
{ {
@ -212,41 +216,47 @@ namespace KeePassLib.Utility
{ {
get get
{ {
if(m_lEncs == null) if(m_lEncs != null) return m_lEncs;
{
m_lEncs = new List<StrEncodingInfo>();
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Default, List<StrEncodingInfo> l = new List<StrEncodingInfo>();
#if !KeePassLibSD
Encoding.Default.EncodingName, l.Add(new StrEncodingInfo(StrEncodingType.Default,
#if KeePassUAP
"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF }));
#else #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 #if !KeePassLibSD
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32LE, Encoding.Default.EncodingName,
"Unicode (UTF-32 LE)", new UTF32Encoding(false, false), #else
4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 })); Encoding.Default.WebName,
m_lEncs.Add(new StrEncodingInfo(StrEncodingType.Utf32BE, #endif
"Unicode (UTF-32 BE)", new UTF32Encoding(true, false), Encoding.Default,
4, new byte[] { 0x0, 0x0, 0xFE, 0xFF })); (uint)Encoding.Default.GetBytes("a").Length, null));
#endif #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]; // char ch = str[i];
// if((int)ch >= 256) // if((int)ch >= 256)
// { // sbEncoded.Append(StrUtil.RtfEncodeChar(ch));
// sbEncoded.Append("\\u");
// sbEncoded.Append((int)ch);
// sbEncoded.Append('?');
// }
// else sbEncoded.Append(ch); // else sbEncoded.Append(ch);
// } // }
// return sbEncoded.ToString(); // 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> /// <summary>
/// Convert a string into a valid HTML sequence representing that string. /// Convert a string into a valid HTML sequence representing that string.
/// </summary> /// </summary>
@ -300,7 +315,7 @@ namespace KeePassLib.Utility
str = str.Replace("\'", @"&#39;"); str = str.Replace("\'", @"&#39;");
str = NormalizeNewLines(str, false); str = NormalizeNewLines(str, false);
str = str.Replace("\n", @"<br />"); str = str.Replace("\n", @"<br />" + MessageService.NewLine);
return str; return str;
} }
@ -343,9 +358,9 @@ namespace KeePassLib.Utility
} }
/// <summary> /// <summary>
/// Split up a command-line into application and argument. /// Split up a command line into application and argument.
/// </summary> /// </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="strApp">Application path.</param>
/// <param name="strArgs">Arguments.</param> /// <param name="strArgs">Arguments.</param>
public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs) public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs)
@ -482,8 +497,10 @@ namespace KeePassLib.Utility
if(excp.StackTrace != null) if(excp.StackTrace != null)
strText += excp.StackTrace + MessageService.NewLine; strText += excp.StackTrace + MessageService.NewLine;
#if !KeePassLibSD #if !KeePassLibSD
#if !KeePassUAP
if(excp.TargetSite != null) if(excp.TargetSite != null)
strText += excp.TargetSite.ToString() + MessageService.NewLine; strText += excp.TargetSite.ToString() + MessageService.NewLine;
#endif
if(excp.Data != null) if(excp.Data != null)
{ {
@ -506,8 +523,10 @@ namespace KeePassLib.Utility
if(excp.InnerException.StackTrace != null) if(excp.InnerException.StackTrace != null)
strText += excp.InnerException.StackTrace + MessageService.NewLine; strText += excp.InnerException.StackTrace + MessageService.NewLine;
#if !KeePassLibSD #if !KeePassLibSD
#if !KeePassUAP
if(excp.InnerException.TargetSite != null) if(excp.InnerException.TargetSite != null)
strText += excp.InnerException.TargetSite.ToString(); strText += excp.InnerException.TargetSite.ToString();
#endif
if(excp.InnerException.Data != null) if(excp.InnerException.Data != null)
{ {
@ -538,7 +557,25 @@ namespace KeePassLib.Utility
return int.TryParse(str, out n); return int.TryParse(str, out n);
#else #else
try { n = int.Parse(str); return true; } 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 #endif
} }
@ -548,7 +585,25 @@ namespace KeePassLib.Utility
return uint.TryParse(str, out u); return uint.TryParse(str, out u);
#else #else
try { u = uint.Parse(str); return true; } 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 #endif
} }
@ -558,7 +613,25 @@ namespace KeePassLib.Utility
return long.TryParse(str, out n); return long.TryParse(str, out n);
#else #else
try { n = long.Parse(str); return true; } 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 #endif
} }
@ -568,7 +641,25 @@ namespace KeePassLib.Utility
return ulong.TryParse(str, out u); return ulong.TryParse(str, out u);
#else #else
try { u = ulong.Parse(str); return true; } 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 #endif
} }
@ -636,25 +727,40 @@ namespace KeePassLib.Utility
Debug.Assert(strText != null); // No throw Debug.Assert(strText != null); // No throw
if(string.IsNullOrEmpty(strText)) return strText; if(string.IsNullOrEmpty(strText)) return strText;
char[] vChars = strText.ToCharArray(); int nLength = strText.Length;
StringBuilder sb = new StringBuilder(strText.Length, strText.Length); StringBuilder sb = new StringBuilder(nLength);
char ch;
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)) || if(((ch >= '\u0020') && (ch <= '\uD7FF')) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD) || (ch == '\u0009') || (ch == '\u000A') || (ch == '\u000D') ||
((ch >= 0xE000) && (ch <= 0xFFFD))) ((ch >= '\uE000') && (ch <= '\uFFFD')))
sb.Append(ch); 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(); return sb.ToString();
} }
private static Regex m_rxNaturalSplit = null; /* private static Regex g_rxNaturalSplit = null;
public static int CompareNaturally(string strX, string strY) public static int CompareNaturally(string strX, string strY)
{ {
Debug.Assert(strX != null); Debug.Assert(strX != null);
@ -665,34 +771,31 @@ namespace KeePassLib.Utility
if(NativeMethods.SupportsStrCmpNaturally) if(NativeMethods.SupportsStrCmpNaturally)
return NativeMethods.StrCmpNaturally(strX, strY); return NativeMethods.StrCmpNaturally(strX, strY);
strX = strX.ToLower(); // Case-insensitive comparison if(g_rxNaturalSplit == null)
strY = strY.ToLower(); g_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled);
if(m_rxNaturalSplit == null) string[] vPartsX = g_rxNaturalSplit.Split(strX);
m_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled); string[] vPartsY = g_rxNaturalSplit.Split(strY);
string[] vPartsX = m_rxNaturalSplit.Split(strX); int n = Math.Min(vPartsX.Length, vPartsY.Length);
string[] vPartsY = m_rxNaturalSplit.Split(strY); for(int i = 0; i < n; ++i)
for(int i = 0; i < Math.Min(vPartsX.Length, vPartsY.Length); ++i)
{ {
string strPartX = vPartsX[i], strPartY = vPartsY[i]; string strPartX = vPartsX[i], strPartY = vPartsY[i];
int iPartCompare; int iPartCompare;
#if KeePassLibSD #if KeePassLibSD
ulong uX = 0, uY = 0;
try try
{ {
uX = ulong.Parse(strPartX); ulong uX = ulong.Parse(strPartX);
uY = ulong.Parse(strPartY); ulong uY = ulong.Parse(strPartY);
iPartCompare = uX.CompareTo(uY); iPartCompare = uX.CompareTo(uY);
} }
catch(Exception) { iPartCompare = strPartX.CompareTo(strPartY); } catch(Exception) { iPartCompare = string.Compare(strPartX, strPartY, true); }
#else #else
ulong uX, uY; ulong uX, uY;
if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY)) if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY))
iPartCompare = uX.CompareTo(uY); iPartCompare = uX.CompareTo(uY);
else iPartCompare = strPartX.CompareTo(strPartY); else iPartCompare = string.Compare(strPartX, strPartY, true);
#endif #endif
if(iPartCompare != 0) return iPartCompare; 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 0;
if(vPartsX.Length < vPartsY.Length) return -1; if(vPartsX.Length < vPartsY.Length) return -1;
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) public static string RemoveAccelerator(string strMenuText)
@ -724,6 +927,54 @@ namespace KeePassLib.Utility
return str; 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) public static bool IsHexString(string str, bool bStrict)
{ {
if(str == null) throw new ArgumentNullException("str"); 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) public static string AlphaNumericOnly(string str)
{ {
if(string.IsNullOrEmpty(str)) return str; if(string.IsNullOrEmpty(str)) return str;
@ -949,37 +1230,44 @@ namespace KeePassLib.Utility
public static string VersionToString(ulong uVersion) public static string VersionToString(ulong uVersion)
{ {
return VersionToString(uVersion, false); return VersionToString(uVersion, 1U);
} }
[Obsolete]
public static string VersionToString(ulong uVersion, public static string VersionToString(ulong uVersion,
bool bEnsureAtLeastTwoComp) bool bEnsureAtLeastTwoComp)
{ {
string str = string.Empty; return VersionToString(uVersion, (bEnsureAtLeastTwoComp ? 2U : 1U));
bool bMultiComp = false; }
public static string VersionToString(ulong uVersion, uint uMinComp)
{
StringBuilder sb = new StringBuilder();
uint uComp = 0;
for(int i = 0; i < 4; ++i) for(int i = 0; i < 4; ++i)
{ {
ushort us = (ushort)(uVersion & 0xFFFFUL); if(uVersion == 0UL) break;
if((us != 0) || (str.Length > 0)) ushort us = (ushort)(uVersion >> 48);
{
if(str.Length > 0)
{
str = "." + str;
bMultiComp = true;
}
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)) while(uComp < uMinComp)
str += ".0"; {
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 }; private static readonly byte[] m_pbOptEnt = { 0xA5, 0x74, 0x2E, 0xEC };
@ -994,7 +1282,7 @@ namespace KeePassLib.Utility
byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt, byte[] pbEnc = ProtectedData.Protect(pbPlain, m_pbOptEnt,
DataProtectionScope.CurrentUser); DataProtectionScope.CurrentUser);
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None); return Convert.ToBase64String(pbEnc, Base64FormattingOptions.None);
#else #else
return Convert.ToBase64String(pbEnc); return Convert.ToBase64String(pbEnc);
@ -1030,7 +1318,7 @@ namespace KeePassLib.Utility
for(int i = 0; i < vNumbers.Length; ++i) for(int i = 0; i < vNumbers.Length; ++i)
{ {
if(i > 0) sb.Append(' '); if(i > 0) sb.Append(' ');
sb.Append(vNumbers[i]); sb.Append(vNumbers[i].ToString(NumberFormatInfo.InvariantInfo));
} }
return sb.ToString(); return sb.ToString();
@ -1047,14 +1335,14 @@ namespace KeePassLib.Utility
for(int i = 0; i < vParts.Length; ++i) for(int i = 0; i < vParts.Length; ++i)
{ {
int n; int n;
if(!TryParseInt(vParts[i], out n)) { Debug.Assert(false); } if(!TryParseIntInvariant(vParts[i], out n)) { Debug.Assert(false); }
v[i] = n; v[i] = n;
} }
return v; 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) public static string TagsToString(List<string> vTags, bool bForDisplay)
{ {
if(vTags == null) throw new ArgumentNullException("vTags"); if(vTags == null) throw new ArgumentNullException("vTags");
@ -1107,7 +1395,7 @@ namespace KeePassLib.Utility
Array.Reverse(pb); Array.Reverse(pb);
for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65); 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); return Convert.ToBase64String(pb, Base64FormattingOptions.None);
#else #else
return Convert.ToBase64String(pb); return Convert.ToBase64String(pb);
@ -1225,9 +1513,33 @@ namespace KeePassLib.Utility
public static bool IsDataUri(string strUri) 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> /// <summary>
@ -1243,7 +1555,7 @@ namespace KeePassLib.Utility
if(strMimeType == null) strMimeType = "application/octet-stream"; if(strMimeType == null) strMimeType = "application/octet-stream";
#if !KeePassLibSD #if (!KeePassLibSD && !KeePassUAP)
return ("data:" + strMimeType + ";base64," + Convert.ToBase64String( return ("data:" + strMimeType + ";base64," + Convert.ToBase64String(
pbData, Base64FormattingOptions.None)); pbData, Base64FormattingOptions.None));
#else #else
@ -1273,14 +1585,15 @@ namespace KeePassLib.Utility
if(bBase64) return Convert.FromBase64String(strData); if(bBase64) return Convert.FromBase64String(strData);
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
Encoding enc = Encoding.ASCII;
string[] v = strData.Split('%'); string[] v = strData.Split('%');
byte[] pb = Encoding.ASCII.GetBytes(v[0]); byte[] pb = enc.GetBytes(v[0]);
ms.Write(pb, 0, pb.Length); ms.Write(pb, 0, pb.Length);
for(int i = 1; i < v.Length; ++i) for(int i = 1; i < v.Length; ++i)
{ {
ms.WriteByte(Convert.ToByte(v[i].Substring(0, 2), 16)); 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); ms.Write(pb, 0, pb.Length);
} }
@ -1330,5 +1643,72 @@ namespace KeePassLib.Utility
return null; 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 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 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 it under the terms of the GNU General Public License as published by
@ -18,7 +18,12 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.Text;
using KeePassLib.Interfaces;
namespace KeePassLib.Utility namespace KeePassLib.Utility
{ {
@ -33,6 +38,26 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
public const int PwTimeLength = 7; 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> /// <summary>
/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits, /// 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 /// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6
@ -138,17 +163,118 @@ namespace KeePassLib.Utility
{ {
DateTime dt; DateTime dt;
#if !KeePassLibSD #if KeePassLibSD
if(DateTime.TryParse(strDisplay, out dt)) return dt;
#else
try { dt = DateTime.Parse(strDisplay); return dt; } try { dt = DateTime.Parse(strDisplay); return dt; }
catch(Exception) { } 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 #endif
Debug.Assert(false); Debug.Assert(false);
return DateTime.Now; 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) public static string SerializeUtc(DateTime dt)
{ {
string str = dt.ToUniversalTime().ToString("s"); string str = dt.ToUniversalTime().ToString("s");
@ -167,17 +293,14 @@ namespace KeePassLib.Utility
return bResult; 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) public static DateTime ConvertUnixTime(double dtUnix)
{ {
try try { return TimeUtil.UnixRoot.AddSeconds(dtUnix); }
{
if(!m_dtUnixRoot.HasValue)
m_dtUnixRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0,
DateTimeKind.Utc)).ToLocalTime();
return m_dtUnixRoot.Value.AddSeconds(dtUnix);
}
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
return DateTime.Now; return DateTime.Now;
@ -218,5 +341,44 @@ namespace KeePassLib.Utility
return null; return null;
} }
#endif #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 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 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 it under the terms of the GNU General Public License as published by
@ -19,10 +19,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Text;
using KeePassLib.Native; using KeePassLib.Native;
@ -34,13 +33,21 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
public static class UrlUtil public static class UrlUtil
{ {
private static readonly char[] m_vDirSeps = new char[] { '\\', '/', private static readonly char[] m_vDirSeps = new char[] {
Path.DirectorySeparatorChar }; '\\', '/', UrlUtil.LocalDirSepChar };
private static readonly char[] m_vPathTrimCharsWs = new char[] {
'\"', ' ', '\t', '\r', '\n' };
public static char LocalDirSepChar
{
get { return Path.DirectorySeparatorChar; }
}
/// <summary> /// <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: /// terminated by a directory separator character. Example:
/// passing <c>C:\\My Documents\\My File.kdb</c> in <paramref name="strFile" /> /// 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>. /// would produce this string: <c>C:\\My Documents\\</c>.
/// </summary> /// </summary>
/// <param name="strFile">Full path of a file.</param> /// <param name="strFile">Full path of a file.</param>
@ -51,8 +58,7 @@ namespace KeePassLib.Utility
/// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />). /// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />).
/// This should only be set to <c>true</c>, if the returned path is directly /// This should only be set to <c>true</c>, if the returned path is directly
/// passed to some directory API.</param> /// passed to some directory API.</param>
/// <returns>Directory of the file. The return value is an empty string /// <returns>Directory of the file.</returns>
/// (<c>""</c>) if the input parameter is <c>null</c>.</returns>
public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar, public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar,
bool bEnsureValidDirSpec) bool bEnsureValidDirSpec)
{ {
@ -60,14 +66,15 @@ namespace KeePassLib.Utility
if(strFile == null) throw new ArgumentNullException("strFile"); if(strFile == null) throw new ArgumentNullException("strFile");
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps); 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] == ':') && if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
(strFile[2] == '\\')) // Length >= 3 and Windows root directory (strFile[2] == '\\')) // Length >= 3 and Windows root directory
bAppendTerminatingChar = true; bAppendTerminatingChar = true;
if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep); if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), false); return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep),
(strFile[nLastSep] == '/'));
} }
/// <summary> /// <summary>
@ -148,7 +155,7 @@ namespace KeePassLib.Utility
} }
if(bUrl) return (strPath + '/'); if(bUrl) return (strPath + '/');
return (strPath + Path.DirectorySeparatorChar); return (strPath + UrlUtil.LocalDirSepChar);
} }
/* /// <summary> /* /// <summary>
@ -211,13 +218,22 @@ namespace KeePassLib.Utility
public static string GetQuotedAppPath(string strPath) public static string GetQuotedAppPath(string strPath)
{ {
int nFirst = strPath.IndexOf('\"'); if(strPath == null) { Debug.Assert(false); return string.Empty; }
int nSecond = strPath.IndexOf('\"', nFirst + 1);
if((nFirst >= 0) && (nSecond >= 0)) // int nFirst = strPath.IndexOf('\"');
return strPath.Substring(nFirst + 1, nSecond - nFirst - 1); // 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) public static string FileUrlToPath(string strUrl)
@ -229,7 +245,7 @@ namespace KeePassLib.Utility
if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp)) if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp))
str = str.Substring(8, str.Length - 8); str = str.Substring(8, str.Length - 8);
str = str.Replace('/', Path.DirectorySeparatorChar); str = str.Replace('/', UrlUtil.LocalDirSepChar);
return str; return str;
} }
@ -297,8 +313,10 @@ namespace KeePassLib.Utility
return strTargetFile; return strTargetFile;
} }
#if (!KeePassLibSD && !KeePassUAP)
if(NativeLib.IsUnix()) if(NativeLib.IsUnix())
{ {
#endif
bool bBaseUnc = IsUncPath(strBaseFile); bool bBaseUnc = IsUncPath(strBaseFile);
bool bTargetUnc = IsUncPath(strTargetFile); bool bTargetUnc = IsUncPath(strTargetFile);
if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc)) if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc))
@ -316,21 +334,19 @@ namespace KeePassLib.Utility
StringBuilder sbRel = new StringBuilder(); StringBuilder sbRel = new StringBuilder();
for(int j = i; j < (vBase.Length - 1); ++j) 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(".."); sbRel.Append("..");
} }
for(int k = i; k < vTarget.Length; ++k) 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]); sbRel.Append(vTarget[k]);
} }
return sbRel.ToString(); return sbRel.ToString();
#if (!KeePassLibSD && !KeePassUAP)
} }
#if KeePassLibSD
return strTargetFile;
#else
try // Windows try // Windows
{ {
const int nMaxPath = NativeMethods.MAX_PATH * 2; const int nMaxPath = NativeMethods.MAX_PATH * 2;
@ -344,7 +360,8 @@ namespace KeePassLib.Utility
return str; return str;
} }
catch(Exception) { Debug.Assert(false); return strTargetFile; } catch(Exception) { Debug.Assert(false); }
return strTargetFile;
#endif #endif
} }
@ -476,7 +493,7 @@ namespace KeePassLib.Utility
public static string ConvertSeparators(string strPath) public static string ConvertSeparators(string strPath)
{ {
return ConvertSeparators(strPath, Path.DirectorySeparatorChar); return ConvertSeparators(strPath, UrlUtil.LocalDirSepChar);
} }
public static string ConvertSeparators(string strPath, char chSeparator) public static string ConvertSeparators(string strPath, char chSeparator)
@ -594,16 +611,97 @@ namespace KeePassLib.Utility
string strDir; string strDir;
if(NativeLib.IsUnix()) if(NativeLib.IsUnix())
strDir = NativeMethods.GetUserRuntimeDir(); strDir = NativeMethods.GetUserRuntimeDir();
#if KeePassUAP
else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
#else
else strDir = Path.GetTempPath(); else strDir = Path.GetTempPath();
#endif
try try
{ {
if(Directory.Exists(strDir) == false) if(!Directory.Exists(strDir)) Directory.CreateDirectory(strDir);
Directory.CreateDirectory(strDir);
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
return strDir; 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
} }
} }