Unmodified KeepassLib from KeePass Desktop v2.20

This commit is contained in:
PhilippC 2013-02-23 14:24:43 +01:00
commit 36c1df19d4
88 changed files with 21818 additions and 0 deletions

1
src/KeePassLib2Android/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
obj/

View File

@ -0,0 +1,220 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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 KeePassLib.Interfaces;
namespace KeePassLib.Collections
{
[Flags]
public enum AutoTypeObfuscationOptions
{
None = 0,
UseClipboard = 1
}
public sealed class AutoTypeAssociation : IEquatable<AutoTypeAssociation>,
IDeepCloneable<AutoTypeAssociation>
{
private string m_strWindow = string.Empty;
public string WindowName
{
get { return m_strWindow; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_strWindow = value;
}
}
private string m_strSequence = string.Empty;
public string Sequence
{
get { return m_strSequence; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_strSequence = value;
}
}
public AutoTypeAssociation() { }
public AutoTypeAssociation(string strWindow, string strSeq)
{
if(strWindow == null) throw new ArgumentNullException("strWindow");
if(strSeq == null) throw new ArgumentNullException("strSeq");
m_strWindow = strWindow;
m_strSequence = strSeq;
}
public bool Equals(AutoTypeAssociation other)
{
if(other == null) return false;
if(m_strWindow != other.m_strWindow) return false;
if(m_strSequence != other.m_strSequence) return false;
return true;
}
public AutoTypeAssociation CloneDeep()
{
return (AutoTypeAssociation)this.MemberwiseClone();
}
}
/// <summary>
/// A list of auto-type associations.
/// </summary>
public sealed class AutoTypeConfig : IEquatable<AutoTypeConfig>,
IDeepCloneable<AutoTypeConfig>
{
private bool m_bEnabled = true;
private AutoTypeObfuscationOptions m_atooObfuscation =
AutoTypeObfuscationOptions.None;
private string m_strDefaultSequence = string.Empty;
private List<AutoTypeAssociation> m_lWindowAssocs =
new List<AutoTypeAssociation>();
/// <summary>
/// Specify whether auto-type is enabled or not.
/// </summary>
public bool Enabled
{
get { return m_bEnabled; }
set { m_bEnabled = value; }
}
/// <summary>
/// Specify whether the typing should be obfuscated.
/// </summary>
public AutoTypeObfuscationOptions ObfuscationOptions
{
get { return m_atooObfuscation; }
set { m_atooObfuscation = value; }
}
/// <summary>
/// The default keystroke sequence that is auto-typed if
/// no matching window is found in the <c>Associations</c>
/// container.
/// </summary>
public string DefaultSequence
{
get { return m_strDefaultSequence; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_strDefaultSequence = value;
}
}
/// <summary>
/// Get all auto-type window/keystroke sequence pairs.
/// </summary>
public IEnumerable<AutoTypeAssociation> Associations
{
get { return m_lWindowAssocs; }
}
public int AssociationsCount
{
get { return m_lWindowAssocs.Count; }
}
/// <summary>
/// Construct a new auto-type associations list.
/// </summary>
public AutoTypeConfig()
{
}
/// <summary>
/// Remove all associations.
/// </summary>
public void Clear()
{
m_lWindowAssocs.Clear();
}
/// <summary>
/// Clone the auto-type associations list.
/// </summary>
/// <returns>New, cloned object.</returns>
public AutoTypeConfig CloneDeep()
{
AutoTypeConfig newCfg = new AutoTypeConfig();
newCfg.m_bEnabled = m_bEnabled;
newCfg.m_atooObfuscation = m_atooObfuscation;
newCfg.m_strDefaultSequence = m_strDefaultSequence;
foreach(AutoTypeAssociation a in m_lWindowAssocs)
newCfg.Add(a.CloneDeep());
return newCfg;
}
public bool Equals(AutoTypeConfig other)
{
if(other == null) { Debug.Assert(false); return false; }
if(m_bEnabled != other.m_bEnabled) return false;
if(m_atooObfuscation != other.m_atooObfuscation) return false;
if(m_strDefaultSequence != other.m_strDefaultSequence) return false;
if(m_lWindowAssocs.Count != other.m_lWindowAssocs.Count) return false;
for(int i = 0; i < m_lWindowAssocs.Count; ++i)
{
if(!m_lWindowAssocs[i].Equals(other.m_lWindowAssocs[i]))
return false;
}
return true;
}
public void Add(AutoTypeAssociation a)
{
Debug.Assert(a != null); if(a == null) throw new ArgumentNullException("a");
m_lWindowAssocs.Add(a);
}
public AutoTypeAssociation GetAt(int iIndex)
{
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
throw new ArgumentOutOfRangeException("iIndex");
return m_lWindowAssocs[iIndex];
}
public void RemoveAt(int iIndex)
{
if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count))
throw new ArgumentOutOfRangeException("iIndex");
m_lWindowAssocs.RemoveAt(iIndex);
}
}
}

View File

@ -0,0 +1,173 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Collections
{
/// <summary>
/// A list of <c>ProtectedBinary</c> objects (dictionary).
/// </summary>
public sealed class ProtectedBinaryDictionary :
IDeepCloneable<ProtectedBinaryDictionary>,
IEnumerable<KeyValuePair<string, ProtectedBinary>>
{
private SortedDictionary<string, ProtectedBinary> m_vBinaries =
new SortedDictionary<string, ProtectedBinary>();
/// <summary>
/// Get the number of binaries in this entry.
/// </summary>
public uint UCount
{
get { return (uint)m_vBinaries.Count; }
}
/// <summary>
/// Construct a new list of protected binaries.
/// </summary>
public ProtectedBinaryDictionary()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vBinaries.GetEnumerator();
}
public IEnumerator<KeyValuePair<string, ProtectedBinary>> GetEnumerator()
{
return m_vBinaries.GetEnumerator();
}
public void Clear()
{
m_vBinaries.Clear();
}
/// <summary>
/// Clone the current <c>ProtectedBinaryList</c> object, including all
/// stored protected strings.
/// </summary>
/// <returns>New <c>ProtectedBinaryList</c> object.</returns>
public ProtectedBinaryDictionary CloneDeep()
{
ProtectedBinaryDictionary plNew = new ProtectedBinaryDictionary();
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in m_vBinaries)
{
// ProtectedBinary objects are immutable
plNew.Set(kvpBin.Key, kvpBin.Value);
}
return plNew;
}
public bool EqualsDictionary(ProtectedBinaryDictionary dict)
{
if(dict == null) { Debug.Assert(false); return false; }
if(m_vBinaries.Count != dict.m_vBinaries.Count) return false;
foreach(KeyValuePair<string, ProtectedBinary> kvp in m_vBinaries)
{
ProtectedBinary pb = dict.Get(kvp.Key);
if(pb == null) return false;
if(!pb.Equals(kvp.Value)) return false;
}
return true;
}
/// <summary>
/// Get one of the stored binaries.
/// </summary>
/// <param name="strName">Binary identifier.</param>
/// <returns>Protected binary. If the binary identified by
/// <paramref name="strName" /> cannot be found, the function
/// returns <c>null</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedBinary Get(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
ProtectedBinary pb;
if(m_vBinaries.TryGetValue(strName, out pb)) return pb;
return null;
}
/// <summary>
/// Set a binary object.
/// </summary>
/// <param name="strField">Identifier of the binary field to modify.</param>
/// <param name="pbNewValue">New value. This parameter must not be <c>null</c>.</param>
/// <exception cref="System.ArgumentNullException">Thrown if any of the input
/// parameters is <c>null</c>.</exception>
public void Set(string strField, ProtectedBinary pbNewValue)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
Debug.Assert(pbNewValue != null); if(pbNewValue == null) throw new ArgumentNullException("pbNewValue");
m_vBinaries[strField] = pbNewValue;
}
/// <summary>
/// Remove a binary object.
/// </summary>
/// <param name="strField">Identifier of the binary field to remove.</param>
/// <returns>Returns <c>true</c> if the object has been successfully
/// removed, otherwise <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input parameter
/// is <c>null</c>.</exception>
public bool Remove(string strField)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
return m_vBinaries.Remove(strField);
}
public string KeysToString()
{
if(m_vBinaries.Count == 0) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach(KeyValuePair<string, ProtectedBinary> kvp in m_vBinaries)
{
if(sb.Length > 0) sb.Append(", ");
sb.Append(kvp.Key);
}
return sb.ToString();
}
}
}

View File

@ -0,0 +1,306 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Collections
{
/// <summary>
/// A list of <c>ProtectedString</c> objects (dictionary).
/// </summary>
public sealed class ProtectedStringDictionary :
IDeepCloneable<ProtectedStringDictionary>,
IEnumerable<KeyValuePair<string, ProtectedString>>
{
private SortedDictionary<string, ProtectedString> m_vStrings =
new SortedDictionary<string, ProtectedString>();
/// <summary>
/// Get the number of strings in this entry.
/// </summary>
public uint UCount
{
get { return (uint)m_vStrings.Count; }
}
/// <summary>
/// Construct a new list of protected strings.
/// </summary>
public ProtectedStringDictionary()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vStrings.GetEnumerator();
}
public IEnumerator<KeyValuePair<string, ProtectedString>> GetEnumerator()
{
return m_vStrings.GetEnumerator();
}
public void Clear()
{
m_vStrings.Clear();
}
/// <summary>
/// Clone the current <c>ProtectedStringList</c> object, including all
/// stored protected strings.
/// </summary>
/// <returns>New <c>ProtectedStringList</c> object.</returns>
public ProtectedStringDictionary CloneDeep()
{
ProtectedStringDictionary plNew = new ProtectedStringDictionary();
foreach(KeyValuePair<string, ProtectedString> kvpStr in m_vStrings)
{
// ProtectedString objects are immutable
plNew.Set(kvpStr.Key, kvpStr.Value);
}
return plNew;
}
[Obsolete]
public bool EqualsDictionary(ProtectedStringDictionary dict)
{
return EqualsDictionary(dict, PwCompareOptions.None, MemProtCmpMode.None);
}
[Obsolete]
public bool EqualsDictionary(ProtectedStringDictionary dict,
MemProtCmpMode mpCompare)
{
return EqualsDictionary(dict, PwCompareOptions.None, mpCompare);
}
public bool EqualsDictionary(ProtectedStringDictionary dict,
PwCompareOptions pwOpt, MemProtCmpMode mpCompare)
{
if(dict == null) { Debug.Assert(false); return false; }
bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) !=
PwCompareOptions.None);
if(!bNeEqStd)
{
if(m_vStrings.Count != dict.m_vStrings.Count) return false;
}
foreach(KeyValuePair<string, ProtectedString> kvp in m_vStrings)
{
bool bStdField = PwDefs.IsStandardField(kvp.Key);
ProtectedString ps = dict.Get(kvp.Key);
if(bNeEqStd && (ps == null) && bStdField)
ps = ProtectedString.Empty;
if(ps == null) return false;
if(mpCompare == MemProtCmpMode.Full)
{
if(ps.IsProtected != kvp.Value.IsProtected) return false;
}
else if(mpCompare == MemProtCmpMode.CustomOnly)
{
if(!bStdField && (ps.IsProtected != kvp.Value.IsProtected))
return false;
}
if(ps.ReadString() != kvp.Value.ReadString()) return false;
}
if(bNeEqStd)
{
foreach(KeyValuePair<string, ProtectedString> kvp in dict.m_vStrings)
{
ProtectedString ps = Get(kvp.Key);
if(ps != null) continue; // Compared previously
if(!PwDefs.IsStandardField(kvp.Key)) return false;
if(!kvp.Value.IsEmpty) return false;
}
}
return true;
}
/// <summary>
/// Get one of the protected strings.
/// </summary>
/// <param name="strName">String identifier.</param>
/// <returns>Protected string. If the string identified by
/// <paramref name="strName" /> cannot be found, the function
/// returns <c>null</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input parameter
/// is <c>null</c>.</exception>
public ProtectedString Get(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
ProtectedString ps;
if(m_vStrings.TryGetValue(strName, out ps)) return ps;
return null;
}
/// <summary>
/// Get one of the protected strings. The return value is never <c>null</c>.
/// If the requested string cannot be found, an empty protected string
/// object is returned.
/// </summary>
/// <param name="strName">String identifier.</param>
/// <returns>Returns a protected string object. If the standard string
/// has not been set yet, the return value is an empty string (<c>""</c>).</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedString GetSafe(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
ProtectedString ps;
if(m_vStrings.TryGetValue(strName, out ps)) return ps;
return ProtectedString.Empty;
}
/// <summary>
/// Test if a named string exists.
/// </summary>
/// <param name="strName">Name of the string to try.</param>
/// <returns>Returns <c>true</c> if the string exists, otherwise <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if
/// <paramref name="strName" /> is <c>null</c>.</exception>
public bool Exists(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
return m_vStrings.ContainsKey(strName);
}
/// <summary>
/// Get one of the protected strings. If the string doesn't exist, the
/// return value is an empty string (<c>""</c>).
/// </summary>
/// <param name="strName">Name of the requested string.</param>
/// <returns>Requested string value or an empty string, if the named
/// string doesn't exist.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public string ReadSafe(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
ProtectedString ps;
if(m_vStrings.TryGetValue(strName, out ps))
return ps.ReadString();
return string.Empty;
}
/// <summary>
/// Get one of the entry strings. If the string doesn't exist, the
/// return value is an empty string (<c>""</c>). If the string is
/// in-memory protected, the return value is <c>PwDefs.HiddenPassword</c>.
/// </summary>
/// <param name="strName">Name of the requested string.</param>
/// <returns>Returns the requested string in plain-text or
/// <c>PwDefs.HiddenPassword</c> if the string cannot be found.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public string ReadSafeEx(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
ProtectedString ps;
if(m_vStrings.TryGetValue(strName, out ps))
{
if(ps.IsProtected) return PwDefs.HiddenPassword;
return ps.ReadString();
}
return string.Empty;
}
/// <summary>
/// Set a string.
/// </summary>
/// <param name="strField">Identifier of the string field to modify.</param>
/// <param name="psNewValue">New value. This parameter must not be <c>null</c>.</param>
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
/// parameters is <c>null</c>.</exception>
public void Set(string strField, ProtectedString psNewValue)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
Debug.Assert(psNewValue != null); if(psNewValue == null) throw new ArgumentNullException("psNewValue");
m_vStrings[strField] = psNewValue;
}
/// <summary>
/// Delete a string.
/// </summary>
/// <param name="strField">Name of the string field to delete.</param>
/// <returns>Returns <c>true</c> if the field has been successfully
/// removed, otherwise the return value is <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public bool Remove(string strField)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
return m_vStrings.Remove(strField);
}
public List<string> GetKeys()
{
List<string> v = new List<string>();
foreach(string strKey in m_vStrings.Keys) v.Add(strKey);
return v;
}
public void EnableProtection(string strField, bool bProtect)
{
ProtectedString ps = Get(strField);
if(ps == null) return; // Nothing to do, no assert
if(ps.IsProtected != bProtect)
{
byte[] pbData = ps.ReadUtf8();
Set(strField, new ProtectedString(bProtect, pbData));
MemUtil.ZeroByteArray(pbData);
}
}
}
}

View File

@ -0,0 +1,303 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Diagnostics;
using KeePassLib.Interfaces;
namespace KeePassLib.Collections
{
/// <summary>
/// List of objects that implement <c>IDeepCloneable</c>,
/// and cannot be <c>null</c>.
/// </summary>
/// <typeparam name="T">Type specifier.</typeparam>
public sealed class PwObjectList<T> : IEnumerable<T>
where T : class, IDeepCloneable<T>
{
private List<T> m_vObjects = new List<T>();
/// <summary>
/// Get number of objects in this list.
/// </summary>
public uint UCount
{
get { return (uint)m_vObjects.Count; }
}
/// <summary>
/// Construct a new list of objects.
/// </summary>
public PwObjectList()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vObjects.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return m_vObjects.GetEnumerator();
}
public void Clear()
{
// Do not destroy contained objects!
m_vObjects.Clear();
}
/// <summary>
/// Clone the current <c>PwObjectList</c>, including all
/// stored objects (deep copy).
/// </summary>
/// <returns>New <c>PwObjectList</c>.</returns>
public PwObjectList<T> CloneDeep()
{
PwObjectList<T> pl = new PwObjectList<T>();
foreach(T po in m_vObjects)
pl.Add(po.CloneDeep());
return pl;
}
public PwObjectList<T> CloneShallow()
{
PwObjectList<T> tNew = new PwObjectList<T>();
foreach(T po in m_vObjects) tNew.Add(po);
return tNew;
}
public List<T> CloneShallowToList()
{
PwObjectList<T> tNew = CloneShallow();
return tNew.m_vObjects;
}
/// <summary>
/// Add an object to this list.
/// </summary>
/// <param name="pwObject">Object to be added.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public void Add(T pwObject)
{
Debug.Assert(pwObject != null);
if(pwObject == null) throw new ArgumentNullException("pwObject");
m_vObjects.Add(pwObject);
}
public void Add(PwObjectList<T> vObjects)
{
Debug.Assert(vObjects != null);
if(vObjects == null) throw new ArgumentNullException("vObjects");
foreach(T po in vObjects)
{
m_vObjects.Add(po);
}
}
public void Add(List<T> vObjects)
{
Debug.Assert(vObjects != null);
if(vObjects == null) throw new ArgumentNullException("vObjects");
foreach(T po in vObjects)
{
m_vObjects.Add(po);
}
}
/// <summary>
/// Get an object of the list.
/// </summary>
/// <param name="uIndex">Index of the object to get. Must be valid, otherwise an
/// exception is thrown.</param>
/// <returns>Reference to an existing <c>T</c> object. Is never <c>null</c>.</returns>
public T GetAt(uint uIndex)
{
Debug.Assert(uIndex < m_vObjects.Count);
if(uIndex >= m_vObjects.Count) throw new ArgumentOutOfRangeException("uIndex");
return m_vObjects[(int)uIndex];
}
public void SetAt(uint uIndex, T pwObject)
{
Debug.Assert(pwObject != null);
if(pwObject == null) throw new ArgumentNullException("pwObject");
if(uIndex >= (uint)m_vObjects.Count)
throw new ArgumentOutOfRangeException("uIndex");
m_vObjects[(int)uIndex] = pwObject;
}
/// <summary>
/// Get a range of objects.
/// </summary>
/// <param name="uStartIndexIncl">Index of the first object to be
/// returned (inclusive).</param>
/// <param name="uEndIndexIncl">Index of the last object to be
/// returned (inclusive).</param>
/// <returns></returns>
public List<T> GetRange(uint uStartIndexIncl, uint uEndIndexIncl)
{
if(uStartIndexIncl >= (uint)m_vObjects.Count)
throw new ArgumentOutOfRangeException("uStartIndexIncl");
if(uEndIndexIncl >= (uint)m_vObjects.Count)
throw new ArgumentOutOfRangeException("uEndIndexIncl");
if(uStartIndexIncl > uEndIndexIncl)
throw new ArgumentException();
List<T> list = new List<T>((int)(uEndIndexIncl - uStartIndexIncl) + 1);
for(uint u = uStartIndexIncl; u <= uEndIndexIncl; ++u)
{
list.Add(m_vObjects[(int)u]);
}
return list;
}
public int IndexOf(T pwReference)
{
Debug.Assert(pwReference != null); if(pwReference == null) throw new ArgumentNullException("pwReference");
return m_vObjects.IndexOf(pwReference);
}
/// <summary>
/// Delete an object of this list. The object to be deleted is identified
/// by a reference handle.
/// </summary>
/// <param name="pwReference">Reference of the object to be deleted.</param>
/// <returns>Returns <c>true</c> if the object was deleted, <c>false</c> if
/// the object wasn't found in this list.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public bool Remove(T pwReference)
{
Debug.Assert(pwReference != null); if(pwReference == null) throw new ArgumentNullException("pwReference");
return m_vObjects.Remove(pwReference);
}
public void RemoveAt(uint uIndex)
{
m_vObjects.RemoveAt((int)uIndex);
}
/// <summary>
/// Move an object up or down.
/// </summary>
/// <param name="tObject">The object to be moved.</param>
/// <param name="bUp">Move one up. If <c>false</c>, move one down.</param>
public void MoveOne(T tObject, bool bUp)
{
Debug.Assert(tObject != null);
if(tObject == null) throw new ArgumentNullException("tObject");
int nCount = m_vObjects.Count;
if(nCount <= 1) return;
int nIndex = m_vObjects.IndexOf(tObject);
Debug.Assert(nIndex >= 0);
if(bUp && (nIndex > 0)) // No assert for top item
{
T tTemp = m_vObjects[nIndex - 1];
m_vObjects[nIndex - 1] = m_vObjects[nIndex];
m_vObjects[nIndex] = tTemp;
}
else if(!bUp && (nIndex != (nCount - 1))) // No assert for bottom item
{
T tTemp = m_vObjects[nIndex + 1];
m_vObjects[nIndex + 1] = m_vObjects[nIndex];
m_vObjects[nIndex] = tTemp;
}
}
/// <summary>
/// Move some of the objects in this list to the top/bottom.
/// </summary>
/// <param name="vObjects">List of objects to be moved.</param>
/// <param name="bTop">Move to top. If <c>false</c>, move to bottom.</param>
public void MoveTopBottom(T[] vObjects, bool bTop)
{
Debug.Assert(vObjects != null);
if(vObjects == null) throw new ArgumentNullException("vObjects");
if(vObjects.Length == 0) return;
int nCount = m_vObjects.Count;
foreach(T t in vObjects) m_vObjects.Remove(t);
if(bTop)
{
int nPos = 0;
foreach(T t in vObjects)
{
m_vObjects.Insert(nPos, t);
++nPos;
}
}
else // Move to bottom
{
foreach(T t in vObjects) m_vObjects.Add(t);
}
Debug.Assert(nCount == m_vObjects.Count);
if(nCount != m_vObjects.Count)
throw new ArgumentException("At least one of the T objects in the vObjects list doesn't exist!");
}
public void Sort(IComparer<T> tComparer)
{
if(tComparer == null) throw new ArgumentNullException("tComparer");
m_vObjects.Sort(tComparer);
}
public static PwObjectList<T> FromArray(T[] tArray)
{
if(tArray == null) throw new ArgumentNullException("tArray");
PwObjectList<T> l = new PwObjectList<T>();
foreach(T t in tArray) { l.Add(t); }
return l;
}
public static PwObjectList<T> FromList(List<T> tList)
{
if(tList == null) throw new ArgumentNullException("tList");
PwObjectList<T> l = new PwObjectList<T>();
l.Add(tList);
return l;
}
}
}

View File

@ -0,0 +1,80 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Collections
{
public sealed class PwObjectPool
{
private SortedDictionary<PwUuidComparable, IStructureItem> m_dict =
new SortedDictionary<PwUuidComparable, IStructureItem>();
public static PwObjectPool FromGroupRecursive(PwGroup pgRoot, bool bEntries)
{
if(pgRoot == null) throw new ArgumentNullException("pgRoot");
PwObjectPool p = new PwObjectPool();
if(!bEntries) p.m_dict[new PwUuidComparable(pgRoot.Uuid)] = pgRoot;
GroupHandler gh = delegate(PwGroup pg)
{
p.m_dict[new PwUuidComparable(pg.Uuid)] = pg;
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
p.m_dict[new PwUuidComparable(pe.Uuid)] = pe;
return true;
};
pgRoot.TraverseTree(TraversalMethod.PreOrder, bEntries ? null : gh,
bEntries ? eh : null);
return p;
}
public IStructureItem Get(PwUuid pwUuid)
{
IStructureItem pItem;
m_dict.TryGetValue(new PwUuidComparable(pwUuid), out pItem);
return pItem;
}
public bool ContainsOnlyType(Type t)
{
foreach(KeyValuePair<PwUuidComparable, IStructureItem> kvp in m_dict)
{
if(kvp.Value.GetType() != t) return false;
}
return true;
}
}
}

View File

@ -0,0 +1,116 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using KeePassLib.Interfaces;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Collections
{
public sealed class StringDictionaryEx : IDeepCloneable<StringDictionaryEx>,
IEnumerable<KeyValuePair<string, string>>
{
private SortedDictionary<string, string> m_vDict =
new SortedDictionary<string, string>();
public int Count
{
get { return m_vDict.Count; }
}
public StringDictionaryEx()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vDict.GetEnumerator();
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return m_vDict.GetEnumerator();
}
public StringDictionaryEx CloneDeep()
{
StringDictionaryEx plNew = new StringDictionaryEx();
foreach(KeyValuePair<string, string> kvpStr in m_vDict)
plNew.Set(kvpStr.Key, kvpStr.Value);
return plNew;
}
public string Get(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
string s;
if(m_vDict.TryGetValue(strName, out s)) return s;
return null;
}
public bool Exists(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
return m_vDict.ContainsKey(strName);
}
/// <summary>
/// Set a string.
/// </summary>
/// <param name="strField">Identifier of the string field to modify.</param>
/// <param name="strNewValue">New value. This parameter must not be <c>null</c>.</param>
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
/// parameters is <c>null</c>.</exception>
public void Set(string strField, string strNewValue)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
Debug.Assert(strNewValue != null); if(strNewValue == null) throw new ArgumentNullException("strNewValue");
m_vDict[strField] = strNewValue;
}
/// <summary>
/// Delete a string.
/// </summary>
/// <param name="strField">Name of the string field to delete.</param>
/// <returns>Returns <c>true</c> if the field has been successfully
/// removed, otherwise the return value is <c>false</c>.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public bool Remove(string strField)
{
Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField");
return m_vDict.Remove(strField);
}
}
}

View File

@ -0,0 +1,162 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
namespace KeePassLib.Cryptography.Cipher
{
/// <summary>
/// Pool of encryption/decryption algorithms (ciphers).
/// </summary>
public sealed class CipherPool
{
private List<ICipherEngine> m_vCiphers = new List<ICipherEngine>();
private static CipherPool m_poolGlobal = null;
/// <summary>
/// Reference to the global cipher pool.
/// </summary>
public static CipherPool GlobalPool
{
get
{
if(m_poolGlobal != null) return m_poolGlobal;
m_poolGlobal = new CipherPool();
m_poolGlobal.AddCipher(new StandardAesEngine());
return m_poolGlobal;
}
}
/// <summary>
/// Remove all cipher engines from the current pool.
/// </summary>
public void Clear()
{
m_vCiphers.Clear();
}
/// <summary>
/// Add a cipher engine to the pool.
/// </summary>
/// <param name="csEngine">Cipher engine to add. Must not be <c>null</c>.</param>
public void AddCipher(ICipherEngine csEngine)
{
Debug.Assert(csEngine != null);
if(csEngine == null) throw new ArgumentNullException("csEngine");
// Return if a cipher with that ID is registered already.
for(int i = 0; i < m_vCiphers.Count; ++i)
if(m_vCiphers[i].CipherUuid.EqualsValue(csEngine.CipherUuid))
return;
m_vCiphers.Add(csEngine);
}
/// <summary>
/// Get a cipher identified by its UUID.
/// </summary>
/// <param name="uuidCipher">UUID of the cipher to return.</param>
/// <returns>Reference to the requested cipher. If the cipher is
/// not found, <c>null</c> is returned.</returns>
public ICipherEngine GetCipher(PwUuid uuidCipher)
{
foreach(ICipherEngine iEngine in m_vCiphers)
{
if(iEngine.CipherUuid.EqualsValue(uuidCipher))
return iEngine;
}
return null;
}
/// <summary>
/// Get the index of a cipher. This index is temporary and should
/// not be stored or used to identify a cipher.
/// </summary>
/// <param name="uuidCipher">UUID of the cipher.</param>
/// <returns>Index of the requested cipher. Returns <c>-1</c> if
/// the specified cipher is not found.</returns>
public int GetCipherIndex(PwUuid uuidCipher)
{
for(int i = 0; i < m_vCiphers.Count; ++i)
{
if(m_vCiphers[i].CipherUuid.EqualsValue(uuidCipher))
return i;
}
Debug.Assert(false);
return -1;
}
/// <summary>
/// Get the index of a cipher. This index is temporary and should
/// not be stored or used to identify a cipher.
/// </summary>
/// <param name="strDisplayName">Name of the cipher. Note that
/// multiple ciphers can have the same name. In this case, the
/// first matching cipher is returned.</param>
/// <returns>Cipher with the specified name or <c>-1</c> if
/// no cipher with that name is found.</returns>
public int GetCipherIndex(string strDisplayName)
{
for(int i = 0; i < m_vCiphers.Count; ++i)
if(m_vCiphers[i].DisplayName == strDisplayName)
return i;
Debug.Assert(false);
return -1;
}
/// <summary>
/// Get the number of cipher engines in this pool.
/// </summary>
public int EngineCount
{
get { return m_vCiphers.Count; }
}
/// <summary>
/// Get the cipher engine at the specified position. Throws
/// an exception if the index is invalid. You can use this
/// to iterate over all ciphers, but do not use it to
/// identify ciphers.
/// </summary>
/// <param name="nIndex">Index of the requested cipher engine.</param>
/// <returns>Reference to the cipher engine at the specified
/// position.</returns>
public ICipherEngine this[int nIndex]
{
get
{
if((nIndex < 0) || (nIndex >= m_vCiphers.Count))
throw new ArgumentOutOfRangeException("nIndex");
return m_vCiphers[nIndex];
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.IO;
namespace KeePassLib.Cryptography.Cipher
{
/// <summary>
/// Interface of an encryption/decryption class.
/// </summary>
public interface ICipherEngine
{
/// <summary>
/// UUID of the engine. If you want to write an engine/plugin,
/// please contact the KeePass team to obtain a new UUID.
/// </summary>
PwUuid CipherUuid
{
get;
}
/// <summary>
/// String displayed in the list of available encryption/decryption
/// engines in the GUI.
/// </summary>
string DisplayName
{
get;
}
/// <summary>
/// Encrypt a stream.
/// </summary>
/// <param name="sPlainText">Stream to read the plain-text from.</param>
/// <param name="pbKey">Key to use.</param>
/// <param name="pbIV">Initialization vector.</param>
/// <returns>Stream, from which the encrypted data can be read.</returns>
Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV);
/// <summary>
/// Decrypt a stream.
/// </summary>
/// <param name="sEncrypted">Stream to read the encrypted data from.</param>
/// <param name="pbKey">Key to use.</param>
/// <param name="pbIV">Initialization vector.</param>
/// <returns>Stream, from which the decrypted data can be read.</returns>
Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV);
}
}

View File

@ -0,0 +1,188 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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
*/
// Implementation of the Salsa20 cipher, based on the eSTREAM submission.
using System;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography.Cipher
{
public sealed class Salsa20Cipher
{
private uint[] m_state = new uint[16];
private uint[] m_x = new uint[16]; // Working buffer
private byte[] m_output = new byte[64];
private int m_outputPos = 64;
private static readonly uint[] m_sigma = new uint[4]{
0x61707865, 0x3320646E, 0x79622D32, 0x6B206574
};
public Salsa20Cipher(byte[] pbKey32, byte[] pbIV8)
{
KeySetup(pbKey32);
IvSetup(pbIV8);
}
~Salsa20Cipher()
{
// Clear sensitive data
Array.Clear(m_state, 0, m_state.Length);
Array.Clear(m_x, 0, m_x.Length);
}
private void NextOutput()
{
uint[] x = m_x; // Local alias for working buffer
// Compiler/runtime might remove array bound checks after this
if(x.Length < 16) throw new InvalidOperationException();
Array.Copy(m_state, x, 16);
unchecked
{
for(int i = 0; i < 10; ++i) // (int i = 20; i > 0; i -= 2)
{
x[ 4] ^= Rotl32(x[ 0] + x[12], 7);
x[ 8] ^= Rotl32(x[ 4] + x[ 0], 9);
x[12] ^= Rotl32(x[ 8] + x[ 4], 13);
x[ 0] ^= Rotl32(x[12] + x[ 8], 18);
x[ 9] ^= Rotl32(x[ 5] + x[ 1], 7);
x[13] ^= Rotl32(x[ 9] + x[ 5], 9);
x[ 1] ^= Rotl32(x[13] + x[ 9], 13);
x[ 5] ^= Rotl32(x[ 1] + x[13], 18);
x[14] ^= Rotl32(x[10] + x[ 6], 7);
x[ 2] ^= Rotl32(x[14] + x[10], 9);
x[ 6] ^= Rotl32(x[ 2] + x[14], 13);
x[10] ^= Rotl32(x[ 6] + x[ 2], 18);
x[ 3] ^= Rotl32(x[15] + x[11], 7);
x[ 7] ^= Rotl32(x[ 3] + x[15], 9);
x[11] ^= Rotl32(x[ 7] + x[ 3], 13);
x[15] ^= Rotl32(x[11] + x[ 7], 18);
x[ 1] ^= Rotl32(x[ 0] + x[ 3], 7);
x[ 2] ^= Rotl32(x[ 1] + x[ 0], 9);
x[ 3] ^= Rotl32(x[ 2] + x[ 1], 13);
x[ 0] ^= Rotl32(x[ 3] + x[ 2], 18);
x[ 6] ^= Rotl32(x[ 5] + x[ 4], 7);
x[ 7] ^= Rotl32(x[ 6] + x[ 5], 9);
x[ 4] ^= Rotl32(x[ 7] + x[ 6], 13);
x[ 5] ^= Rotl32(x[ 4] + x[ 7], 18);
x[11] ^= Rotl32(x[10] + x[ 9], 7);
x[ 8] ^= Rotl32(x[11] + x[10], 9);
x[ 9] ^= Rotl32(x[ 8] + x[11], 13);
x[10] ^= Rotl32(x[ 9] + x[ 8], 18);
x[12] ^= Rotl32(x[15] + x[14], 7);
x[13] ^= Rotl32(x[12] + x[15], 9);
x[14] ^= Rotl32(x[13] + x[12], 13);
x[15] ^= Rotl32(x[14] + x[13], 18);
}
for(int i = 0; i < 16; ++i)
x[i] += m_state[i];
for(int i = 0; i < 16; ++i)
{
m_output[i << 2] = (byte)x[i];
m_output[(i << 2) + 1] = (byte)(x[i] >> 8);
m_output[(i << 2) + 2] = (byte)(x[i] >> 16);
m_output[(i << 2) + 3] = (byte)(x[i] >> 24);
}
m_outputPos = 0;
++m_state[8];
if(m_state[8] == 0) ++m_state[9];
}
}
private static uint Rotl32(uint x, int b)
{
unchecked
{
return ((x << b) | (x >> (32 - b)));
}
}
private static uint U8To32Little(byte[] pb, int iOffset)
{
unchecked
{
return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) |
((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24));
}
}
private void KeySetup(byte[] k)
{
if(k == null) throw new ArgumentNullException("k");
if(k.Length != 32) throw new ArgumentException();
m_state[1] = U8To32Little(k, 0);
m_state[2] = U8To32Little(k, 4);
m_state[3] = U8To32Little(k, 8);
m_state[4] = U8To32Little(k, 12);
m_state[11] = U8To32Little(k, 16);
m_state[12] = U8To32Little(k, 20);
m_state[13] = U8To32Little(k, 24);
m_state[14] = U8To32Little(k, 28);
m_state[0] = m_sigma[0];
m_state[5] = m_sigma[1];
m_state[10] = m_sigma[2];
m_state[15] = m_sigma[3];
}
private void IvSetup(byte[] pbIV)
{
if(pbIV == null) throw new ArgumentNullException("pbIV");
if(pbIV.Length != 8) throw new ArgumentException();
m_state[6] = U8To32Little(pbIV, 0);
m_state[7] = U8To32Little(pbIV, 4);
m_state[8] = 0;
m_state[9] = 0;
}
public void Encrypt(byte[] m, int nByteCount, bool bXor)
{
if(m == null) throw new ArgumentNullException("m");
if(nByteCount > m.Length) throw new ArgumentException();
int nBytesRem = nByteCount, nOffset = 0;
while(nBytesRem > 0)
{
Debug.Assert((m_outputPos >= 0) && (m_outputPos <= 64));
if(m_outputPos == 64) NextOutput();
Debug.Assert(m_outputPos < 64);
int nCopy = Math.Min(64 - m_outputPos, nBytesRem);
if(bXor) MemUtil.XorArray(m_output, m_outputPos, m, nOffset, nCopy);
else Array.Copy(m_output, m_outputPos, m, nOffset, nCopy);
m_outputPos += nCopy;
nBytesRem -= nCopy;
nOffset += nCopy;
}
}
}
}

View File

@ -0,0 +1,140 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics;
using KeePassLib.Resources;
namespace KeePassLib.Cryptography.Cipher
{
/// <summary>
/// Standard AES cipher implementation.
/// </summary>
public sealed class StandardAesEngine : ICipherEngine
{
private const CipherMode m_rCipherMode = CipherMode.CBC;
private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7;
private static PwUuid m_uuidAes = null;
/// <summary>
/// UUID of the cipher engine. This ID uniquely identifies the
/// AES engine. Must not be used by other ciphers.
/// </summary>
public static PwUuid AesUuid
{
get
{
if(m_uuidAes == null)
{
m_uuidAes = new PwUuid(new byte[]{
0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50,
0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF });
}
return m_uuidAes;
}
}
/// <summary>
/// Get the UUID of this cipher engine as <c>PwUuid</c> object.
/// </summary>
public PwUuid CipherUuid
{
get { return StandardAesEngine.AesUuid; }
}
/// <summary>
/// Get a displayable name describing this cipher engine.
/// </summary>
public string DisplayName { get { return KLRes.EncAlgorithmAes; } }
private static void ValidateArguments(Stream stream, bool bEncrypt, byte[] pbKey, byte[] pbIV)
{
Debug.Assert(stream != null); if(stream == null) throw new ArgumentNullException("stream");
Debug.Assert(pbKey != null); if(pbKey == null) throw new ArgumentNullException("pbKey");
Debug.Assert(pbKey.Length == 32);
if(pbKey.Length != 32) throw new ArgumentException("Key must be 256 bits wide!");
Debug.Assert(pbIV != null); if(pbIV == null) throw new ArgumentNullException("pbIV");
Debug.Assert(pbIV.Length == 16);
if(pbIV.Length != 16) throw new ArgumentException("Initialization vector must be 128 bits wide!");
if(bEncrypt)
{
Debug.Assert(stream.CanWrite);
if(stream.CanWrite == false) throw new ArgumentException("Stream must be writable!");
}
else // Decrypt
{
Debug.Assert(stream.CanRead);
if(stream.CanRead == false) throw new ArgumentException("Encrypted stream must be readable!");
}
}
private static Stream CreateStream(Stream s, bool bEncrypt, byte[] pbKey, byte[] pbIV)
{
StandardAesEngine.ValidateArguments(s, bEncrypt, pbKey, pbIV);
RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size
{
Debug.Assert(false);
r.BlockSize = 128;
}
byte[] pbLocalIV = new byte[16];
Array.Copy(pbIV, pbLocalIV, 16);
r.IV = pbLocalIV;
byte[] pbLocalKey = new byte[32];
Array.Copy(pbKey, pbLocalKey, 32);
r.KeySize = 256;
r.Key = pbLocalKey;
r.Mode = m_rCipherMode;
r.Padding = m_rCipherPadding;
ICryptoTransform iTransform = (bEncrypt ? r.CreateEncryptor() : r.CreateDecryptor());
Debug.Assert(iTransform != null);
if(iTransform == null) throw new SecurityException("Unable to create Rijndael transform!");
return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write :
CryptoStreamMode.Read);
}
public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV)
{
return StandardAesEngine.CreateStream(sPlainText, true, pbKey, pbIV);
}
public Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV)
{
return StandardAesEngine.CreateStream(sEncrypted, false, pbKey, pbIV);
}
}
}

View File

@ -0,0 +1,283 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Security;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;
using KeePassLib.Native;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography
{
/// <summary>
/// Cryptographically strong random number generator. The returned values
/// are unpredictable and cannot be reproduced.
/// <c>CryptoRandom</c> is a singleton class.
/// </summary>
public sealed class CryptoRandom
{
private byte[] m_pbEntropyPool = new byte[64];
private uint m_uCounter;
private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider();
private ulong m_uGeneratedBytesCount = 0;
private object m_oSyncRoot = new object();
private static CryptoRandom m_pInstance = null;
public static CryptoRandom Instance
{
get
{
if(m_pInstance != null) return m_pInstance;
m_pInstance = new CryptoRandom();
return m_pInstance;
}
}
/// <summary>
/// Get the number of random bytes that this instance generated so far.
/// Note that this number can be higher than the number of random bytes
/// actually requested using the <c>GetRandomBytes</c> method.
/// </summary>
public ulong GeneratedBytesCount
{
get
{
ulong u;
lock(m_oSyncRoot) { u = m_uGeneratedBytesCount; }
return u;
}
}
/// <summary>
/// Event that is triggered whenever the internal <c>GenerateRandom256</c>
/// method is called to generate random bytes.
/// </summary>
public event EventHandler GenerateRandom256Pre;
private CryptoRandom()
{
Random r = new Random();
m_uCounter = (uint)r.Next();
AddEntropy(GetSystemData(r));
AddEntropy(GetCspData());
}
/// <summary>
/// Update the internal seed of the random number generator based
/// on entropy data.
/// This method is thread-safe.
/// </summary>
/// <param name="pbEntropy">Entropy bytes.</param>
public void AddEntropy(byte[] pbEntropy)
{
if(pbEntropy == null) { Debug.Assert(false); return; }
if(pbEntropy.Length == 0) { Debug.Assert(false); return; }
byte[] pbNewData = pbEntropy;
if(pbEntropy.Length >= 64)
{
#if !KeePassLibSD
SHA512Managed shaNew = new SHA512Managed();
#else
SHA256Managed shaNew = new SHA256Managed();
#endif
pbNewData = shaNew.ComputeHash(pbEntropy);
}
MemoryStream ms = new MemoryStream();
lock(m_oSyncRoot)
{
ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length);
ms.Write(pbNewData, 0, pbNewData.Length);
byte[] pbFinal = ms.ToArray();
#if !KeePassLibSD
Debug.Assert(pbFinal.Length == (64 + pbNewData.Length));
SHA512Managed shaPool = new SHA512Managed();
#else
SHA256Managed shaPool = new SHA256Managed();
#endif
m_pbEntropyPool = shaPool.ComputeHash(pbFinal);
}
ms.Close();
}
private static byte[] GetSystemData(Random rWeak)
{
MemoryStream ms = new MemoryStream();
byte[] pb;
pb = MemUtil.UInt32ToBytes((uint)Environment.TickCount);
ms.Write(pb, 0, pb.Length);
pb = TimeUtil.PackTime(DateTime.Now);
ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD
Point pt = Cursor.Position;
pb = MemUtil.UInt32ToBytes((uint)pt.X);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)pt.Y);
ms.Write(pb, 0, pb.Length);
#endif
pb = MemUtil.UInt32ToBytes((uint)rWeak.Next());
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID());
ms.Write(pb, 0, pb.Length);
#if !KeePassLibSD
try
{
pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)Environment.WorkingSet);
ms.Write(pb, 0, pb.Length);
Version v = Environment.OSVersion.Version;
int nv = (v.Major << 28) + (v.MajorRevision << 24) +
(v.Minor << 20) + (v.MinorRevision << 16) +
(v.Revision << 12) + v.Build;
pb = MemUtil.UInt32ToBytes((uint)nv);
ms.Write(pb, 0, pb.Length);
Process p = Process.GetCurrentProcess();
pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64());
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)p.HandleCount);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt32ToBytes((uint)p.Id);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.NonpagedSystemMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PagedMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PagedSystemMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PeakPagedMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PeakVirtualMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PeakWorkingSet64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.PrivateMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.StartTime.ToBinary());
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.VirtualMemorySize64);
ms.Write(pb, 0, pb.Length);
pb = MemUtil.UInt64ToBytes((ulong)p.WorkingSet64);
ms.Write(pb, 0, pb.Length);
// Not supported in Mono 1.2.6:
// pb = MemUtil.UInt32ToBytes((uint)p.SessionId);
// ms.Write(pb, 0, pb.Length);
}
catch(Exception) { }
#endif
pb = Guid.NewGuid().ToByteArray();
ms.Write(pb, 0, pb.Length);
byte[] pbAll = ms.ToArray();
ms.Close();
return pbAll;
}
private byte[] GetCspData()
{
byte[] pbCspRandom = new byte[32];
m_rng.GetBytes(pbCspRandom);
return pbCspRandom;
}
private byte[] GenerateRandom256()
{
if(this.GenerateRandom256Pre != null)
this.GenerateRandom256Pre(this, EventArgs.Empty);
byte[] pbFinal;
lock(m_oSyncRoot)
{
unchecked { m_uCounter += 386047; } // Prime number
byte[] pbCounter = MemUtil.UInt32ToBytes(m_uCounter);
byte[] pbCspRandom = GetCspData();
MemoryStream ms = new MemoryStream();
ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length);
ms.Write(pbCounter, 0, pbCounter.Length);
ms.Write(pbCspRandom, 0, pbCspRandom.Length);
pbFinal = ms.ToArray();
Debug.Assert(pbFinal.Length == (m_pbEntropyPool.Length +
pbCounter.Length + pbCspRandom.Length));
ms.Close();
m_uGeneratedBytesCount += 32;
}
SHA256Managed sha256 = new SHA256Managed();
return sha256.ComputeHash(pbFinal);
}
/// <summary>
/// Get a number of cryptographically strong random bytes.
/// This method is thread-safe.
/// </summary>
/// <param name="uRequestedBytes">Number of requested random bytes.</param>
/// <returns>A byte array consisting of <paramref name="uRequestedBytes" />
/// random bytes.</returns>
public byte[] GetRandomBytes(uint uRequestedBytes)
{
if(uRequestedBytes == 0) return new byte[0]; // Allow zero-length array
byte[] pbRes = new byte[uRequestedBytes];
long lPos = 0;
while(uRequestedBytes != 0)
{
byte[] pbRandom256 = GenerateRandom256();
Debug.Assert(pbRandom256.Length == 32);
long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32);
#if !KeePassLibSD
Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy);
#else
Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy);
#endif
lPos += lCopy;
uRequestedBytes -= (uint)lCopy;
}
Debug.Assert((int)lPos == pbRes.Length);
return pbRes;
}
}
}

View File

@ -0,0 +1,209 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Diagnostics;
using System.Security.Cryptography;
using KeePassLib.Cryptography.Cipher;
namespace KeePassLib.Cryptography
{
/// <summary>
/// Algorithms supported by <c>CryptoRandomStream</c>.
/// </summary>
public enum CrsAlgorithm
{
/// <summary>
/// Not supported.
/// </summary>
Null = 0,
/// <summary>
/// A variant of the ARCFour algorithm (RC4 incompatible).
/// </summary>
ArcFourVariant = 1,
/// <summary>
/// Salsa20 stream cipher algorithm.
/// </summary>
Salsa20 = 2,
Count = 3
}
/// <summary>
/// A random stream class. The class is initialized using random
/// bytes provided by the caller. The produced stream has random
/// properties, but for the same seed always the same stream
/// is produced, i.e. this class can be used as stream cipher.
/// </summary>
public sealed class CryptoRandomStream
{
private CrsAlgorithm m_crsAlgorithm;
private byte[] m_pbState = null;
private byte m_i = 0;
private byte m_j = 0;
private Salsa20Cipher m_salsa20 = null;
/// <summary>
/// Construct a new cryptographically secure random stream object.
/// </summary>
/// <param name="genAlgorithm">Algorithm to use.</param>
/// <param name="pbKey">Initialization key. Must not be <c>null</c> and
/// must contain at least 1 byte.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the
/// <paramref name="pbKey" /> parameter is <c>null</c>.</exception>
/// <exception cref="System.ArgumentException">Thrown if the
/// <paramref name="pbKey" /> parameter contains no bytes or the
/// algorithm is unknown.</exception>
public CryptoRandomStream(CrsAlgorithm genAlgorithm, byte[] pbKey)
{
m_crsAlgorithm = genAlgorithm;
Debug.Assert(pbKey != null); if(pbKey == null) throw new ArgumentNullException("pbKey");
uint uKeyLen = (uint)pbKey.Length;
Debug.Assert(uKeyLen != 0); if(uKeyLen == 0) throw new ArgumentException();
if(genAlgorithm == CrsAlgorithm.ArcFourVariant)
{
// Fill the state linearly
m_pbState = new byte[256];
for(uint w = 0; w < 256; ++w) m_pbState[w] = (byte)w;
unchecked
{
byte j = 0, t;
uint inxKey = 0;
for(uint w = 0; w < 256; ++w) // Key setup
{
j += (byte)(m_pbState[w] + pbKey[inxKey]);
t = m_pbState[0]; // Swap entries
m_pbState[0] = m_pbState[j];
m_pbState[j] = t;
++inxKey;
if(inxKey >= uKeyLen) inxKey = 0;
}
}
GetRandomBytes(512); // Increases security, see cryptanalysis
}
else if(genAlgorithm == CrsAlgorithm.Salsa20)
{
SHA256Managed sha256 = new SHA256Managed();
byte[] pbKey32 = sha256.ComputeHash(pbKey);
byte[] pbIV = new byte[]{ 0xE8, 0x30, 0x09, 0x4B,
0x97, 0x20, 0x5D, 0x2A }; // Unique constant
m_salsa20 = new Salsa20Cipher(pbKey32, pbIV);
}
else // Unknown algorithm
{
Debug.Assert(false);
throw new ArgumentException();
}
}
/// <summary>
/// Get <paramref name="uRequestedCount" /> random bytes.
/// </summary>
/// <param name="uRequestedCount">Number of random bytes to retrieve.</param>
/// <returns>Returns <paramref name="uRequestedCount" /> random bytes.</returns>
public byte[] GetRandomBytes(uint uRequestedCount)
{
if(uRequestedCount == 0) return new byte[0];
byte[] pbRet = new byte[uRequestedCount];
if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant)
{
unchecked
{
for(uint w = 0; w < uRequestedCount; ++w)
{
++m_i;
m_j += m_pbState[m_i];
byte t = m_pbState[m_i]; // Swap entries
m_pbState[m_i] = m_pbState[m_j];
m_pbState[m_j] = t;
t = (byte)(m_pbState[m_i] + m_pbState[m_j]);
pbRet[w] = m_pbState[t];
}
}
}
else if(m_crsAlgorithm == CrsAlgorithm.Salsa20)
m_salsa20.Encrypt(pbRet, pbRet.Length, false);
else { Debug.Assert(false); }
return pbRet;
}
public ulong GetRandomUInt64()
{
byte[] pb = GetRandomBytes(8);
unchecked
{
return ((ulong)pb[0]) | ((ulong)pb[1] << 8) |
((ulong)pb[2] << 16) | ((ulong)pb[3] << 24) |
((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) |
((ulong)pb[6] << 48) | ((ulong)pb[7] << 56);
}
}
#if CRSBENCHMARK
public static string Benchmark()
{
int nRounds = 2000000;
string str = "ArcFour small: " + BenchTime(CrsAlgorithm.ArcFourVariant,
nRounds, 16).ToString() + "\r\n";
str += "ArcFour big: " + BenchTime(CrsAlgorithm.ArcFourVariant,
32, 2 * 1024 * 1024).ToString() + "\r\n";
str += "Salsa20 small: " + BenchTime(CrsAlgorithm.Salsa20,
nRounds, 16).ToString() + "\r\n";
str += "Salsa20 big: " + BenchTime(CrsAlgorithm.Salsa20,
32, 2 * 1024 * 1024).ToString();
return str;
}
private static int BenchTime(CrsAlgorithm cra, int nRounds, int nDataSize)
{
byte[] pbKey = new byte[4] { 0x00, 0x01, 0x02, 0x03 };
int nStart = Environment.TickCount;
for(int i = 0; i < nRounds; ++i)
{
CryptoRandomStream c = new CryptoRandomStream(cra, pbKey);
c.GetRandomBytes((uint)nDataSize);
}
int nEnd = Environment.TickCount;
return (nEnd - nStart);
}
#endif
}
}

View File

@ -0,0 +1,180 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography
{
public sealed class HashingStreamEx : Stream
{
private Stream m_sBaseStream;
private bool m_bWriting;
private HashAlgorithm m_hash;
private byte[] m_pbFinalHash = null;
public byte[] Hash
{
get { return m_pbFinalHash; }
}
public override bool CanRead
{
get { return !m_bWriting; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return m_bWriting; }
}
public override long Length
{
get { return m_sBaseStream.Length; }
}
public override long Position
{
get { return m_sBaseStream.Position; }
set { throw new NotSupportedException(); }
}
public HashingStreamEx(Stream sBaseStream, bool bWriting, HashAlgorithm hashAlgorithm)
{
if(sBaseStream == null) throw new ArgumentNullException("sBaseStream");
m_sBaseStream = sBaseStream;
m_bWriting = bWriting;
#if !KeePassLibSD
m_hash = (hashAlgorithm ?? new SHA256Managed());
#else // KeePassLibSD
m_hash = null;
try { m_hash = HashAlgorithm.Create("SHA256"); }
catch(Exception) { }
try { if(m_hash == null) m_hash = HashAlgorithm.Create(); }
catch(Exception) { }
#endif
if(m_hash == null) { Debug.Assert(false); return; }
// Validate hash algorithm
if((!m_hash.CanReuseTransform) || (!m_hash.CanTransformMultipleBlocks) ||
(m_hash.InputBlockSize != 1) || (m_hash.OutputBlockSize != 1))
{
#if DEBUG
MessageService.ShowWarning("Broken HashAlgorithm object in HashingStreamEx.");
#endif
m_hash = null;
}
}
public override void Flush()
{
m_sBaseStream.Flush();
}
public override void Close()
{
if(m_hash != null)
{
try
{
m_hash.TransformFinalBlock(new byte[0], 0, 0);
m_pbFinalHash = m_hash.Hash;
}
catch(Exception) { Debug.Assert(false); }
m_hash = null;
}
m_sBaseStream.Close();
}
public override long Seek(long lOffset, SeekOrigin soOrigin)
{
throw new NotSupportedException();
}
public override void SetLength(long lValue)
{
throw new NotSupportedException();
}
public override int Read(byte[] pbBuffer, int nOffset, int nCount)
{
if(m_bWriting) throw new InvalidOperationException();
int nRead = m_sBaseStream.Read(pbBuffer, nOffset, nCount);
int nPartialRead = nRead;
while((nRead < nCount) && (nPartialRead != 0))
{
nPartialRead = m_sBaseStream.Read(pbBuffer, nOffset + nRead,
nCount - nRead);
nRead += nPartialRead;
}
#if DEBUG
byte[] pbOrg = new byte[pbBuffer.Length];
Array.Copy(pbBuffer, pbOrg, pbBuffer.Length);
#endif
if((m_hash != null) && (nRead > 0))
m_hash.TransformBlock(pbBuffer, nOffset, nRead, pbBuffer, nOffset);
#if DEBUG
Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg));
#endif
return nRead;
}
public override void Write(byte[] pbBuffer, int nOffset, int nCount)
{
if(!m_bWriting) throw new InvalidOperationException();
#if DEBUG
byte[] pbOrg = new byte[pbBuffer.Length];
Array.Copy(pbBuffer, pbOrg, pbBuffer.Length);
#endif
if((m_hash != null) && (nCount > 0))
m_hash.TransformBlock(pbBuffer, nOffset, nCount, pbBuffer, nOffset);
#if DEBUG
Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg));
#endif
m_sBaseStream.Write(pbBuffer, nOffset, nCount);
}
}
}

View File

@ -0,0 +1,90 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Security.Cryptography;
using KeePassLib.Utility;
#if !KeePassLibSD
namespace KeePassLib.Cryptography
{
/// <summary>
/// Generate HMAC-based one-time passwords as specified in RFC 4226.
/// </summary>
public static class HmacOtp
{
private static readonly uint[] vDigitsPower = new uint[]{ 1, 10, 100,
1000, 10000, 100000, 1000000, 10000000, 100000000 };
public static string Generate(byte[] pbSecret, ulong uFactor,
uint uCodeDigits, bool bAddChecksum, int iTruncationOffset)
{
byte[] pbText = MemUtil.UInt64ToBytes(uFactor);
Array.Reverse(pbText); // Big-Endian
HMACSHA1 hsha1 = new HMACSHA1(pbSecret);
byte[] pbHash = hsha1.ComputeHash(pbText);
uint uOffset = (uint)(pbHash[pbHash.Length - 1] & 0xF);
if((iTruncationOffset >= 0) && (iTruncationOffset < (pbHash.Length - 4)))
uOffset = (uint)iTruncationOffset;
uint uBinary = (uint)(((pbHash[uOffset] & 0x7F) << 24) |
((pbHash[uOffset + 1] & 0xFF) << 16) |
((pbHash[uOffset + 2] & 0xFF) << 8) |
(pbHash[uOffset + 3] & 0xFF));
uint uOtp = (uBinary % vDigitsPower[uCodeDigits]);
if(bAddChecksum)
uOtp = ((uOtp * 10) + CalculateChecksum(uOtp, uCodeDigits));
uint uDigits = (bAddChecksum ? (uCodeDigits + 1) : uCodeDigits);
return uOtp.ToString().PadLeft((int)uDigits, '0');
}
private static readonly uint[] vDoubleDigits = new uint[]{ 0, 2, 4, 6, 8,
1, 3, 5, 7, 9 };
private static uint CalculateChecksum(uint uNum, uint uDigits)
{
bool bDoubleDigit = true;
uint uTotal = 0;
while(0 < uDigits--)
{
uint uDigit = (uNum % 10);
uNum /= 10;
if(bDoubleDigit) uDigit = vDoubleDigits[uDigit];
uTotal += uDigit;
bDoubleDigit = !bDoubleDigit;
}
uint uResult = (uTotal % 10);
if(uResult != 0) uResult = 10 - uResult;
return uResult;
}
}
}
#endif

View File

@ -0,0 +1,65 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography.PasswordGenerator
{
internal static class CharSetBasedGenerator
{
internal static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crsRandomSource)
{
psOut = ProtectedString.Empty;
if(pwProfile.Length == 0) return PwgError.Success;
PwCharSet pcs = new PwCharSet(pwProfile.CharSet.ToString());
char[] vGenerated = new char[pwProfile.Length];
PwGenerator.PrepareCharSet(pcs, pwProfile);
for(int nIndex = 0; nIndex < (int)pwProfile.Length; ++nIndex)
{
char ch = PwGenerator.GenerateCharacter(pwProfile, pcs,
crsRandomSource);
if(ch == char.MinValue)
{
Array.Clear(vGenerated, 0, vGenerated.Length);
return PwgError.TooFewCharacters;
}
vGenerated[nIndex] = ch;
}
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated);
psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vGenerated, 0, vGenerated.Length);
return PwgError.Success;
}
}
}

View File

@ -0,0 +1,66 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using KeePassLib;
using KeePassLib.Security;
namespace KeePassLib.Cryptography.PasswordGenerator
{
public abstract class CustomPwGenerator
{
/// <summary>
/// Each custom password generation algorithm must have
/// its own unique UUID.
/// </summary>
public abstract PwUuid Uuid { get; }
/// <summary>
/// Displayable name of the password generation algorithm.
/// </summary>
public abstract string Name { get; }
public virtual bool SupportsOptions
{
get { return false; }
}
/// <summary>
/// Password generation function.
/// </summary>
/// <param name="prf">Password generation options chosen
/// by the user. This may be <c>null</c>, if the default
/// options should be used.</param>
/// <param name="crsRandomSource">Source that the algorithm
/// can use to generate random numbers.</param>
/// <returns>Generated password or <c>null</c> in case
/// of failure. If returning <c>null</c>, the caller assumes
/// that an error message has already been shown to the user.</returns>
public abstract ProtectedString Generate(PwProfile prf,
CryptoRandomStream crsRandomSource);
public virtual string GetOptions(string strCurrentOptions)
{
return string.Empty;
}
}
}

View File

@ -0,0 +1,110 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Text;
namespace KeePassLib.Cryptography.PasswordGenerator
{
public sealed class CustomPwGeneratorPool : IEnumerable<CustomPwGenerator>
{
private List<CustomPwGenerator> m_vGens = new List<CustomPwGenerator>();
public int Count
{
get { return m_vGens.Count; }
}
public CustomPwGeneratorPool()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vGens.GetEnumerator();
}
public IEnumerator<CustomPwGenerator> GetEnumerator()
{
return m_vGens.GetEnumerator();
}
public void Add(CustomPwGenerator pwg)
{
if(pwg == null) throw new ArgumentNullException("pwg");
PwUuid uuid = pwg.Uuid;
if(uuid == null) throw new ArgumentException();
int nIndex = FindIndex(uuid);
if(nIndex >= 0) m_vGens[nIndex] = pwg; // Replace
else m_vGens.Add(pwg);
}
public CustomPwGenerator Find(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
foreach(CustomPwGenerator pwg in m_vGens)
{
if(uuid.EqualsValue(pwg.Uuid)) return pwg;
}
return null;
}
public CustomPwGenerator Find(string strName)
{
if(strName == null) throw new ArgumentNullException("strName");
foreach(CustomPwGenerator pwg in m_vGens)
{
if(pwg.Name == strName) return pwg;
}
return null;
}
private int FindIndex(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
for(int i = 0; i < m_vGens.Count; ++i)
{
if(uuid.EqualsValue(m_vGens[i].Uuid)) return i;
}
return -1;
}
public bool Remove(PwUuid uuid)
{
if(uuid == null) throw new ArgumentNullException("uuid");
int nIndex = FindIndex(uuid);
if(nIndex < 0) return false;
m_vGens.RemoveAt(nIndex);
return true;
}
}
}

View File

@ -0,0 +1,173 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography.PasswordGenerator
{
internal static class PatternBasedGenerator
{
internal static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crsRandomSource)
{
psOut = ProtectedString.Empty;
LinkedList<char> vGenerated = new LinkedList<char>();
PwCharSet pcsCurrent = new PwCharSet();
PwCharSet pcsCustom = new PwCharSet();
PwCharSet pcsUsed = new PwCharSet();
bool bInCharSetDef = false;
string strPattern = ExpandPattern(pwProfile.Pattern);
if(strPattern.Length == 0) return PwgError.Success;
CharStream csStream = new CharStream(strPattern);
char ch = csStream.ReadChar();
while(ch != char.MinValue)
{
pcsCurrent.Clear();
bool bGenerateChar = false;
if(ch == '\\')
{
ch = csStream.ReadChar();
if(ch == char.MinValue) // Backslash at the end
{
vGenerated.AddLast('\\');
break;
}
if(bInCharSetDef) pcsCustom.Add(ch);
else
{
vGenerated.AddLast(ch);
pcsUsed.Add(ch);
}
}
else if(ch == '[')
{
pcsCustom.Clear();
bInCharSetDef = true;
}
else if(ch == ']')
{
pcsCurrent.Add(pcsCustom.ToString());
bInCharSetDef = false;
bGenerateChar = true;
}
else if(bInCharSetDef)
{
if(pcsCustom.AddCharSet(ch) == false)
pcsCustom.Add(ch);
}
else if(pcsCurrent.AddCharSet(ch) == false)
{
vGenerated.AddLast(ch);
pcsUsed.Add(ch);
}
else bGenerateChar = true;
if(bGenerateChar)
{
PwGenerator.PrepareCharSet(pcsCurrent, pwProfile);
if(pwProfile.NoRepeatingCharacters)
pcsCurrent.Remove(pcsUsed.ToString());
char chGen = PwGenerator.GenerateCharacter(pwProfile,
pcsCurrent, crsRandomSource);
if(chGen == char.MinValue) return PwgError.TooFewCharacters;
vGenerated.AddLast(chGen);
pcsUsed.Add(chGen);
}
ch = csStream.ReadChar();
}
if(vGenerated.Count == 0) return PwgError.Success;
char[] vArray = new char[vGenerated.Count];
vGenerated.CopyTo(vArray, 0);
if(pwProfile.PatternPermutePassword)
PwGenerator.ShufflePassword(vArray, crsRandomSource);
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vArray);
psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vArray, 0, vArray.Length);
vGenerated.Clear();
return PwgError.Success;
}
private static string ExpandPattern(string strPattern)
{
Debug.Assert(strPattern != null); if(strPattern == null) return string.Empty;
string str = strPattern;
while(true)
{
int nOpen = FindFirstUnescapedChar(str, '{');
int nClose = FindFirstUnescapedChar(str, '}');
if((nOpen >= 0) && (nOpen < nClose))
{
string strCount = str.Substring(nOpen + 1, nClose - nOpen - 1);
str = str.Remove(nOpen, nClose - nOpen + 1);
uint uRepeat;
if(StrUtil.TryParseUInt(strCount, out uRepeat) && (nOpen >= 1))
{
if(uRepeat == 0)
str = str.Remove(nOpen - 1, 1);
else
str = str.Insert(nOpen, new string(str[nOpen - 1], (int)uRepeat - 1));
}
}
else break;
}
return str;
}
private static int FindFirstUnescapedChar(string str, char ch)
{
for(int i = 0; i < str.Length; ++i)
{
char chCur = str[i];
if(chCur == '\\') ++i; // Next is escaped, skip it
else if(chCur == ch) return i;
}
return -1;
}
}
}

View File

@ -0,0 +1,318 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
namespace KeePassLib.Cryptography.PasswordGenerator
{
public sealed class PwCharSet
{
public const string UpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public const string LowerCase = "abcdefghijklmnopqrstuvwxyz";
public const string Digits = "0123456789";
public const string UpperConsonants = "BCDFGHJKLMNPQRSTVWXYZ";
public const string LowerConsonants = "bcdfghjklmnpqrstvwxyz";
public const string UpperVowels = "AEIOU";
public const string LowerVowels = "aeiou";
public const string Punctuation = @",.;:";
public const string Brackets = @"[]{}()<>";
public const string PrintableAsciiSpecial = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
public const string UpperHex = "0123456789ABCDEF";
public const string LowerHex = "0123456789abcdef";
public const string Invalid = "\t\r\n";
public const string LookAlike = @"O0l1I|";
private const int CharTabSize = (0x10000 / 8);
private List<char> m_vChars = new List<char>();
private byte[] m_vTab = new byte[CharTabSize];
private string m_strHighAnsi = string.Empty;
private string m_strSpecial = string.Empty;
/// <summary>
/// Create a new, empty character set collection object.
/// </summary>
public PwCharSet()
{
this.Initialize(true);
}
public PwCharSet(string strCharSet)
{
this.Initialize(true);
this.Add(strCharSet);
}
private PwCharSet(bool bFullInitialize)
{
this.Initialize(bFullInitialize);
}
private void Initialize(bool bFullInitialize)
{
this.Clear();
if(bFullInitialize == false) return;
StringBuilder sbHighAnsi = new StringBuilder();
for(char ch = '~'; ch < 255; ++ch)
sbHighAnsi.Append(ch);
m_strHighAnsi = sbHighAnsi.ToString();
PwCharSet pcs = new PwCharSet(false);
pcs.AddRange('!', '/');
pcs.AddRange(':', '@');
pcs.AddRange('[', '`');
pcs.Remove(@"-_ ");
pcs.Remove(PwCharSet.Brackets);
m_strSpecial = pcs.ToString();
}
/// <summary>
/// Number of characters in this set.
/// </summary>
public uint Size
{
get { return (uint)m_vChars.Count; }
}
/// <summary>
/// Get a character of the set using an index.
/// </summary>
/// <param name="uPos">Index of the character to get.</param>
/// <returns>Character at the specified position. If the index is invalid,
/// an <c>ArgumentOutOfRangeException</c> is thrown.</returns>
public char this[uint uPos]
{
get
{
if(uPos >= (uint)m_vChars.Count)
throw new ArgumentOutOfRangeException("uPos");
return m_vChars[(int)uPos];
}
}
public string SpecialChars { get { return m_strSpecial; } }
public string HighAnsiChars { get { return m_strHighAnsi; } }
/// <summary>
/// Remove all characters from this set.
/// </summary>
public void Clear()
{
m_vChars.Clear();
Array.Clear(m_vTab, 0, m_vTab.Length);
}
public bool Contains(char ch)
{
return (((m_vTab[ch / 8] >> (ch % 8)) & 1) != char.MinValue);
}
public bool Contains(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
foreach(char ch in strCharacters)
{
if(this.Contains(ch) == false) return false;
}
return true;
}
/// <summary>
/// Add characters to the set.
/// </summary>
/// <param name="ch">Character to add.</param>
public void Add(char ch)
{
if(ch == char.MinValue) { Debug.Assert(false); return; }
if(this.Contains(ch) == false)
{
m_vChars.Add(ch);
m_vTab[ch / 8] |= (byte)(1 << (ch % 8));
}
}
/// <summary>
/// Add characters to the set.
/// </summary>
/// <param name="strCharSet">String containing characters to add.</param>
public void Add(string strCharSet)
{
Debug.Assert(strCharSet != null);
if(strCharSet == null) throw new ArgumentNullException("strCharSet");
m_vChars.Capacity = m_vChars.Count + strCharSet.Length;
foreach(char ch in strCharSet)
this.Add(ch);
}
public void Add(string strCharSet1, string strCharSet2)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
}
public void Add(string strCharSet1, string strCharSet2, string strCharSet3)
{
this.Add(strCharSet1);
this.Add(strCharSet2);
this.Add(strCharSet3);
}
public void AddRange(char chMin, char chMax)
{
m_vChars.Capacity = m_vChars.Count + (chMax - chMin) + 1;
for(char ch = chMin; ch < chMax; ++ch)
this.Add(ch);
this.Add(chMax);
}
public bool AddCharSet(char chCharSetIdentifier)
{
bool bResult = true;
switch(chCharSetIdentifier)
{
case 'a': this.Add(PwCharSet.LowerCase, PwCharSet.Digits); break;
case 'A': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase,
PwCharSet.Digits); break;
case 'U': this.Add(PwCharSet.UpperCase, PwCharSet.Digits); break;
case 'c': this.Add(PwCharSet.LowerConsonants); break;
case 'C': this.Add(PwCharSet.LowerConsonants,
PwCharSet.UpperConsonants); break;
case 'z': this.Add(PwCharSet.UpperConsonants); break;
case 'd': this.Add(PwCharSet.Digits); break; // Digit
case 'h': this.Add(PwCharSet.LowerHex); break;
case 'H': this.Add(PwCharSet.UpperHex); break;
case 'l': this.Add(PwCharSet.LowerCase); break;
case 'L': this.Add(PwCharSet.LowerCase, PwCharSet.UpperCase); break;
case 'u': this.Add(PwCharSet.UpperCase); break;
case 'p': this.Add(PwCharSet.Punctuation); break;
case 'b': this.Add(PwCharSet.Brackets); break;
case 's': this.Add(PwCharSet.PrintableAsciiSpecial); break;
case 'S': this.Add(PwCharSet.UpperCase, PwCharSet.LowerCase);
this.Add(PwCharSet.Digits, PwCharSet.PrintableAsciiSpecial); break;
case 'v': this.Add(PwCharSet.LowerVowels); break;
case 'V': this.Add(PwCharSet.LowerVowels, PwCharSet.UpperVowels); break;
case 'Z': this.Add(PwCharSet.UpperVowels); break;
case 'x': this.Add(m_strHighAnsi); break;
default: bResult = false; break;
}
return bResult;
}
public bool Remove(char ch)
{
m_vTab[ch / 8] &= (byte)~(1 << (ch % 8));
return m_vChars.Remove(ch);
}
public bool Remove(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
bool bResult = true;
foreach(char ch in strCharacters)
{
if(!Remove(ch)) bResult = false;
}
return bResult;
}
public bool RemoveIfAllExist(string strCharacters)
{
Debug.Assert(strCharacters != null);
if(strCharacters == null) throw new ArgumentNullException("strCharacters");
if(this.Contains(strCharacters) == false)
return false;
return this.Remove(strCharacters);
}
/// <summary>
/// Convert the character set to a string containing all its characters.
/// </summary>
/// <returns>String containing all character set characters.</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach(char ch in m_vChars)
sb.Append(ch);
return sb.ToString();
}
public string PackAndRemoveCharRanges()
{
StringBuilder sb = new StringBuilder();
sb.Append(this.RemoveIfAllExist(PwCharSet.UpperCase) ? 'U' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.LowerCase) ? 'L' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Digits) ? 'D' : '_');
sb.Append(this.RemoveIfAllExist(m_strSpecial) ? 'S' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Punctuation) ? 'P' : '_');
sb.Append(this.RemoveIfAllExist(@"-") ? 'm' : '_');
sb.Append(this.RemoveIfAllExist(@"_") ? 'u' : '_');
sb.Append(this.RemoveIfAllExist(@" ") ? 's' : '_');
sb.Append(this.RemoveIfAllExist(PwCharSet.Brackets) ? 'B' : '_');
sb.Append(this.RemoveIfAllExist(m_strHighAnsi) ? 'H' : '_');
return sb.ToString();
}
public void UnpackCharRanges(string strRanges)
{
if(strRanges == null) { Debug.Assert(false); return; }
if(strRanges.Length < 10) { Debug.Assert(false); return; }
if(strRanges[0] != '_') this.Add(PwCharSet.UpperCase);
if(strRanges[1] != '_') this.Add(PwCharSet.LowerCase);
if(strRanges[2] != '_') this.Add(PwCharSet.Digits);
if(strRanges[3] != '_') this.Add(m_strSpecial);
if(strRanges[4] != '_') this.Add(PwCharSet.Punctuation);
if(strRanges[5] != '_') this.Add('-');
if(strRanges[6] != '_') this.Add('_');
if(strRanges[7] != '_') this.Add(' ');
if(strRanges[8] != '_') this.Add(PwCharSet.Brackets);
if(strRanges[9] != '_') this.Add(m_strHighAnsi);
}
}
}

View File

@ -0,0 +1,146 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using KeePassLib.Security;
namespace KeePassLib.Cryptography.PasswordGenerator
{
public enum PwgError
{
Success = 0,
Unknown = 1,
TooFewCharacters = 2,
UnknownAlgorithm = 3
}
/// <summary>
/// Utility functions for generating random passwords.
/// </summary>
public static class PwGenerator
{
public static PwgError Generate(out ProtectedString psOut,
PwProfile pwProfile, byte[] pbUserEntropy,
CustomPwGeneratorPool pwAlgorithmPool)
{
Debug.Assert(pwProfile != null);
if(pwProfile == null) throw new ArgumentNullException("pwProfile");
CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy);
PwgError e = PwgError.Unknown;
if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet)
e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs);
else if(pwProfile.GeneratorType == PasswordGeneratorType.Pattern)
e = PatternBasedGenerator.Generate(out psOut, pwProfile, crs);
else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom)
e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool);
else { Debug.Assert(false); psOut = ProtectedString.Empty; }
return e;
}
private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy)
{
byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(256);
// Mix in additional entropy
if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))
{
for(int nKeyPos = 0; nKeyPos < pbKey.Length; ++nKeyPos)
pbKey[nKeyPos] ^= pbAdditionalEntropy[nKeyPos % pbAdditionalEntropy.Length];
}
return new CryptoRandomStream(CrsAlgorithm.Salsa20, pbKey);
}
internal static char GenerateCharacter(PwProfile pwProfile,
PwCharSet pwCharSet, CryptoRandomStream crsRandomSource)
{
if(pwCharSet.Size == 0) return char.MinValue;
ulong uIndex = crsRandomSource.GetRandomUInt64();
uIndex %= (ulong)pwCharSet.Size;
char ch = pwCharSet[(uint)uIndex];
if(pwProfile.NoRepeatingCharacters)
pwCharSet.Remove(ch);
return ch;
}
internal static void PrepareCharSet(PwCharSet pwCharSet, PwProfile pwProfile)
{
pwCharSet.Remove(PwCharSet.Invalid);
if(pwProfile.ExcludeLookAlike) pwCharSet.Remove(PwCharSet.LookAlike);
if(pwProfile.ExcludeCharacters.Length > 0)
pwCharSet.Remove(pwProfile.ExcludeCharacters);
}
internal static void ShufflePassword(char[] pPassword,
CryptoRandomStream crsRandomSource)
{
Debug.Assert(pPassword != null); if(pPassword == null) return;
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) return;
if(pPassword.Length <= 1) return; // Nothing to shuffle
for(int nSelect = 0; nSelect < pPassword.Length; ++nSelect)
{
ulong uRandomIndex = crsRandomSource.GetRandomUInt64();
uRandomIndex %= (ulong)(pPassword.Length - nSelect);
char chTemp = pPassword[nSelect];
pPassword[nSelect] = pPassword[nSelect + (int)uRandomIndex];
pPassword[nSelect + (int)uRandomIndex] = chTemp;
}
}
private static PwgError GenerateCustom(out ProtectedString psOut,
PwProfile pwProfile, CryptoRandomStream crs,
CustomPwGeneratorPool pwAlgorithmPool)
{
psOut = ProtectedString.Empty;
Debug.Assert(pwProfile.GeneratorType == PasswordGeneratorType.Custom);
if(pwAlgorithmPool == null) return PwgError.UnknownAlgorithm;
string strID = pwProfile.CustomAlgorithmUuid;
if(string.IsNullOrEmpty(strID)) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
byte[] pbUuid = Convert.FromBase64String(strID);
PwUuid uuid = new PwUuid(pbUuid);
CustomPwGenerator pwg = pwAlgorithmPool.Find(uuid);
if(pwg == null) { Debug.Assert(false); return PwgError.UnknownAlgorithm; }
ProtectedString pwd = pwg.Generate(pwProfile.CloneDeep(), crs);
if(pwd == null) return PwgError.Unknown;
psOut = pwd;
return PwgError.Success;
}
}
}

View File

@ -0,0 +1,277 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Diagnostics;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Cryptography.PasswordGenerator
{
/// <summary>
/// Type of the password generator. Different types like generators
/// based on given patterns, based on character sets, etc. are
/// available.
/// </summary>
public enum PasswordGeneratorType
{
/// <summary>
/// Generator based on character spaces/sets, i.e. groups
/// of characters like lower-case, upper-case or numeric characters.
/// </summary>
CharSet = 0,
/// <summary>
/// Password generation based on a pattern. The user has provided
/// a pattern, which describes how the generated password has to
/// look like.
/// </summary>
Pattern = 1,
Custom = 2
}
public sealed class PwProfile : IDeepCloneable<PwProfile>
{
private string m_strName = string.Empty;
[DefaultValue("")]
public string Name
{
get { return m_strName; }
set { m_strName = value; }
}
private PasswordGeneratorType m_type = PasswordGeneratorType.CharSet;
public PasswordGeneratorType GeneratorType
{
get { return m_type; }
set { m_type = value; }
}
private bool m_bUserEntropy = false;
[DefaultValue(false)]
public bool CollectUserEntropy
{
get { return m_bUserEntropy; }
set { m_bUserEntropy = value; }
}
private uint m_uLength = 20;
public uint Length
{
get { return m_uLength; }
set { m_uLength = value; }
}
private PwCharSet m_pwCharSet = new PwCharSet(PwCharSet.UpperCase +
PwCharSet.LowerCase + PwCharSet.Digits);
[XmlIgnore]
public PwCharSet CharSet
{
get { return m_pwCharSet; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_pwCharSet = value;
}
}
private string m_strCharSetRanges = string.Empty;
[DefaultValue("")]
public string CharSetRanges
{
get { this.UpdateCharSet(true); return m_strCharSetRanges; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCharSetRanges = value;
this.UpdateCharSet(false);
}
}
private string m_strCharSetAdditional = string.Empty;
[DefaultValue("")]
public string CharSetAdditional
{
get { this.UpdateCharSet(true); return m_strCharSetAdditional; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCharSetAdditional = value;
this.UpdateCharSet(false);
}
}
private string m_strPattern = string.Empty;
[DefaultValue("")]
public string Pattern
{
get { return m_strPattern; }
set { m_strPattern = value; }
}
private bool m_bPatternPermute = false;
[DefaultValue(false)]
public bool PatternPermutePassword
{
get { return m_bPatternPermute; }
set { m_bPatternPermute = value; }
}
private bool m_bNoLookAlike = false;
[DefaultValue(false)]
public bool ExcludeLookAlike
{
get { return m_bNoLookAlike; }
set { m_bNoLookAlike = value; }
}
private bool m_bNoRepeat = false;
[DefaultValue(false)]
public bool NoRepeatingCharacters
{
get { return m_bNoRepeat; }
set { m_bNoRepeat = value; }
}
private string m_strExclude = string.Empty;
[DefaultValue("")]
public string ExcludeCharacters
{
get { return m_strExclude; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strExclude = value;
}
}
private string m_strCustomID = string.Empty;
[DefaultValue("")]
public string CustomAlgorithmUuid
{
get { return m_strCustomID; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCustomID = value;
}
}
private string m_strCustomOpt = string.Empty;
[DefaultValue("")]
public string CustomAlgorithmOptions
{
get { return m_strCustomOpt; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strCustomOpt = value;
}
}
public PwProfile()
{
}
public PwProfile CloneDeep()
{
PwProfile p = new PwProfile();
p.m_strName = m_strName;
p.m_type = m_type;
p.m_bUserEntropy = m_bUserEntropy;
p.m_uLength = m_uLength;
p.m_pwCharSet = new PwCharSet(m_pwCharSet.ToString());
p.m_strCharSetRanges = m_strCharSetRanges;
p.m_strCharSetAdditional = m_strCharSetAdditional;
p.m_strPattern = m_strPattern;
p.m_bPatternPermute = m_bPatternPermute;
p.m_bNoLookAlike = m_bNoLookAlike;
p.m_bNoRepeat = m_bNoRepeat;
p.m_strExclude = m_strExclude;
p.m_strCustomID = m_strCustomID;
p.m_strCustomOpt = m_strCustomOpt;
return p;
}
private void UpdateCharSet(bool bSetXml)
{
if(bSetXml)
{
PwCharSet pcs = new PwCharSet(m_pwCharSet.ToString());
m_strCharSetRanges = pcs.PackAndRemoveCharRanges();
m_strCharSetAdditional = pcs.ToString();
}
else
{
PwCharSet pcs = new PwCharSet(m_strCharSetAdditional);
pcs.UnpackCharRanges(m_strCharSetRanges);
m_pwCharSet = pcs;
}
}
public static PwProfile DeriveFromPassword(ProtectedString psPassword)
{
PwProfile pp = new PwProfile();
Debug.Assert(psPassword != null); if(psPassword == null) return pp;
byte[] pbUtf8 = psPassword.ReadUtf8();
char[] vChars = StrUtil.Utf8.GetChars(pbUtf8);
pp.GeneratorType = PasswordGeneratorType.CharSet;
pp.Length = (uint)vChars.Length;
PwCharSet pcs = pp.CharSet;
pcs.Clear();
foreach(char ch in vChars)
{
if((ch >= 'A') && (ch <= 'Z')) pcs.Add(PwCharSet.UpperCase);
else if((ch >= 'a') && (ch <= 'z')) pcs.Add(PwCharSet.LowerCase);
else if((ch >= '0') && (ch <= '9')) pcs.Add(PwCharSet.Digits);
else if((@"!#$%&'*+,./:;=?@^").IndexOf(ch) >= 0) pcs.Add(pcs.SpecialChars);
else if(ch == ' ') pcs.Add(' ');
else if(ch == '-') pcs.Add('-');
else if(ch == '_') pcs.Add('_');
else if(ch == '\"') pcs.Add(pcs.SpecialChars);
else if(ch == '\\') pcs.Add(pcs.SpecialChars);
else if((@"()[]{}<>").IndexOf(ch) >= 0) pcs.Add(PwCharSet.Brackets);
else if((ch >= '~') && (ch <= 255)) pcs.Add(pcs.HighAnsiChars);
else pcs.Add(ch);
}
Array.Clear(vChars, 0, vChars.Length);
MemUtil.ZeroByteArray(pbUtf8);
return pp;
}
public bool HasSecurityReducingOption()
{
return (m_bNoLookAlike || m_bNoRepeat || (m_strExclude.Length > 0));
}
}
}

View File

@ -0,0 +1,540 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Security.Cryptography;
using System.Globalization;
using System.Diagnostics;
using KeePassLib.Utility;
#if !KeePassLibSD
namespace KeePassLib.Cryptography
{
/// <summary>
/// Bloom filter-based popular password checking.
/// </summary>
public static class PopularPasswords
{
private const int PpcTableSize = 8192 * 8; // Bits, multiple of 64
// Bits set: 32433 of 65536
// Hash functions: 32
// Phi (bits unset ratio) estimation: 0.505455388896019
// Exact Phi: 0.505111694335938
// False positives ratio: 1.67583063859565E-10
private static readonly ulong[] PpcTable = {
0x60383D3A85560B9BUL, 0x2578CE9D37C6AEB7UL, 0xF509A5743FD03228UL,
0x19B7455E8933EE56UL, 0x5EA419ADCFD9C20EUL, 0xEA618EFC0B37A162UL,
0xE0FD4D1FFF1CE415UL, 0x7A649E0301BB6060UL, 0x80D9CD9F9EEB603DUL,
0x47D6010D0D6E6CDEUL, 0x2552708C589EB554UL, 0x073F1A3DB3267502UL,
0x3313FEC2A2FEA475UL, 0x4593665C44934FEBUL, 0x410A301A23660395UL,
0x6AD06DA533FF5659UL, 0x423DAF86F3E41F4AUL, 0x82F035A971C6FD18UL,
0xB5E9139F28C93223UL, 0x1D07C3F4160585CAUL, 0x24B01EDB6B23E2C5UL,
0xD52F25B724F936C9UL, 0x8018392517836928UL, 0x3AA4C0F8E181EDA2UL,
0x8D93683EF7D52529UL, 0x6164BB6208114460UL, 0x737A04D8FEF3D88FUL,
0x3400097098D5C2CBUL, 0x3C2B9ABE5C455B2EUL, 0x3A3819973AB32DA2UL,
0x38ACB428510AF40BUL, 0x83320D5114B74771UL, 0xC25BEC333B90DCD1UL,
0x0E9F412FBA3813D1UL, 0x047E31E3098EB2B8UL, 0xBB686AC643F1741FUL,
0x0BE22E9C0EF0E8F2UL, 0x65AA9504E5F40D31UL, 0xE018DF5D64C62AC7UL,
0x17020E9A7EFA12EDUL, 0xFC12A7C16006DE82UL, 0x8DE4747E3745346DUL,
0x31D8C051A43CECAFUL, 0xBE9AFBEF127C1B12UL, 0xAEE94B4B808BBEE2UL,
0x3A0099CA32835B41UL, 0x59EB3173468D8C49UL, 0x6F89DB1E6DAAE9E1UL,
0x4C1ADAA837E968E4UL, 0x6E3593A56C682769UL, 0x022AD591689B5B82UL,
0x4AC33861ED978032UL, 0xF6F476E4E6A1318DUL, 0x2DA690A11AA05A23UL,
0x916FC56378C29D77UL, 0xAB3238BE22294659UL, 0x2D73A29019B28C77UL,
0xAAF26C12EC9C3C42UL, 0x058A278A24B334F9UL, 0x033BD18FB8D9BACDUL,
0x8B3833596008B07CUL, 0x280B6D093333E5E5UL, 0x2128DBE126CA3E1EUL,
0xCCF09769382472D8UL, 0x0CB6E495BD90CED6UL, 0x1303A37577C01C5AUL,
0xC8BBF4734FC34C53UL, 0x1B38B72B10F86CD5UL, 0x5098E2D6C1892E51UL,
0x2DD8065B79DB5380UL, 0x5B9A1A6D6A2292B7UL, 0xC70F751604D0497CUL,
0x911E08D7363B5213UL, 0x9F2E245273308D2EUL, 0x64D354827957F50EUL,
0x09856750F560342CUL, 0xDE091F26603F0E70UL, 0xDDE6B4E76173E3B1UL,
0xC1584AE1B26FA08EUL, 0x1EA29887837838D2UL, 0x6D7643FC67B15C54UL,
0x921E60571ED103EAUL, 0x63EB1EB33E7AFFF1UL, 0x80BA4D1F95BFD615UL,
0xEC8A1D4FC1A6B8E0UL, 0x2C46861B6DB17D1AUL, 0x01F05D06927E443BUL,
0x6172EC2EABEAD454UL, 0x21B8726C6F7C4102UL, 0x3C016CD9945C72ECUL,
0x708F77B2C0E8B665UL, 0xFC35BE2BB88974DAUL, 0x805897A33702BD61UL,
0x9A93367A6041226CUL, 0xFDAB188B6158F6BEUL, 0x5F21014A065E918CUL,
0xF4381DD77772D19CUL, 0xC664B6358AA85011UL, 0xF2639D7B3E2307E6UL,
0x3FA000D4A5A9C37AUL, 0x8F45D116ED8DC70FUL, 0x8CB8758E45C140D0UL,
0x49832B46D716236DUL, 0xCC8E4961A93065B8UL, 0x8A996533EDACEB0EUL,
0x15B35155EC56FAC1UL, 0xE7E0C6C05A9F1885UL, 0x05914F9A1D1C79F9UL,
0x730000A30B6725F0UL, 0xC95E671F8E543780UL, 0x47D68382400AF94EUL,
0x1A27F2734FE2249AUL, 0x828079C332D9C0ABUL, 0x2E9BC798EA09170EUL,
0x6B7CDAC829018C91UL, 0x7B89604901736993UL, 0xABE4EB26F47608F0UL,
0x70D5FDC88A0FF1B1UL, 0x5A1F0BAB9AB8A158UL, 0xDC89AE0A735C51A4UL,
0x36C1EA01E9C89B84UL, 0x3A9757AF204096DBUL, 0x1D56C8328540F963UL,
0x910A8694692472FAUL, 0x697192C9DF145604UL, 0xB20F7A4438712AA2UL,
0xE8C99185243F4896UL, 0xFBC8970EDBC39CA7UL, 0x33485403868C3761UL,
0xAFA97DDEDB1D6AD8UL, 0x54A1A6F24476A3BBUL, 0xFE4E078B184BDB7FUL,
0x5ED1543919754CD8UL, 0x86F8C775160FC08CUL, 0x9B4098F57019040DUL,
0x039518BBE841327BUL, 0x111D0D420A3F5F6AUL, 0x0666067346AF34ACUL,
0xD43F1D14EB239B9BUL, 0xA6BB91FEB5618F5BUL, 0xA2B5218B202409ADUL,
0xC004FA688C3AC25EUL, 0xF0E2D9EA2935E1DCUL, 0x380B31CFA2F2AF43UL,
0x50E050AE426250EAUL, 0x628ED94D1AA8F55BUL, 0xF8EB0654F0166311UL,
0x1F8858D26DDA5CC5UL, 0x931425D11CB1EFEBUL, 0xF661D461DC1A05D3UL,
0x7B75ED7EC6936DA8UL, 0x8713C59690985202UL, 0xF61D6F93F07C0E85UL,
0xFD1771F6711D6F4FUL, 0x5835A67E1B11419FUL, 0x33EF08ABD56A1050UL,
0x55B5D0043FA2C01CUL, 0x53316ED963B92D9DUL, 0x6A8C93744E521EDBUL,
0x083E948062EB9543UL, 0x1C15289B3189AFB1UL, 0xA6A0A5053AE2212DUL,
0x6573AF7F01FAFF3BUL, 0x58B6F034CFCFE843UL, 0xEB2837CA5AEA6AEDUL,
0x633E7897097AC328UL, 0x7FA91789B6CCEE82UL, 0xBEE2402F4E7D65EEUL,
0x616A103EC8FB0DBEUL, 0x65991F9FB25E13FCUL, 0x54EA8A3FADEC1F4BUL,
0x6D497C5ACDEA0E7AUL, 0x5865045E8CA18527UL, 0xA406C09215ABD61FUL,
0x68F81F5745FC9875UL, 0xE496D850CEFF3FA9UL, 0xD225C88D63212CB1UL,
0x37676390525116D2UL, 0x415614AB14188A7DUL, 0xABE58EBC1F6DDC63UL,
0xDE10312B2C25D28CUL, 0x86C86D7A0B847635UL, 0x408B511D584DC3DCUL,
0x6711FCC14B303FEDUL, 0x1284DF9CC6972023UL, 0xC3CE0B33141BFA8FUL,
0x0F3F58367D4A1819UL, 0x9313F83058FBE6D0UL, 0x6FCA5EF39B8E2F47UL,
0xA90F5C95D887756DUL, 0x96C4E2AD85D5AF6EUL, 0x0ED68A81F526F0A0UL,
0x53E4472DB4255A35UL, 0xAC581015134D58A6UL, 0x12C000D85C644FC7UL,
0x124D489B2C0FE6E4UL, 0x8FF83531C6F5D61AUL, 0x132BD6488304F73BUL,
0x110E99BC59604CB9UL, 0xC28186ACBC940C9BUL, 0x2094C07F48141230UL,
0x65FB9881A5053589UL, 0x940A3E6D72F09D69UL, 0x972A922CB14BA66EUL,
0x8D07E59C6DDD4327UL, 0xCB67F993F820157CUL, 0x65B7A54E5FB2ED6CUL,
0xC235828849576653UL, 0xA695F85479467538UL, 0x9E2BA885E63C4243UL,
0xDE64A6A5EF84C222UL, 0xC2AB9AF302080621UL, 0x88DBA09B87FA0734UL,
0xDF002765B44D02E1UL, 0xD50D8D90587CD820UL, 0x1B68B70ED179EFE1UL,
0xD6E77F8EC26AE95CUL, 0xEE57EB7C45051872UL, 0x4D2B445F36A7F9FDUL,
0x5502ABB8BB14D7F1UL, 0xAF2C0DF0406FA901UL, 0x6522833444BF4A83UL,
0xD7CB2E3FC691BE8DUL, 0x4F36F70D2E80D19AUL, 0xF6945FE911D4923BUL,
0xE3C6FE1EA47399C1UL, 0xF09EA1B2F837702CUL, 0x5122537CF97B5CB5UL,
0x0C8202B70E9BF154UL, 0x68B554AB58EB5E68UL, 0x7BF9B8052C9BEADEUL,
0x33612BFCD303810DUL, 0x03E38CF67B37DC53UL, 0x2BFDFF8691F37D5CUL,
0x4AB483D1CB1D07F6UL, 0xF071A58640639A5CUL, 0x9D6B98169B745CE1UL,
0x5F42D3E870FDCD93UL, 0x4EDF04404F258238UL, 0x2EAB6E10D65C9BB3UL,
0x5BB71411EF78DAD2UL, 0x0DE8128636A5D689UL, 0x18FDD1F484DC9365UL,
0x9896B8896941DA5BUL, 0x8BEF8E3BA4448E5FUL, 0x963A1E977CB1D2CAUL,
0x02BCF5F068D52851UL, 0x0CD783F09BFBE381UL, 0x350DA833D8C5DB47UL,
0x8D444C914D795C43UL, 0x8A00B4DFC44D9476UL, 0x4B36CBEC089E55FDUL,
0xD9D2FA1B0AC66211UL, 0x6C7FC30FA31A8B60UL, 0x9EF4504CC985AD6BUL,
0x8F2E7E5E0C00EE73UL, 0x819131CFEEBEA069UL, 0xB1E406A863E7A1B4UL,
0x501F072FF1F2AB67UL, 0xDE578BFC5ADBC264UL, 0xCDD66A09C8E13881UL,
0x4D443460CE52957FUL, 0x3B198C267976ECFAUL, 0x6B98323D8BD26522UL,
0x80161F6A489E4BF8UL, 0xE03A8AFCC7AE6872UL, 0x2484BD95A305AB27UL,
0x6ADDAA46BF25DD0EUL, 0xA429D8B00100477CUL, 0x55AEDB88A074BF2CUL,
0x63D9F9021AB8F5F3UL, 0x37858538A10C265CUL, 0xEF54C2CE9D063149UL,
0xFA5CE5AF33E2C136UL, 0xE601A559D0C391D7UL, 0x7C4ED29BBF57DC7EUL,
0x8FD0D4146DE9E900UL, 0xB58ABFA6CE6C0733UL, 0xF8D7F7743B33EAFFUL,
0x453FA782F454643CUL, 0xD01752C21AF21E66UL, 0xA50BB7913EAF05DFUL,
0x966D5B140B2F4189UL, 0x956F5638AFF3D148UL, 0x93FAA838420E8AB3UL,
0x715E26043071EABDUL, 0x01E7B458B5FD3A41UL, 0x5CFA99C4CC0492AAUL,
0x761FD391C3623044UL, 0xD39E44E9DB96B5BCUL, 0x8806C544F0534A07UL,
0x9B225CAFE97EAAC1UL, 0xEAE5E18583492767UL, 0x6B4E51E4C297F096UL,
0xFC512662EF47E41DUL, 0xB6AC60427DB46F8BUL, 0x8F137F3DB4429C9DUL,
0x04C65FBEAE9FD8D0UL, 0xEB72305958AE5022UL, 0xAA93AA14BCA2961EUL,
0x6C7547F9456CA37AUL, 0xEE6094871615BA34UL, 0x489BC8EDE0940402UL,
0x1108AEFAAD892229UL, 0x673B8B1CF6BED23EUL, 0xFDB781A75FD94DEAUL,
0x11D9E0F5D914A7BEUL, 0x02830D07F018143DUL, 0x9B3163B8188FD2BAUL,
0x32C1BEC97D06117EUL, 0x697268B761240CFFUL, 0xBD89CE3037C2E7A9UL,
0xF21C158125B19600UL, 0x632CB1931601B70AUL, 0x7BB3FB131338085CUL,
0xA9C06689B8138384UL, 0x161CCBF83EBDC2A1UL, 0x2CF83C01A80B7935UL,
0x9E51FE393B8E2FF0UL, 0xFE96E52B1606C1A7UL, 0x5E20DFB87F81ACCEUL,
0xF95DB9602CDAE467UL, 0xDEA155CD35555FEBUL, 0xF0669B810F70CDC6UL,
0xD36C2FBEB6A449ACUL, 0xCE500C6621C0A445UL, 0x41308909E366460AUL,
0xAC4D8178DA0CEC24UL, 0xC69049179ED09F7DUL, 0x36B608A0BA2FD848UL,
0xDF511894DD9568B4UL, 0xB3BFDF78EC861A6CUL, 0xCD50F39D19848153UL,
0xD2C1BC57E78A408CUL, 0x1E6613EFBB11B5EBUL, 0xF58E30D2D90F73D3UL,
0xCCB5E2F5E168D742UL, 0xEE97259469BDB672UL, 0x6784D35AF65935A8UL,
0x71032765ADED1FE8UL, 0x4BBF2FE54D9B72E3UL, 0x5A1BB7831E876A05UL,
0x12A8FC949EE91686UL, 0x8296F8FA83BD112CUL, 0xAAA7E3BFF64D34D5UL,
0x0301655E1794EE4BUL, 0x1E547C011BBF30E1UL, 0x39D74FEC536F31D6UL,
0x3C31A7478B1815BAUL, 0x525C774F82D5836EUL, 0xECF7186DC612FD8CUL,
0x96B7C4EDD1F3536FUL, 0x7E8C21F19C08541CUL, 0xEE92DB0CF91E4B09UL,
0xF666190D1591AE5DUL, 0x5E9B45102C895361UL, 0x9A95597AAE5C905DUL,
0x6E1272E5BB93F93FUL, 0x0E39E612402BFCF8UL, 0x576C9E8CA2A3B35EUL,
0x7E2E629996D0C35FUL, 0xC95DFF54E3524FCCUL, 0x260F9DEBDEB0E5CBUL,
0x577B6C6640BAF1ABUL, 0xCA76677779CA358EUL, 0x9E2714BEBCFDB144UL,
0xD660595CE30FD3EEUL, 0x72DE172D55A5706EUL, 0xB4C84D564489D420UL,
0x160AA2B9399D5A9DUL, 0x2906ECE619DAC4D2UL, 0x12CE8E8E68A4C317UL,
0x6BE2DFE89901CAA1UL, 0xEE1D68158102EB77UL, 0x64EB75E45BDA1AC5UL,
0xEFECF9F98720B55DUL, 0x41CDF813931315BFUL, 0x5F1E4F50CF98FFD4UL,
0xE69E09EED12E173BUL, 0x89A3707F0396FF65UL, 0x81E36B9DF4FFB492UL,
0x58C32E883D4DE6DDUL, 0x2D4725C2A5F0B469UL, 0x6B2B9C27CC421CACUL,
0x3C30F2AD966800C7UL, 0xFF74938BB76B8A7CUL, 0x52B5C99114FD93FAUL,
0x51647EDCA6C104DAUL, 0xEB47684CF796DF4EUL, 0x376D74A5AB14BD71UL,
0xF0871FEF8E9DAA3EUL, 0x1D65B134B2E045B6UL, 0x9DC8C0D8623BBA48UL,
0xAD6FC3C59DBDADF4UL, 0x66F6EBA55488B569UL, 0xB00D53E0E2D38F0AUL,
0x43A4212CEAD34593UL, 0x44724185FF7019FFUL, 0x50F46061432B3635UL,
0x880AA4C24E6B320BUL, 0xCAFCB3409A0DB43FUL, 0xA7F1A13DEF47514BUL,
0x3DC8A385A698220CUL, 0xFA17F82E30B85580UL, 0x430E7F0E88655F47UL,
0x45A1566013837B47UL, 0x84B2306D2292804EUL, 0xE7A3AF21D074E419UL,
0x09D08E2C5E569D4DUL, 0x84228F8908383FA2UL, 0xC34079610C8D3E82UL,
0x66C96426C54A5453UL, 0xD41F164117D32C93UL, 0x7829A66BF1FEC186UL,
0x4BB6846694BDFC18UL, 0x857D1C1C01352C01UL, 0xAB8E68BA85402A45UL,
0x74B3C4F101FE76C8UL, 0x6CF482CFAFB29FFEUL, 0x28B174A18F4DC3D1UL,
0x833C3425B2AA3755UL, 0x8AA58A32747F4432UL, 0xFE7B9FB4BCE3CD58UL,
0xB0836B2C16FA5553UL, 0x1D08EE6861BF3F23UL, 0x0FAE41E914562DF3UL,
0xB10A2E041937FC57UL, 0xDA60BB363415BF4CUL, 0xEEC67DBAB4CF4F0AUL,
0x9A6ED59FCC923B5CUL, 0x9A913C01A8EC7A83UL, 0xAD4779F2F9C7721FUL,
0x2BF0B7D105BE7459UL, 0x189EFA9AD5195EC6UL, 0xB5C9A2DD64B2A903UL,
0x5BCD642B2C2FD32CUL, 0xFED3FBF78CB0891FUL, 0x1ED958EE3C36DD3FUL,
0x030F5DE9CA65E97CUL, 0xBB5BCF8C931B85FEUL, 0xFD128759EA1D8061UL,
0x2C0238AC416BE6BCUL, 0xBB018584EEACFA27UL, 0xCEA7288C1964DE15UL,
0x7EA5C3840F29AA4DUL, 0x5DA841BA609E4A50UL, 0xE53AF84845985EB1UL,
0x93264DA9487183E4UL, 0xC3A4E367AF6D8D15UL, 0xDD4EB6450577BAF8UL,
0x2AA3093EE2C658ACUL, 0x3D036EC45055C580UL, 0xDDEDB34341C5B7DFUL,
0x524FFBDC4A1FAC90UL, 0x1B9D63DE13D82907UL, 0x69F9BAF0E868B640UL,
0xFC1A453A9253013CUL, 0x08B900DECAA77377UL, 0xFF24C72324153C59UL,
0x6182C1285C507A9BUL, 0x4E6680A54A03CCC8UL, 0x7165680200B67F1FUL,
0xC3290B26A07DCE5BUL, 0x2AD16584AA5BECE9UL, 0x5F10DF677C91B05EUL,
0x4BE1B0E2334B198AUL, 0xEA2466E4F4E4406DUL, 0x6ECAA92FF91E6F1DUL,
0x0267738EFA75CADDUL, 0x4282ED10A0EBFCF2UL, 0xD3F84CE8E1685271UL,
0xB667ED35716CA215UL, 0x97B4623D70DB7FA8UL, 0xB7BA3AA5E6C2E7CBUL,
0x8942B2F97118255BUL, 0x009050F842FB52ADUL, 0x114F5511999F5BD5UL,
0x70C1CAAF1E83F00AUL, 0xAC8EE25D462BB1AAUL, 0x63EEF42AD4E1BED9UL,
0x58DFBB3D22D3D1A5UL, 0x82B0027C0C63D816UL, 0x48D038F08F3D848BUL,
0xCE262D5F9A12610EUL, 0xA54BF51C21BD0167UL, 0xF3645F6FB948397DUL,
0x9188AE58532DA501UL, 0xEC90B0E1479DB767UL, 0x37F4886B83724F80UL,
0x232B8FF20ACD95AFUL, 0x88A228285D6BCDF0UL, 0x321FB91600259AEEUL,
0xA1F875F161D18E5EUL, 0x5B6087CDA21AEA0CUL, 0x0156923ED1A3D5F1UL,
0xC2892C8A6133B5D3UL, 0x015CA4DF0EA6354DUL, 0x5E25EB261B69A7D4UL,
0xAAA8CF0C012EFBA7UL, 0xCF3466248C37868BUL, 0x0D744514BD1D82C0UL,
0xB00FF1431EDDF490UL, 0xC79B86A0E3A8AB08UL, 0xFC361529BC9F1252UL,
0x869285653FB82865UL, 0x9F1C7A17546339ABUL, 0xE31AA66DBD5C4760UL,
0x51B9D2A765E0FC31UL, 0x31F39528C4CD13D8UL, 0x16C6C35B0D3A341DUL,
0x90296B1B0F28E2CDUL, 0x36338472A8DB5830UL, 0xA648E6D44DF14F87UL,
0x93E231E65EB1823FUL, 0x95AA7B9D08E2B627UL, 0x7932D149374700C7UL,
0x09EFE0A8BF245193UL, 0x742AA63BCEAFD6D8UL, 0x82D4BC5FEDF158B7UL,
0x02CDEA673CFF150DUL, 0xD8D7B5813B602D15UL, 0xA5A7B670EF15A5EDUL,
0x4C08E580A1D46AF2UL, 0xC3CA9B905D035647UL, 0x6A39ABB02F6F1B83UL,
0xD2EC2169F4D02436UL, 0x8E6AEA4DF8515AF2UL, 0x7B3DD4A8693CA2DAUL,
0xC2ABF17A50AEC383UL, 0xD4FB84F8B6D4F709UL, 0x2839A3EAA2E4C8A7UL,
0x5D5FD278FE10E1E9UL, 0x5610DDF74125D5A7UL, 0xA484B0B83461DCEAUL,
0xA511920C0A502369UL, 0xC53F30C6A5394CA4UL, 0x528799285D304DD4UL,
0xF6D7914CB252BB48UL, 0x892129CB52E65D15UL, 0x15A81B70519ACE6FUL,
0x5CFBFFD7A2A1C630UL, 0x3B900509C82DF46DUL, 0x19C3CE05D66D5FFCUL,
0x937D521A4A4799A0UL, 0xD0AE34A6EAD7207DUL, 0x3258A69F1D1A1B38UL,
0xB173E3255723CC02UL, 0xD7E48FEF7F414F1BUL, 0xDCEBA75F5C761ABEUL,
0x6DA10C618DEA0D17UL, 0x423FA8B05954FBD1UL, 0x7E73C2E7D923F3C9UL,
0xC22E21C927C684D1UL, 0x756BAA758764685FUL, 0x8C90B4C4E741D880UL,
0x1B658C9F4B41D846UL, 0x5D80C14094366707UL, 0xB55FED3E03C00F2DUL,
0x9B69EB7964C69C83UL, 0x356ED81C9494DADDUL, 0x7599AFF0B2A339D6UL,
0xA5EBFD25C9B5816BUL, 0xA481DC1C8995E1EFUL, 0xE42C63DF0D402397UL,
0x3B497B4C30873BAAUL, 0xA950B78BA8772C96UL, 0xD46308D4C76F115DUL,
0x73714A4ACA76A857UL, 0x0DA86B958FF8CB7DUL, 0xEB61F617B90E0A75UL,
0xD6106C9B39F51F55UL, 0xB179F73A6BD23B59UL, 0xE7F056E50104A460UL,
0xBC5B5387634A8642UL, 0xE1678D8752996AF4UL, 0xB508F3D394664A4BUL,
0xC88536DC4A219B0FUL, 0x39964CBB8CE367B1UL, 0xD51E211D5E9E1417UL,
0x6821B97B496870F2UL, 0xA596257350CA0A99UL, 0x6D051EE2C49D4D1DUL,
0xCB426AD61AA8D9B5UL, 0x5FFD3A4062B06D22UL, 0xDAD37BF2A4C594EBUL,
0x6B9CC848E2B0C686UL, 0x19B4232F3BC622AEUL, 0x70C13C7E5950B702UL,
0x383318CA622101ACUL, 0xD9647C028CD1C4DFUL, 0x006D123BC553B93CUL,
0x2CA9D7D896EAE722UL, 0xF19872AC8A0BD5A8UL, 0x59838578EB9E8E5CUL,
0xB948621EE99B27D4UL, 0x2B470E6036E0E387UL, 0xD0A7E8F0C8A32A84UL,
0xCBF869271A8E0914UL, 0x705F76A5EA4437CFUL, 0xBAD2BF4933215152UL,
0xE52EDE847038EA23UL, 0xB8A3EFD3D58D7607UL, 0x748472F5AD330239UL,
0xCC079CFD428690F6UL, 0x3687450CB7534DACUL, 0x0FEF82D5CC8ACE2AUL,
0x214653D5C552CA9AUL, 0x9FCA4E87BF6A04FDUL, 0x78D4B114D234A0D7UL,
0x22840422BD6A5BB5UL, 0x5B9ABE0DE1B4410FUL, 0xB3B50007963FDD6BUL,
0x53A8A46793B68E35UL, 0x8CDD8E8D188B6033UL, 0x5DD22B6E3ED49572UL,
0xE561F5D27F5302D6UL, 0xDF89CEC3322E56CDUL, 0x87167F503D600F90UL,
0x1698BB71C8201862UL, 0xF7BF5DFDB023108EUL, 0xA17FB15B66ACFB5FUL,
0x2DD771987768073BUL, 0x19299D2D86E0EB29UL, 0x8B537B7F206EED29UL,
0xE536DA153325ABFCUL, 0x30A69976796DB3B9UL, 0x8E65A2C94E2D4981UL,
0xC301D53553BD6514UL, 0x46DF3639B9E43790UL, 0x3004CD0E5AFD0463UL,
0x46E460B0F6ACA1A0UL, 0xCBA210E7372D9BD5UL, 0x45064274A74CA582UL,
0xFDD57EA43CE631AEUL, 0xF2BA08FFA4A683D0UL, 0x8DA658C4DAD42999UL,
0x7418042943E88040UL, 0x96000F72E9371FEFUL, 0xE9F1212DC8F47302UL,
0x2AFB565ECC3553EDUL, 0xCD3D55137EFF7FD6UL, 0xD36F11059388E442UL,
0xC4B47515DB5709DDUL, 0x5C363EFBF0BAAB67UL, 0x28C63B5A31650BBBUL,
0x6AE54E5068061C81UL, 0xDEE62000F4E0AA21UL, 0xE8238672FE088A8BUL,
0x9869CB6370F075B9UL, 0xBA376E2FC7DB330FUL, 0xB0F73E208487CDEEUL,
0x359D5017BE37FE97UL, 0x684D828C7F95E2DCUL, 0x9985ECA20E46AE1FUL,
0x8030A5137D1A21C4UL, 0xF78CDC00FC37AC39UL, 0x41CDDC8E61D9C644UL,
0xB6F3CD1D833BAD1DUL, 0x301D0D858A23DE22UL, 0xA51FCA12AD849BC8UL,
0x9F55E615986AB10EUL, 0x904AAA59854F2215UL, 0x12ECEA4AB40F51A7UL,
0xB4EDF5807735E23BUL, 0x6190200F1C589478UL, 0xA3CA57F321909A5AUL,
0x0BFAEE04B7325B63UL, 0x10C393E7FBCF826DUL, 0x4050A2CA53FDA708UL,
0xF31114A9B462B680UL, 0x6FB9A6F121BA2006UL, 0x04550CF09389D602UL,
0xB8C7D6D8CA8942F7UL, 0x71BB430C6436E9D1UL, 0xD9070DD5FAA0A10AUL,
0x8FD6827757D07E5BUL, 0xD04E6C313F8FD974UL, 0x2CFDEA1187909B9AUL,
0xC7A8E758C115F593UL, 0xA79A17663009ACC2UL, 0x8091A6B5372B141DUL,
0xEB33B08767F5BA73UL, 0xDAC1F6823B6111C7UL, 0x697DF90C3515611BUL,
0xCC1005F198761F48UL, 0x5067E4F5303B45A1UL, 0x04816D292A2D9AC2UL,
0x2949C7A0874DD5E9UL, 0x25DB2547804CEE5EUL, 0x7EDC3A8946D6F229UL,
0x00B586F67FD0C622UL, 0x3CAE5798E40324E0UL, 0x0A4F1437DE637164UL,
0x5F59B2B715871981UL, 0x5D68FF31051E48FBUL, 0x0F2C369D73A2AA46UL,
0xB009C6B53DD23399UL, 0xC366A81277084988UL, 0x5AF0E0CA0711E730UL,
0x7AD831A9E9E854BAUL, 0x1DD5EDB0CA4E85AEUL, 0x54651209D259E9DDUL,
0x3EBB1D9DAB237EADUL, 0xDA96989317AC464CUL, 0xBFCB0F8FBC52C74EUL,
0x9597ACB9E27B692EUL, 0x6F436B1643C95B23UL, 0xB81A1253E1C3CD9DUL,
0x7B35F37E905EC67EUL, 0x29CE62666EDA76DDUL, 0xFF2490DC1EC4014DUL,
0x2D4FF9124DD6B5C4UL, 0xB9510FEC23E0E9D1UL, 0x8BCDBC56541ED071UL,
0x5414E097C1B0CCB2UL, 0x82BEF8213076F5C7UL, 0xE9FC9A71BD512615UL,
0xCF15ECC39490DF5AUL, 0x49FA9328D8EE97DBUL, 0x5F80FF0153BC2145UL,
0xF63BA156B55BCB02UL, 0x0E3B9113109FDF36UL, 0x8FCD6528F54EDE69UL,
0x5D6AE9C000054763UL, 0x326D873633431FBBUL, 0x380E07FFCEF7A978UL,
0xDCAA09874A1DF230UL, 0x601494F49F6D261EUL, 0x856159486C9B60E3UL,
0x85C7F822D07089A5UL, 0xAFFB99CF5AB836C2UL, 0x241AD414FBBB956BUL,
0x0CFC042822831692UL, 0x382B16D049727FF2UL, 0x784F9997633C819AUL,
0x5C40ED725F6C390AUL, 0x2CE78B7A3331BA9CUL, 0x9C80636639963B41UL,
0x1B2D41C968355018UL, 0xD189B57691FB60E4UL, 0x3BD599A9DD85CE31UL,
0x46FC8E2EF0B9A77CUL, 0x1A389E07D0075EA4UL, 0x1622CA52401DF2ACUL,
0x528F3FF9B7993BFAUL, 0xF16C176CCA292DDBUL, 0x6C154010961EF542UL,
0x04B78E92BF6C82DFUL, 0x7D9AFEA6ABB46072UL, 0x3BC573291CBFFC2EUL,
0x277FFF096D567AF3UL, 0x1CBEB86841A6F757UL, 0xD0BCD49E76CA20A7UL,
0x25B6024756B1FE90UL, 0xE685C04EF84881FBUL, 0xDCAB14B352FC442EUL,
0x4FF80A521719953DUL, 0xD10425E411DBE94BUL, 0x60998D0507D6E38DUL,
0x146AA432C981BD5EUL, 0x1729A596282AAA41UL, 0x152BE1A263BAF963UL,
0x15278DF497D254CAUL, 0xE4B5E9891E88A5DAUL, 0x087FA3472067D0ACUL,
0xD99C2899A0AD9158UL, 0x5040F234DC531236UL, 0x9D7E1531259EEE90UL,
0x29AFB8B49391036EUL, 0x84B619599642D68EUL, 0xE838AAE0F249545CUL,
0x42D524BA8BB96959UL, 0x9A5B3E817A20EE59UL, 0x584F0530EC4C566BUL,
0xD6544FD14B47F945UL, 0x3613FB3B553A7CDEUL, 0x284E92B56831AA56UL,
0xCEE89BA10E951A22UL, 0x476806FA1A8A44E0UL, 0xC84CEF151885C1DFUL,
0x3DB1D5C1B0B73936UL, 0x45D2D90FDF452388UL, 0x038A7DD71BC5DD21UL,
0x2AC90C7422C56819UL, 0x4742046638ECE0FBUL, 0x553B44360FC8495DUL,
0xC8DBA1CF3F9A6E97UL, 0xF85919F494CAB021UL, 0x1479455C2FF236AFUL,
0x29BCAD159F7D018DUL, 0x016DFF51CBA3BCC5UL, 0x234BF8A77F6B1CF5UL,
0x20564C6F44F9E641UL, 0x063A550C5AA50FA8UL, 0xB063D0AAAA96DFECUL,
0x3EC659DF42C092F8UL, 0x29D4A76A5A5F7E09UL, 0x65EFF3EE6E691D1EUL,
0xBD1634F5721CF799UL, 0xE85BD016723B43FFUL, 0x5233E9E7AEA11022UL,
0x8C68852EA9039B4CUL, 0x2C978ADBE885BC15UL, 0x726615ED9D497550UL,
0x7C1E145EB8D2BD96UL, 0xC2FEFB25935A5D71UL, 0x9EE9C3E1C3DE416FUL,
0xFFD568A03E20E0B3UL, 0xF53649AD90156F2AUL, 0x0331B91DCE54E7EDUL,
0x67CED5A86E99392FUL, 0x16FC0A5815500B05UL, 0x030392E8D24A7C00UL,
0x232E5E31DF32A7B5UL, 0xCC8BF22B1947DF21UL, 0x4EC2C72D9C1EEABDUL,
0x0B1B79F45220E668UL, 0xCC3CF0EE9C4A899BUL, 0xFC260A60592EBC80UL,
0xC1989A0382CB03EDUL, 0x35FE679A6CD800B2UL, 0x8A6B1ADE4FBB162FUL,
0xB0FD284563625295UL, 0xCDCC1C7B2181D024UL, 0x5B8BA0C895C0BB23UL,
0xA681FEA9ADCD43DBUL, 0x0FE30FB6876DE718UL, 0x6DDD1E27B769C494UL,
0x83A1E58460FFE8BBUL, 0x8FAD6FD2DC90FF65UL, 0x41BB28B81201CB24UL,
0xA148CE79B2597204UL, 0x7CB87DF97BB477A6UL, 0x9F79E6DED87DC688UL,
0xE044D84A6C758171UL, 0x1A29E750D9EC4097UL, 0x8445FC2B80C4A0F5UL,
0x5EFD9784AFED4ED2UL, 0x344C252BD90EB0E4UL, 0xEAD18D2E4418E5B5UL,
0x207EF4FFC260BD24UL, 0xD2E5C3AE534EC538UL, 0x2F5A59BF3D10E7E1UL,
0x9528E29266C2924CUL, 0x0121B6BDAB45D138UL, 0xADD0256ACBC771DDUL,
0x7301769600C6C50DUL, 0x3E7404EA8231D497UL, 0xB39B3840B8D03117UL,
0x56EFCEDDEF5B6634UL, 0xE6BE2C0D73B72098UL, 0x5A2841A21A5E4959UL,
0xCFEB3586156DF6E0UL, 0xD84F58901E2D65B8UL, 0x79796786CCC59703UL,
0x13BFA9A94DD07696UL, 0x7B63116A6B5458B6UL, 0x1406628176C932E0UL,
0xDD7ACC4E97F91B1AUL, 0xC82B8F84A56BDBE8UL, 0x325D87D08ED8B0B0UL,
0x3F7847B1E82002DDUL, 0x4662900D2ADAF6BFUL, 0x12AE9F58561DB1D7UL,
0xA896E956A95CC074UL, 0xAA4FA3A2F8BA4084UL, 0x1D577E35F5DCA67FUL,
0x796FF2D75469DEC2UL, 0xBD3F3F87E4DE894EUL, 0x3666B2262DEBFB6BUL,
0x1E26D7AEEF976C2EUL, 0x6BC3854F867AC4A0UL, 0x743DBF8C2E95A821UL,
0xA62A76B9AE2E645AUL, 0xB4D76561F40187C1UL, 0xD3E5F23F9FA5DB25UL,
0x34B1F6B39E6A87E2UL, 0x7DA5C3DFF7BE72CFUL, 0xFDF46B1BE80AD4F9UL,
0x0B21121CA9653B8AUL, 0x1199CA9D0A90F21AUL, 0x6021EA302D01E0BAUL,
0x8101D063C05CF5D4UL, 0xE2652410DFE78F23UL, 0x84095ACF47C21A25UL,
0xD7E29A4DB2FD3A99UL, 0x7793C0CB57959F93UL, 0x94C605308B9E5AA7UL,
0x943DB1AC54165B8FUL, 0xC1391A544C07447CUL, 0x3FEF1A61F785D97BUL,
0x6DFCC3152478BDE4UL, 0x312AFB0E1982933AUL, 0xB8069C2605631ED3UL,
0x5A6076423430BED2UL, 0x34E379F09E2D4F42UL, 0x9167F5E4019573E3UL,
0x18F81157828D2A49UL, 0xF4A8723B4955EAB8UL, 0x0BE6C0ABFEA9E8A6UL,
0xC63ADCF2CEF25556UL, 0xC5EBD3BEAE9F364FUL, 0xA301D60CF5B6F2FCUL,
0x8C606CA881D27A00UL, 0x826FEE13B554C18AUL, 0x8DF251716F10B776UL,
0xB2573A33AC7D94FFUL, 0xC0E771248CB7ABB9UL, 0x753DD605DB38F4EAUL,
0x21901664C3D92114UL, 0xA408FCB7A1892612UL, 0x3084FC64A03D6722UL,
0xC8C9D9569AD42A34UL, 0x1FBFBAFC1694B383UL, 0x1894280CC3F94ABEUL,
0xE14C38A7BBB54651UL, 0x23A48CC84A6EB704UL, 0xD034ADC45AABEDBDUL,
0xC93F2C21C973C766UL, 0x66A8AEC11D743CC6UL, 0xB4F72AA52E37C145UL,
0xB02834DF0D9266B4UL, 0xDB8E724EA1FF402FUL, 0x531E9C058112E352UL,
0xC2F692531DB317D2UL, 0xEFC9586498D263A7UL, 0x84F2C524D2F3ADB9UL,
0xAFAF02C27CF25D08UL, 0x385873595F9CFC09UL, 0x36DDA10D1A152B7AUL,
0x9F9B997A0DACFB55UL, 0x10AB5EB5C4714882UL, 0x7BA4E8703E22B7EEUL,
0x0A2BFD558607BCC8UL, 0x201D3706F74F8BA1UL, 0x3DBD573B1358F02EUL,
0x5B37645FA93BCEBCUL, 0xC0166864BC1A7544UL, 0x45C7AA5559FC65D7UL,
0xEFEA04AA83349B78UL, 0x607859194F9E9FD8UL, 0xA6B9AE5B53CF7710UL,
0x73B9142ACBC50821UL, 0x8B7D67495887E65CUL, 0x39B6C4FB2B232E56UL,
0xD212DB10E31D2A68UL, 0x629AC0A3D263DC6EUL, 0x6BC2E7FF912050BAUL,
0xE0AD5A8FDB183F62UL, 0xF05648134F0C6F0FUL, 0x31E146F4AF980FDAUL,
0x7FAF0078D84D62CCUL, 0xE13F044C2830D21EUL, 0x49A047AD204B4C4BUL,
0xF3AFBE2237351A74UL, 0x32826C9217BB07EDUL, 0xD4C3AEB099319B5CUL,
0x49CE5BD05B2B0F61UL, 0x75DD36984DCBD0A2UL, 0x84EC5D7C2F0AAC6CUL,
0x8E59CC9B9942EDDFUL, 0x89FF85DCDF9AE895UL, 0x6F9EE0D8D9E8D414UL,
0x10E01A59058D3904UL, 0x1DFAF567BFF55D2EUL, 0x8DD6A18C03382CD4UL,
0xE12FD89A0CF58553UL, 0xE245DA902C0C4F5CUL, 0x8BE7566B9987520DUL,
0x4CA1C0A4B38A3098UL, 0x81E45015BE618A72UL, 0xA80E0344FF27EFDFUL,
0xC98DAEC6DC5005BAUL, 0xF56873F3A958AE5EUL, 0xDB88604670C794ACUL,
0x4F68E448DDF6535FUL, 0x3443DBF1CA6031A8UL, 0x73DFA5DEEF409A41UL,
0xA7C556941F6643B2UL, 0x424BC40D8C83D962UL, 0x6F292A325B99B726UL,
0x6EECB1009717D65EUL, 0x899BE4CE7BB2D8EEUL, 0x25285FED3E59781DUL,
0x14C5AEDD76E092D3UL, 0x9BB5EE10567640AEUL, 0xCD62A1D43558FD06UL,
0x70A7B09FC5F39447UL, 0xF10064AE92EFFB99UL, 0xD55FA1A918A23082UL,
0xD03F28AD25C73A78UL, 0x76CFFFEE094D8B0EUL, 0x4FD5A46AD5A4B4CFUL,
0x8F3A36F9D7BF87E3UL, 0x64224315210625BEUL, 0x749A131B71B64350UL,
0x9034FF9DAC089F48UL, 0xB58D3017E7321217UL, 0x549D818937D5CE90UL,
0x903CE1452419E99CUL, 0xFD052F0388DB2E76UL, 0x7390051E3972480EUL,
0x5E5F6EC3F27B3679UL, 0x3E3637D4D4EE917DUL, 0x4FE04068CA2A4309UL,
0x98C9C17454AAE42DUL, 0x659AE0BDB113BC21UL, 0x4C0BDECB1511AF4CUL,
0x17048BFAEAC0006DUL, 0x68F106AADAA64912UL, 0x2286234ECEB7EAF0UL,
0x350CD42CAF697E51UL, 0x8DCDE6D1FAC19A9FUL, 0xF97E55A245A8A8A2UL,
0xAAE86B2092DA90A3UL, 0x5123E878AA8AEF76UL, 0x022B88B9694A55F6UL,
0xC4C1A9B1C0221985UL, 0x20056D91DD5E0FFEUL, 0xF5BF61EC225C9843UL,
0x1A315A05BDCF4A31UL, 0x5710A21A8DF4F15FUL, 0x99BD1A0AF97AD027UL,
0x7602C5997AD4E12CUL
};
public static bool IsPopularPassword(char[] vPassword)
{
Debug.Assert(PpcTable.Length == (PpcTableSize / 64));
if(vPassword == null) throw new ArgumentNullException("vPassword");
if(vPassword.Length == 0) return false;
foreach(char ch in vPassword)
{
if(!IsPopularChar(ch)) return false;
}
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vPassword);
int[] vIndices = GetTableIndices(pbUtf8, PpcTableSize);
Array.Clear(pbUtf8, 0, pbUtf8.Length);
foreach(int iIndex in vIndices)
{
if(!GetTableBit(PpcTable, iIndex)) return false;
}
return true;
}
private static bool IsPopularChar(char ch)
{
return (((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z')) ||
((ch >= '0') && (ch <= '9')) || (ch == '_') || (ch == '!'));
}
private static int[] GetTableIndices(byte[] pbPasswordUtf8, int nTableSize)
{
Debug.Assert((nTableSize >= 2) && (nTableSize <= 0x10000));
Debug.Assert((nTableSize % 64) == 0);
SHA512Managed sha = new SHA512Managed();
byte[] pbHash = sha.ComputeHash(pbPasswordUtf8);
int[] vIndices = new int[pbHash.Length / 2];
for(int i = 0; i < vIndices.Length; ++i)
vIndices[i] = ((((int)pbHash[i * 2] << 8) |
(int)pbHash[i * 2 + 1]) % nTableSize);
return vIndices;
}
private static bool GetTableBit(ulong[] vTable, int iBit)
{
return ((vTable[iBit >> 6] & (1UL << (iBit & 0x3F))) != 0UL);
}
#if (DEBUG && !KeePassLibSD)
private static bool SetTableBit(ulong[] vTable, int iBit)
{
if(GetTableBit(vTable, iBit)) return false;
vTable[iBit >> 6] = (vTable[iBit >> 6] | (1UL << (iBit & 0x3F)));
return true;
}
public static void MakeList()
{
string strData = File.ReadAllText("MostPopularPasswords.txt", StrUtil.Utf8);
strData += " ";
CharStream cs = new CharStream(strData);
List<string> vPasswords = new List<string>();
StringBuilder sbPassword = new StringBuilder();
while(true)
{
char ch = cs.ReadChar();
if(ch == char.MinValue) break;
if(char.IsWhiteSpace(ch))
{
string strPassword = sbPassword.ToString();
strPassword = strPassword.ToLower();
if(strPassword.Length > 3)
{
if(vPasswords.IndexOf(strPassword) < 0)
vPasswords.Add(strPassword);
}
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);
}
}
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

@ -0,0 +1,145 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Cryptography
{
/// <summary>
/// A class that offers static functions to estimate the quality of
/// passwords.
/// </summary>
public static class QualityEstimation
{
private enum CharSpaceBits : uint
{
Control = 32,
Alpha = 26,
Number = 10,
Special = 33,
High = 112
}
/// <summary>
/// Estimate the quality of a password.
/// </summary>
/// <param name="vPasswordChars">Password to check.</param>
/// <returns>Estimated bit-strength of the password.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public static uint EstimatePasswordBits(char[] vPasswordChars)
{
Debug.Assert(vPasswordChars != null);
if(vPasswordChars == null) throw new ArgumentNullException("vPasswordChars");
bool bChLower = false, bChUpper = false, bChNumber = false;
bool bChSpecial = false, bChHigh = false, bChControl = false;
Dictionary<char, uint> vCharCounts = new Dictionary<char, uint>();
Dictionary<int, uint> vDifferences = new Dictionary<int, uint>();
double dblEffectiveLength = 0.0;
for(int i = 0; i < vPasswordChars.Length; ++i) // Get character types
{
char tch = vPasswordChars[i];
if(tch < ' ') bChControl = true;
else if((tch >= 'A') && (tch <= 'Z')) bChUpper = true;
else if((tch >= 'a') && (tch <= 'z')) bChLower = true;
else if((tch >= '0') && (tch <= '9')) bChNumber = true;
else if((tch >= ' ') && (tch <= '/')) bChSpecial = true;
else if((tch >= ':') && (tch <= '@')) bChSpecial = true;
else if((tch >= '[') && (tch <= '`')) bChSpecial = true;
else if((tch >= '{') && (tch <= '~')) bChSpecial = true;
else if(tch > '~') bChHigh = true;
double dblDiffFactor = 1.0;
if(i >= 1)
{
int iDiff = (int)tch - (int)vPasswordChars[i - 1];
uint uDiffCount;
if(vDifferences.TryGetValue(iDiff, out uDiffCount))
{
++uDiffCount;
vDifferences[iDiff] = uDiffCount;
dblDiffFactor /= (double)uDiffCount;
}
else vDifferences.Add(iDiff, 1);
}
uint uCharCount;
if(vCharCounts.TryGetValue(tch, out uCharCount))
{
++uCharCount;
vCharCounts[tch] = uCharCount;
dblEffectiveLength += dblDiffFactor * (1.0 / (double)uCharCount);
}
else
{
vCharCounts.Add(tch, 1);
dblEffectiveLength += dblDiffFactor;
}
}
uint uCharSpace = 0;
if(bChControl) uCharSpace += (uint)CharSpaceBits.Control;
if(bChUpper) uCharSpace += (uint)CharSpaceBits.Alpha;
if(bChLower) uCharSpace += (uint)CharSpaceBits.Alpha;
if(bChNumber) uCharSpace += (uint)CharSpaceBits.Number;
if(bChSpecial) uCharSpace += (uint)CharSpaceBits.Special;
if(bChHigh) uCharSpace += (uint)CharSpaceBits.High;
if(uCharSpace == 0) return 0;
double dblBitsPerChar = Math.Log((double)uCharSpace) / Math.Log(2.0);
double dblRating = dblBitsPerChar * dblEffectiveLength;
#if !KeePassLibSD
char[] vLowerCopy = new char[vPasswordChars.Length];
for(int ilc = 0; ilc < vLowerCopy.Length; ++ilc)
vLowerCopy[ilc] = char.ToLower(vPasswordChars[ilc]);
if(PopularPasswords.IsPopularPassword(vLowerCopy)) dblRating /= 8.0;
Array.Clear(vLowerCopy, 0, vLowerCopy.Length);
#endif
return (uint)Math.Ceiling(dblRating);
}
/// <summary>
/// Estimate the quality of a password.
/// </summary>
/// <param name="pbUnprotectedUtf8">Password to check, UTF-8 encoded.</param>
/// <returns>Estimated bit-strength of the password.</returns>
public static uint EstimatePasswordBits(byte[] pbUnprotectedUtf8)
{
if(pbUnprotectedUtf8 == null) { Debug.Assert(false); return 0; }
char[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8);
uint uResult = EstimatePasswordBits(vChars);
Array.Clear(vChars, 0, vChars.Length);
return uResult;
}
}
}

View File

@ -0,0 +1,402 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Security;
using System.Security.Cryptography;
using System.Text;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Keys;
using KeePassLib.Native;
using KeePassLib.Utility;
using KeePassLib.Resources;
using KeePassLib.Security;
namespace KeePassLib.Cryptography
{
/* #pragma warning disable 1591
/// <summary>
/// Return values of the <c>SelfTest.Perform</c> method.
/// </summary>
public enum SelfTestResult
{
Success = 0,
RijndaelEcbError = 1,
Salsa20Error = 2,
NativeKeyTransformationError = 3
}
#pragma warning restore 1591 */
/// <summary>
/// Class containing self-test methods.
/// </summary>
public static class SelfTest
{
/// <summary>
/// Perform a self-test.
/// </summary>
public static void Perform()
{
TestFipsComplianceProblems(); // Must be the first test
TestRijndael();
TestSalsa20();
TestNativeKeyTransform();
TestHmacOtp();
TestProtectedObjects();
TestMemUtil();
TestStrUtil();
TestUrlUtil();
Debug.Assert((int)PwIcon.World == 1);
Debug.Assert((int)PwIcon.Warning == 2);
Debug.Assert((int)PwIcon.BlackBerry == 68);
}
internal static void TestFipsComplianceProblems()
{
try { new RijndaelManaged(); }
catch(Exception exAes)
{
throw new SecurityException("AES/Rijndael: " + exAes.Message);
}
try { new SHA256Managed(); }
catch(Exception exSha256)
{
throw new SecurityException("SHA-256: " + exSha256.Message);
}
}
private static void TestRijndael()
{
// Test vector (official ECB test vector #356)
byte[] pbIV = new byte[16];
byte[] pbTestKey = new byte[32];
byte[] pbTestData = new byte[16];
byte[] pbReferenceCT = new byte[16] {
0x75, 0xD1, 0x1B, 0x0E, 0x3A, 0x68, 0xC4, 0x22,
0x3D, 0x88, 0xDB, 0xF0, 0x17, 0x97, 0x7D, 0xD7 };
int i;
for(i = 0; i < 16; ++i) pbIV[i] = 0;
for(i = 0; i < 32; ++i) pbTestKey[i] = 0;
for(i = 0; i < 16; ++i) pbTestData[i] = 0;
pbTestData[0] = 0x04;
RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size
{
Debug.Assert(false);
r.BlockSize = 128;
}
r.IV = pbIV;
r.KeySize = 256;
r.Key = pbTestKey;
r.Mode = CipherMode.ECB;
ICryptoTransform iCrypt = r.CreateEncryptor();
iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0);
if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
throw new SecurityException(KLRes.EncAlgorithmAes + ".");
}
private static void TestSalsa20()
{
// Test values from official set 6, vector 3
byte[] pbKey= new byte[32] {
0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC,
0x3F, 0x92, 0xE5, 0x38, 0x8B, 0xDE, 0x31, 0x84,
0xD7, 0x2A, 0x7D, 0xD0, 0x23, 0x76, 0xC9, 0x1C
};
byte[] pbIV = new byte[8] { 0x28, 0x8F, 0xF6, 0x5D,
0xC4, 0x2B, 0x92, 0xF9 };
byte[] pbExpected = new byte[16] {
0x5E, 0x5E, 0x71, 0xF9, 0x01, 0x99, 0x34, 0x03,
0x04, 0xAB, 0xB2, 0x2A, 0x37, 0xB6, 0x62, 0x5B
};
byte[] pb = new byte[16];
Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV);
c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected))
throw new SecurityException("Salsa20.");
#if DEBUG
// Extended test in debug mode
byte[] pbExpected2 = new byte[16] {
0xAB, 0xF3, 0x9A, 0x21, 0x0E, 0xEE, 0x89, 0x59,
0x8B, 0x71, 0x33, 0x37, 0x70, 0x56, 0xC2, 0xFE
};
byte[] pbExpected3 = new byte[16] {
0x1B, 0xA8, 0x9D, 0xBD, 0x3F, 0x98, 0x83, 0x97,
0x28, 0xF5, 0x67, 0x91, 0xD5, 0xB7, 0xCE, 0x23
};
Random r = new Random();
int nPos = Salsa20ToPos(c, r, pb.Length, 65536);
c.Encrypt(pb, pb.Length, false);
if(!MemUtil.ArraysEqual(pb, pbExpected2))
throw new SecurityException("Salsa20-2.");
nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008);
Array.Clear(pb, 0, pb.Length);
c.Encrypt(pb, pb.Length, true);
if(!MemUtil.ArraysEqual(pb, pbExpected3))
throw new SecurityException("Salsa20-3.");
#endif
}
#if DEBUG
private static int Salsa20ToPos(Salsa20Cipher c, Random r, int nPos,
int nTargetPos)
{
byte[] pb = new byte[512];
while(nPos < nTargetPos)
{
int x = r.Next(1, 513);
int nGen = Math.Min(nTargetPos - nPos, x);
c.Encrypt(pb, nGen, r.Next(0, 2) == 0);
nPos += nGen;
}
return nTargetPos;
}
#endif
private static void TestNativeKeyTransform()
{
#if DEBUG
byte[] pbOrgKey = CryptoRandom.Instance.GetRandomBytes(32);
byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32);
ulong uRounds = (ulong)((new Random()).Next(1, 0x3FFF));
byte[] pbManaged = new byte[32];
Array.Copy(pbOrgKey, pbManaged, 32);
if(CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds) == false)
throw new SecurityException("Managed transform.");
byte[] pbNative = new byte[32];
Array.Copy(pbOrgKey, pbNative, 32);
if(NativeLib.TransformKey256(pbNative, pbSeed, uRounds) == false)
return; // Native library not available ("success")
if(!MemUtil.ArraysEqual(pbManaged, pbNative))
throw new SecurityException("Native transform.");
#endif
}
private static void TestMemUtil()
{
#if DEBUG
Random r = new Random();
byte[] pb = CryptoRandom.Instance.GetRandomBytes((uint)r.Next(
0, 0x2FFFF));
byte[] pbCompressed = MemUtil.Compress(pb);
if(!MemUtil.ArraysEqual(MemUtil.Decompress(pbCompressed), pb))
throw new InvalidOperationException("GZip");
pb = Encoding.ASCII.GetBytes("012345678901234567890a");
byte[] pbN = Encoding.ASCII.GetBytes("9012");
if(MemUtil.IndexOf<byte>(pb, pbN) != 9)
throw new InvalidOperationException("MemUtil-1");
pbN = Encoding.ASCII.GetBytes("01234567890123");
if(MemUtil.IndexOf<byte>(pb, pbN) != 0)
throw new InvalidOperationException("MemUtil-2");
pbN = Encoding.ASCII.GetBytes("a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 21)
throw new InvalidOperationException("MemUtil-3");
pbN = Encoding.ASCII.GetBytes("0a");
if(MemUtil.IndexOf<byte>(pb, pbN) != 20)
throw new InvalidOperationException("MemUtil-4");
pbN = Encoding.ASCII.GetBytes("1");
if(MemUtil.IndexOf<byte>(pb, pbN) != 1)
throw new InvalidOperationException("MemUtil-5");
pbN = Encoding.ASCII.GetBytes("b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-6");
pbN = Encoding.ASCII.GetBytes("012b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-7");
#endif
}
private static void TestHmacOtp()
{
#if (DEBUG && !KeePassLibSD)
byte[] pbSecret = Encoding.ASCII.GetBytes("12345678901234567890");
string[] vExp = new string[]{ "755224", "287082", "359152",
"969429", "338314", "254676", "287922", "162583", "399871",
"520489" };
for(int i = 0; i < vExp.Length; ++i)
{
if(HmacOtp.Generate(pbSecret, (ulong)i, 6, false, -1) != vExp[i])
throw new InvalidOperationException("HmacOtp");
}
#endif
}
private static void TestProtectedObjects()
{
#if DEBUG
byte[] pbData = Encoding.ASCII.GetBytes("Test Test Test Test");
ProtectedBinary pb = new ProtectedBinary(true, pbData);
if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-1");
byte[] pbDec = pb.ReadData();
if(!MemUtil.ArraysEqual(pbData, pbDec))
throw new SecurityException("ProtectedBinary-2");
if(!pb.IsProtected) throw new SecurityException("ProtectedBinary-3");
byte[] pbData2 = Encoding.ASCII.GetBytes("Test Test Test Test");
byte[] pbData3 = Encoding.ASCII.GetBytes("Test Test Test Test Test");
ProtectedBinary pb2 = new ProtectedBinary(true, pbData2);
ProtectedBinary pb3 = new ProtectedBinary(true, pbData3);
if(!pb.Equals(pb2)) throw new SecurityException("ProtectedBinary-4");
if(pb.Equals(pb3)) throw new SecurityException("ProtectedBinary-5");
if(pb2.Equals(pb3)) throw new SecurityException("ProtectedBinary-6");
if(pb.GetHashCode() != pb2.GetHashCode())
throw new SecurityException("ProtectedBinary-7");
if(!((object)pb).Equals((object)pb2))
throw new SecurityException("ProtectedBinary-8");
if(((object)pb).Equals((object)pb3))
throw new SecurityException("ProtectedBinary-9");
if(((object)pb2).Equals((object)pb3))
throw new SecurityException("ProtectedBinary-10");
ProtectedString ps = new ProtectedString();
if(ps.Length != 0) throw new SecurityException("ProtectedString-1");
if(!ps.IsEmpty) throw new SecurityException("ProtectedString-2");
if(ps.ReadString().Length != 0)
throw new SecurityException("ProtectedString-3");
ps = new ProtectedString(true, "Test");
ProtectedString ps2 = new ProtectedString(true,
StrUtil.Utf8.GetBytes("Test"));
if(ps.IsEmpty) throw new SecurityException("ProtectedString-4");
pbData = ps.ReadUtf8();
pbData2 = ps2.ReadUtf8();
if(!MemUtil.ArraysEqual(pbData, pbData2))
throw new SecurityException("ProtectedString-5");
if(pbData.Length != 4)
throw new SecurityException("ProtectedString-6");
if(ps.ReadString() != ps2.ReadString())
throw new SecurityException("ProtectedString-7");
pbData = ps.ReadUtf8();
pbData2 = ps2.ReadUtf8();
if(!MemUtil.ArraysEqual(pbData, pbData2))
throw new SecurityException("ProtectedString-8");
if(!ps.IsProtected) throw new SecurityException("ProtectedString-9");
if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10");
#endif
}
private static void TestStrUtil()
{
#if DEBUG
string[] vSeps = new string[]{ "ax", "b", "c" };
const string str1 = "axbqrstcdeax";
List<string> v1 = StrUtil.SplitWithSep(str1, vSeps, true);
if(v1.Count != 9) throw new InvalidOperationException("StrUtil-1");
if(v1[0].Length > 0) throw new InvalidOperationException("StrUtil-2");
if(!v1[1].Equals("ax")) throw new InvalidOperationException("StrUtil-3");
if(v1[2].Length > 0) throw new InvalidOperationException("StrUtil-4");
if(!v1[3].Equals("b")) throw new InvalidOperationException("StrUtil-5");
if(!v1[4].Equals("qrst")) throw new InvalidOperationException("StrUtil-6");
if(!v1[5].Equals("c")) throw new InvalidOperationException("StrUtil-7");
if(!v1[6].Equals("de")) throw new InvalidOperationException("StrUtil-8");
if(!v1[7].Equals("ax")) throw new InvalidOperationException("StrUtil-9");
if(v1[8].Length > 0) throw new InvalidOperationException("StrUtil-10");
const string str2 = "12ab56";
List<string> v2 = StrUtil.SplitWithSep(str2, new string[]{ "AB" }, false);
if(v2.Count != 3) throw new InvalidOperationException("StrUtil-11");
if(!v2[0].Equals("12")) throw new InvalidOperationException("StrUtil-12");
if(!v2[1].Equals("AB")) throw new InvalidOperationException("StrUtil-13");
if(!v2[2].Equals("56")) throw new InvalidOperationException("StrUtil-14");
List<string> v3 = StrUtil.SplitWithSep("pqrs", vSeps, false);
if(v3.Count != 1) throw new InvalidOperationException("StrUtil-15");
if(!v3[0].Equals("pqrs")) throw new InvalidOperationException("StrUtil-16");
if(StrUtil.VersionToString(0x000F000E000D000CUL) != "15.14.13.12")
throw new InvalidOperationException("StrUtil-V1");
if(StrUtil.VersionToString(0x00FF000E00010000UL) != "255.14.1")
throw new InvalidOperationException("StrUtil-V2");
if(StrUtil.VersionToString(0x000F00FF00000000UL) != "15.255")
throw new InvalidOperationException("StrUtil-V3");
if(StrUtil.VersionToString(0x00FF000000000000UL) != "255")
throw new InvalidOperationException("StrUtil-V4");
if(StrUtil.VersionToString(0x00FF000000000000UL, true) != "255.0")
throw new InvalidOperationException("StrUtil-V5");
if(StrUtil.VersionToString(0x0000000000070000UL, true) != "0.0.7")
throw new InvalidOperationException("StrUtil-V6");
#endif
}
private static void TestUrlUtil()
{
#if DEBUG
if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") !=
"domain")
throw new InvalidOperationException("UrlUtil-H1");
if(UrlUtil.GetHost(@"http://example.org:80") != "example.org")
throw new InvalidOperationException("UrlUtil-H2");
if(UrlUtil.GetHost(@"mailto:bob@example.com") != "example.com")
throw new InvalidOperationException("UrlUtil-H3");
if(UrlUtil.GetHost(@"ftp://asmith@ftp.example.org") != "ftp.example.org")
throw new InvalidOperationException("UrlUtil-H4");
if(UrlUtil.GetHost(@"scheme://username:password@domain:port/path?query_string#fragment_id") !=
"domain")
throw new InvalidOperationException("UrlUtil-H5");
if(UrlUtil.GetHost(@"bob@example.com") != "example.com")
throw new InvalidOperationException("UrlUtil-H6");
if(UrlUtil.GetHost(@"s://u:p@d.tld:p/p?q#f") != "d.tld")
throw new InvalidOperationException("UrlUtil-H7");
if(NativeLib.IsUnix()) return;
string strBase = "\\\\HOMESERVER\\Apps\\KeePass\\KeePass.exe";
string strDoc = "\\\\HOMESERVER\\Documents\\KeePass\\NewDatabase.kdbx";
string strRel = "..\\..\\Documents\\KeePass\\NewDatabase.kdbx";
string str = UrlUtil.MakeRelativePath(strBase, strDoc);
if(!str.Equals(strRel)) throw new InvalidOperationException("UrlUtil-R1");
str = UrlUtil.MakeAbsolutePath(strBase, strRel);
if(!str.Equals(strDoc)) throw new InvalidOperationException("UrlUtil-R2");
#endif
}
}
}

View File

@ -0,0 +1,49 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Delegates
{
/// <summary>
/// Function definition of a method that performs an action on a group.
/// When traversing the internal tree, this function will be invoked
/// for all visited groups.
/// </summary>
/// <param name="pg">Currently visited group.</param>
/// <returns>You must return <c>true</c> if you want to continue the
/// traversal. If you want to immediately stop the whole traversal,
/// return <c>false</c>.</returns>
public delegate bool GroupHandler(PwGroup pg);
/// <summary>
/// Function definition of a method that performs an action on an entry.
/// When traversing the internal tree, this function will be invoked
/// for all visited entries.
/// </summary>
/// <param name="pe">Currently visited entry.</param>
/// <returns>You must return <c>true</c> if you want to continue the
/// traversal. If you want to immediately stop the whole traversal,
/// return <c>false</c>.</returns>
public delegate bool EntryHandler(PwEntry pe);
public delegate void VoidDelegate();
public delegate string StrPwEntryDelegate(string str, PwEntry pe);
}

View File

@ -0,0 +1,37 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Interfaces
{
/// <summary>
/// Interface for objects that are deeply cloneable.
/// </summary>
/// <typeparam name="T">Reference type.</typeparam>
public interface IDeepCloneable<T> where T : class
{
/// <summary>
/// Deeply clone the object.
/// </summary>
/// <returns>Cloned object.</returns>
T CloneDeep();
}
}

View File

@ -0,0 +1,105 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Interfaces
{
/// <summary>
/// Status message types.
/// </summary>
public enum LogStatusType
{
/// <summary>
/// Default type: simple information type.
/// </summary>
Info = 0,
/// <summary>
/// Warning message.
/// </summary>
Warning,
/// <summary>
/// Error message.
/// </summary>
Error,
/// <summary>
/// Additional information. Depends on lines above.
/// </summary>
AdditionalInfo
}
/// <summary>
/// Status logging interface.
/// </summary>
public interface IStatusLogger
{
/// <summary>
/// Function which needs to be called when logging is started.
/// </summary>
/// <param name="strOperation">This string should roughly describe
/// the operation, of which the status is logged.</param>
/// <param name="bWriteOperationToLog">Specifies whether the
/// operation is written to the log or not.</param>
void StartLogging(string strOperation, bool bWriteOperationToLog);
/// <summary>
/// Function which needs to be called when logging is ended
/// (i.e. when no more messages will be logged and when the
/// percent value won't change any more).
/// </summary>
void EndLogging();
/// <summary>
/// Set the current progress in percent.
/// </summary>
/// <param name="uPercent">Percent of work finished.</param>
/// <returns>Returns <c>true</c> if the caller should continue
/// the current work.</returns>
bool SetProgress(uint uPercent);
/// <summary>
/// Set the current status text.
/// </summary>
/// <param name="strNewText">Status text.</param>
/// <param name="lsType">Type of the message.</param>
/// <returns>Returns <c>true</c> if the caller should continue
/// the current work.</returns>
bool SetText(string strNewText, LogStatusType lsType);
/// <summary>
/// Check if the user cancelled the current work.
/// </summary>
/// <returns>Returns <c>true</c> if the caller should continue
/// the current work.</returns>
bool ContinueWork();
}
public sealed class NullStatusLogger : IStatusLogger
{
public void StartLogging(string strOperation, bool bWriteOperationToLog) { }
public void EndLogging() { }
public bool SetProgress(uint uPercent) { return true; }
public bool SetText(string strNewText, LogStatusType lsType) { return true; }
public bool ContinueWork() { return true; }
}
}

View File

@ -0,0 +1,37 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Interfaces
{
public interface IStructureItem : ITimeLogger // Provides LocationChanged
{
PwUuid Uuid
{
get;
set;
}
PwGroup ParentGroup
{
get;
}
}
}

View File

@ -0,0 +1,105 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Interfaces
{
/// <summary>
/// Interface for objects that support various times (creation time, last
/// access time, last modification time and expiry time). Offers
/// several helper functions (for example a function to touch the current
/// object).
/// </summary>
public interface ITimeLogger
{
/// <summary>
/// The date/time when the object was created.
/// </summary>
DateTime CreationTime
{
get;
set;
}
/// <summary>
/// The date/time when the object was last accessed.
/// </summary>
DateTime LastAccessTime
{
get;
set;
}
/// <summary>
/// The date/time when the object was last modified.
/// </summary>
DateTime LastModificationTime
{
get;
set;
}
/// <summary>
/// The date/time when the object expires.
/// </summary>
DateTime ExpiryTime
{
get;
set;
}
/// <summary>
/// Flag that determines if the object does expire.
/// </summary>
bool Expires
{
get;
set;
}
/// <summary>
/// Get or set the usage count of the object. To increase the usage
/// count by one, use the <c>Touch</c> function.
/// </summary>
ulong UsageCount
{
get;
set;
}
/// <summary>
/// The date/time when the location of the object was last changed.
/// </summary>
DateTime LocationChanged
{
get;
set;
}
/// <summary>
/// Touch the object. This function updates the internal last access
/// time. If the <paramref name="bModified" /> parameter is <c>true</c>,
/// the last modification time gets updated, too. Each time you call
/// <c>Touch</c>, the usage count of the object is increased by one.
/// </summary>
/// <param name="bModified">Update last modification time.</param>
void Touch(bool bModified);
}
}

View File

@ -0,0 +1,37 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
namespace KeePassLib.Interfaces
{
public interface IUIOperations
{
/// <summary>
/// Let the user interface save the current database.
/// </summary>
/// <param name="bForceSave">If <c>true</c>, the UI will not ask for
/// whether to synchronize or overwrite, it'll simply overwrite the
/// file.</param>
/// <returns>Returns <c>true</c> if the file has been saved.</returns>
bool UIFileSave(bool bForceSave);
}
}

View File

@ -0,0 +1,33 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Xml;
namespace KeePassLib.Interfaces
{
public interface IXmlSerializerEx
{
void Serialize(XmlWriter xmlWriter, object o);
object Deserialize(Stream s);
}
}

Binary file not shown.

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{545B4A6B-8BBA-4FBE-92FC-4AC060122A54}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<RootNamespace>KeePassLib2Android</RootNamespace>
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AndroidResgenClass>Resource</AndroidResgenClass>
<AssemblyName>KeePassLib2Android</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>False</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>None</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>True</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<ConsolePause>False</ConsolePause>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Mono.Android" />
</ItemGroup>
<ItemGroup>
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="Resources\KLRes.Generated.cs" />
<Compile Include="Resources\KSRes.Generated.cs" />
<Compile Include="Collections\AutoTypeConfig.cs" />
<Compile Include="Collections\ProtectedBinaryDictionary.cs" />
<Compile Include="Collections\ProtectedStringDictionary.cs" />
<Compile Include="Collections\PwObjectList.cs" />
<Compile Include="Collections\PwObjectPool.cs" />
<Compile Include="Collections\StringDictionaryEx.cs" />
<Compile Include="Cryptography\Cipher\CipherPool.cs" />
<Compile Include="Cryptography\Cipher\Salsa20Cipher.cs" />
<Compile Include="Cryptography\Cipher\StandardAesEngine.cs" />
<Compile Include="Cryptography\CryptoRandom.cs" />
<Compile Include="Cryptography\CryptoRandomStream.cs" />
<Compile Include="Cryptography\Cipher\ICipherEngine.cs" />
<Compile Include="Cryptography\HashingStreamEx.cs" />
<Compile Include="Cryptography\HmacOtp.cs" />
<Compile Include="Cryptography\PasswordGenerator\CharSetBasedGenerator.cs" />
<Compile Include="Cryptography\PasswordGenerator\CustomPwGenerator.cs" />
<Compile Include="Cryptography\PasswordGenerator\CustomPwGeneratorPool.cs" />
<Compile Include="Cryptography\PasswordGenerator\PatternBasedGenerator.cs" />
<Compile Include="Cryptography\PasswordGenerator\PwCharSet.cs" />
<Compile Include="Cryptography\PasswordGenerator\PwProfile.cs" />
<Compile Include="Cryptography\PopularPasswords.cs" />
<Compile Include="Cryptography\QualityEstimation.cs" />
<Compile Include="Cryptography\SelfTest.cs" />
<Compile Include="Cryptography\PasswordGenerator\PwGenerator.cs" />
<Compile Include="PwCustomIcon.cs" />
<Compile Include="PwDatabase.cs" />
<Compile Include="PwDefs.cs" />
<Compile Include="PwDeletedObject.cs" />
<Compile Include="PwEntry.cs" />
<Compile Include="PwEnums.cs" />
<Compile Include="PwGroup.cs" />
<Compile Include="PwUuid.cs" />
<Compile Include="Interfaces\IStructureItem.cs" />
<Compile Include="Interfaces\IUIOperations.cs" />
<Compile Include="Interfaces\IXmlSerializerEx.cs" />
<Compile Include="Interfaces\IDeepCloneable.cs" />
<Compile Include="Interfaces\IStatusLogger.cs" />
<Compile Include="Interfaces\ITimeLogger.cs" />
<Compile Include="Keys\KcpCustomKey.cs" />
<Compile Include="Keys\KeyProvider.cs" />
<Compile Include="Keys\KeyProviderPool.cs" />
<Compile Include="Keys\KeyValidator.cs" />
<Compile Include="Keys\KeyValidatorPool.cs" />
<Compile Include="Keys\UserKeyType.cs" />
<Compile Include="Keys\KcpKeyFile.cs" />
<Compile Include="Keys\IUserKey.cs" />
<Compile Include="Keys\KcpPassword.cs" />
<Compile Include="Keys\KcpUserAccount.cs" />
<Compile Include="Keys\CompositeKey.cs" />
<Compile Include="Native\NativeMethods.cs" />
<Compile Include="Native\NativeLib.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Security\XorredBuffer.cs" />
<Compile Include="Security\ProtectedBinary.cs" />
<Compile Include="Security\ProtectedString.cs" />
<Compile Include="Serialization\BinaryReaderEx.cs" />
<Compile Include="Serialization\FileLock.cs" />
<Compile Include="Serialization\FileTransactionEx.cs" />
<Compile Include="Serialization\HashedBlockStream.cs" />
<Compile Include="Serialization\IOConnection.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Serialization\KdbxFile.cs" />
<Compile Include="Serialization\KdbxFile.Read.cs" />
<Compile Include="Serialization\KdbxFile.Read.Streamed.cs" />
<Compile Include="Serialization\KdbxFile.Write.cs" />
<Compile Include="Serialization\IOConnectionInfo.cs" />
<Compile Include="Serialization\OldFormatException.cs" />
<Compile Include="Translation\KPControlCustomization.cs" />
<Compile Include="Translation\KPFormCustomization.cs" />
<Compile Include="Translation\KPStringTable.cs" />
<Compile Include="Translation\KPStringTableItem.cs" />
<Compile Include="Translation\KPTranslation.cs" />
<Compile Include="Translation\KPTranslationProperties.cs" />
<Compile Include="Utility\AppLogEx.cs" />
<Compile Include="Utility\GfxUtil.cs" />
<Compile Include="Utility\MemUtil.cs" />
<Compile Include="Utility\MessageService.cs" />
<Compile Include="Utility\StrUtil.cs" />
<Compile Include="Utility\UrlUtil.cs" />
<Compile Include="Utility\TimeUtil.cs" />
<Compile Include="Delegates\Handlers.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\AboutResources.txt" />
<None Include="KeePassLib.pfx" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\values\Strings.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
</Project>

View File

@ -0,0 +1,408 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using KeePassLib.Native;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
/// <summary>
/// Represents a key. A key can be build up using several user key data sources
/// like a password, a key file, the currently logged on user credentials,
/// the current computer ID, etc.
/// </summary>
public sealed class CompositeKey
{
private List<IUserKey> m_vUserKeys = new List<IUserKey>();
/// <summary>
/// List of all user keys contained in the current composite key.
/// </summary>
public IEnumerable<IUserKey> UserKeys
{
get { return m_vUserKeys; }
}
public uint UserKeyCount
{
get { return (uint)m_vUserKeys.Count; }
}
/// <summary>
/// Construct a new, empty key object.
/// </summary>
public CompositeKey()
{
}
// /// <summary>
// /// Deconstructor, clears up the key.
// /// </summary>
// ~CompositeKey()
// {
// Clear();
// }
// /// <summary>
// /// Clears the key. This function also erases all previously stored
// /// user key data objects.
// /// </summary>
// public void Clear()
// {
// foreach(IUserKey pKey in m_vUserKeys)
// pKey.Clear();
// m_vUserKeys.Clear();
// }
/// <summary>
/// Add a user key.
/// </summary>
/// <param name="pKey">User key to add.</param>
public void AddUserKey(IUserKey pKey)
{
Debug.Assert(pKey != null); if(pKey == null) throw new ArgumentNullException("pKey");
m_vUserKeys.Add(pKey);
}
/// <summary>
/// Remove a user key.
/// </summary>
/// <param name="pKey">User key to remove.</param>
/// <returns>Returns <c>true</c> if the key was removed successfully.</returns>
public bool RemoveUserKey(IUserKey pKey)
{
Debug.Assert(pKey != null); if(pKey == null) throw new ArgumentNullException("pKey");
Debug.Assert(m_vUserKeys.IndexOf(pKey) >= 0);
return m_vUserKeys.Remove(pKey);
}
/// <summary>
/// Test whether the composite key contains a specific type of
/// user keys (password, key file, ...). If at least one user
/// key of that type is present, the function returns <c>true</c>.
/// </summary>
/// <param name="tUserKeyType">User key type.</param>
/// <returns>Returns <c>true</c>, if the composite key contains
/// a user key of the specified type.</returns>
public bool ContainsType(Type tUserKeyType)
{
Debug.Assert(tUserKeyType != null);
if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType");
foreach(IUserKey pKey in m_vUserKeys)
{
if(tUserKeyType.IsInstanceOfType(pKey))
return true;
}
return false;
}
/// <summary>
/// Get the first user key of a specified type.
/// </summary>
/// <param name="tUserKeyType">Type of the user key to get.</param>
/// <returns>Returns the first user key of the specified type
/// or <c>null</c> if no key of that type is found.</returns>
public IUserKey GetUserKey(Type tUserKeyType)
{
Debug.Assert(tUserKeyType != null);
if(tUserKeyType == null) throw new ArgumentNullException("tUserKeyType");
foreach(IUserKey pKey in m_vUserKeys)
{
if(tUserKeyType.IsInstanceOfType(pKey))
return pKey;
}
return null;
}
/// <summary>
/// Creates the composite key from the supplied user key sources (password,
/// key file, user account, computer ID, etc.).
/// </summary>
private byte[] CreateRawCompositeKey32()
{
ValidateUserKeys();
// Concatenate user key data
MemoryStream ms = new MemoryStream();
foreach(IUserKey pKey in m_vUserKeys)
{
ProtectedBinary b = pKey.KeyData;
if(b != null)
{
byte[] pbKeyData = b.ReadData();
ms.Write(pbKeyData, 0, pbKeyData.Length);
MemUtil.ZeroByteArray(pbKeyData);
}
}
SHA256Managed sha256 = new SHA256Managed();
byte[] pbHash = sha256.ComputeHash(ms.ToArray());
ms.Close();
return pbHash;
}
public bool EqualsValue(CompositeKey ckOther)
{
if(ckOther == null) throw new ArgumentNullException("ckOther");
byte[] pbThis = CreateRawCompositeKey32();
byte[] pbOther = ckOther.CreateRawCompositeKey32();
bool bResult = MemUtil.ArraysEqual(pbThis, pbOther);
Array.Clear(pbOther, 0, pbOther.Length);
Array.Clear(pbThis, 0, pbThis.Length);
return bResult;
}
/// <summary>
/// Generate a 32-bit wide key out of the composite key.
/// </summary>
/// <param name="pbKeySeed32">Seed used in the key transformation
/// rounds. Must be a byte array containing exactly 32 bytes; must
/// not be null.</param>
/// <param name="uNumRounds">Number of key transformation rounds.</param>
/// <returns>Returns a protected binary object that contains the
/// resulting 32-bit wide key.</returns>
public ProtectedBinary GenerateKey32(byte[] pbKeySeed32, ulong uNumRounds)
{
Debug.Assert(pbKeySeed32 != null);
if(pbKeySeed32 == null) throw new ArgumentNullException("pbKeySeed32");
Debug.Assert(pbKeySeed32.Length == 32);
if(pbKeySeed32.Length != 32) throw new ArgumentException("pbKeySeed32");
byte[] pbRaw32 = CreateRawCompositeKey32();
if((pbRaw32 == null) || (pbRaw32.Length != 32))
{ Debug.Assert(false); return null; }
byte[] pbTrf32 = TransformKey(pbRaw32, pbKeySeed32, uNumRounds);
if((pbTrf32 == null) || (pbTrf32.Length != 32))
{ Debug.Assert(false); return null; }
ProtectedBinary pbRet = new ProtectedBinary(true, pbTrf32);
MemUtil.ZeroByteArray(pbTrf32);
MemUtil.ZeroByteArray(pbRaw32);
return pbRet;
}
private void ValidateUserKeys()
{
int nAccounts = 0;
foreach(IUserKey uKey in m_vUserKeys)
{
if(uKey is KcpUserAccount)
++nAccounts;
}
if(nAccounts >= 2)
{
Debug.Assert(false);
throw new InvalidOperationException();
}
}
/// <summary>
/// Transform the current key <c>uNumRounds</c> times.
/// </summary>
/// <param name="pbOriginalKey32">The original key which will be transformed.
/// This parameter won't be modified.</param>
/// <param name="pbKeySeed32">Seed used for key transformations. Must not
/// be <c>null</c>. This parameter won't be modified.</param>
/// <param name="uNumRounds">Transformation count.</param>
/// <returns>256-bit transformed key.</returns>
private static byte[] TransformKey(byte[] pbOriginalKey32, byte[] pbKeySeed32,
ulong uNumRounds)
{
Debug.Assert((pbOriginalKey32 != null) && (pbOriginalKey32.Length == 32));
if(pbOriginalKey32 == null) throw new ArgumentNullException("pbOriginalKey32");
if(pbOriginalKey32.Length != 32) throw new ArgumentException();
Debug.Assert((pbKeySeed32 != null) && (pbKeySeed32.Length == 32));
if(pbKeySeed32 == null) throw new ArgumentNullException("pbKeySeed32");
if(pbKeySeed32.Length != 32) throw new ArgumentException();
byte[] pbNewKey = new byte[32];
Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length);
// Try to use the native library first
if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds))
return (new SHA256Managed()).ComputeHash(pbNewKey);
if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds) == false)
return null;
SHA256Managed sha256 = new SHA256Managed();
return sha256.ComputeHash(pbNewKey);
}
public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32,
ulong uNumRounds)
{
byte[] pbIV = new byte[16];
Array.Clear(pbIV, 0, pbIV.Length);
RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size
{
Debug.Assert(false);
r.BlockSize = 128;
}
r.IV = pbIV;
r.Mode = CipherMode.ECB;
r.KeySize = 256;
r.Key = pbKeySeed32;
ICryptoTransform iCrypt = r.CreateEncryptor();
// !iCrypt.CanReuseTransform -- doesn't work with Mono
if((iCrypt == null) || (iCrypt.InputBlockSize != 16) ||
(iCrypt.OutputBlockSize != 16))
{
Debug.Assert(false, "Invalid ICryptoTransform.");
Debug.Assert((iCrypt.InputBlockSize == 16), "Invalid input block size!");
Debug.Assert((iCrypt.OutputBlockSize == 16), "Invalid output block size!");
return false;
}
for(ulong i = 0; i < uNumRounds; ++i)
{
iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0);
iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16);
}
return true;
}
/// <summary>
/// Benchmark the <c>TransformKey</c> method. Within
/// <paramref name="uMilliseconds"/> ms, random keys will be transformed
/// and the number of performed transformations are returned.
/// </summary>
/// <param name="uMilliseconds">Test duration in ms.</param>
/// <param name="uStep">Stepping.
/// <paramref name="uStep" /> should be a prime number. For fast processors
/// (PCs) a value of <c>3001</c> is recommended, for slower processors (PocketPC)
/// a value of <c>401</c> is recommended.</param>
/// <returns>Number of transformations performed in the specified
/// amount of time. Maximum value is <c>uint.MaxValue</c>.</returns>
public static ulong TransformKeyBenchmark(uint uMilliseconds, ulong uStep)
{
ulong uRounds;
// Try native method
if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds))
return uRounds;
byte[] pbIV = new byte[16];
Array.Clear(pbIV, 0, pbIV.Length);
byte[] pbKey = new byte[32];
byte[] pbNewKey = new byte[32];
for(int i = 0; i < pbKey.Length; ++i)
{
pbKey[i] = (byte)i;
pbNewKey[i] = (byte)i;
}
RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size
{
Debug.Assert(false);
r.BlockSize = 128;
}
r.IV = pbIV;
r.Mode = CipherMode.ECB;
r.KeySize = 256;
r.Key = pbKey;
ICryptoTransform iCrypt = r.CreateEncryptor();
// !iCrypt.CanReuseTransform -- doesn't work with Mono
if((iCrypt == null) || (iCrypt.InputBlockSize != 16) ||
(iCrypt.OutputBlockSize != 16))
{
Debug.Assert(false, "Invalid ICryptoTransform.");
Debug.Assert(iCrypt.InputBlockSize == 16, "Invalid input block size!");
Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!");
return PwDefs.DefaultKeyEncryptionRounds;
}
DateTime dtStart = DateTime.Now;
TimeSpan ts;
double dblReqMillis = uMilliseconds;
uRounds = 0;
while(true)
{
for(ulong j = 0; j < uStep; ++j)
{
iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0);
iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16);
}
uRounds += uStep;
if(uRounds < uStep) // Overflow check
{
uRounds = ulong.MaxValue;
break;
}
ts = DateTime.Now - dtStart;
if(ts.TotalMilliseconds > dblReqMillis) break;
}
return uRounds;
}
}
public sealed class InvalidCompositeKeyException : Exception
{
public override string Message
{
get
{
return KLRes.InvalidCompositeKey + MessageService.NewParagraph +
KLRes.InvalidCompositeKeyHint;
}
}
/// <summary>
/// Construct a new invalid composite key exception.
/// </summary>
public InvalidCompositeKeyException()
{
}
}
}

View File

@ -0,0 +1,46 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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 KeePassLib.Security;
namespace KeePassLib.Keys
{
/// <summary>
/// Interface to a user key, like a password, key file data, etc.
/// </summary>
public interface IUserKey
{
/// <summary>
/// Get key data. Querying this property is fast (it returns a
/// reference to a cached <c>ProtectedBinary</c> object).
/// If no key data is available, <c>null</c> is returned.
/// </summary>
ProtectedBinary KeyData
{
get;
}
// /// <summary>
// /// Clear the key and securely erase all security-critical information.
// /// </summary>
// void Clear();
}
}

View File

@ -0,0 +1,70 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using System.Security.Cryptography;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
public sealed class KcpCustomKey : IUserKey
{
private readonly string m_strName;
private ProtectedBinary m_pbKey;
/// <summary>
/// Name of the provider that generated the custom key.
/// </summary>
public string Name
{
get { return m_strName; }
}
public ProtectedBinary KeyData
{
get { return m_pbKey; }
}
public KcpCustomKey(string strName, byte[] pbKeyData, bool bPerformHash)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
Debug.Assert(pbKeyData != null); if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
m_strName = strName;
if(bPerformHash)
{
SHA256Managed sha256 = new SHA256Managed();
byte[] pbRaw = sha256.ComputeHash(pbKeyData);
m_pbKey = new ProtectedBinary(true, pbRaw);
}
else m_pbKey = new ProtectedBinary(true, pbKeyData);
}
// public void Clear()
// {
// m_pbKey = null;
// }
}
}

View File

@ -0,0 +1,271 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Diagnostics;
using KeePassLib.Cryptography;
using KeePassLib.Security;
using KeePassLib.Serialization;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
/// <summary>
/// Key files as provided by the user.
/// </summary>
public sealed class KcpKeyFile : IUserKey
{
private string m_strPath;
private ProtectedBinary m_pbKeyData;
/// <summary>
/// Path to the key file.
/// </summary>
public string Path
{
get { return m_strPath; }
}
/// <summary>
/// Get key data. Querying this property is fast (it returns a
/// reference to a cached <c>ProtectedBinary</c> object).
/// If no key data is available, <c>null</c> is returned.
/// </summary>
public ProtectedBinary KeyData
{
get { return m_pbKeyData; }
}
public KcpKeyFile(string strKeyFile)
{
Construct(IOConnectionInfo.FromPath(strKeyFile));
}
public KcpKeyFile(IOConnectionInfo iocKeyFile)
{
Construct(iocKeyFile);
}
private void Construct(IOConnectionInfo iocFile)
{
byte[] pbFileData = IOConnection.ReadFile(iocFile);
if(pbFileData == null) throw new FileNotFoundException();
byte[] pbKey = LoadXmlKeyFile(pbFileData);
if(pbKey == null) pbKey = LoadKeyFile(pbFileData);
if(pbKey == null) throw new InvalidOperationException();
m_strPath = iocFile.Path;
m_pbKeyData = new ProtectedBinary(true, pbKey);
MemUtil.ZeroByteArray(pbKey);
}
// public void Clear()
// {
// m_strPath = string.Empty;
// m_pbKeyData = null;
// }
private static byte[] LoadKeyFile(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
int iLength = pbFileData.Length;
byte[] pbKey = null;
if(iLength == 32) pbKey = LoadBinaryKey32(pbFileData);
else if(iLength == 64) pbKey = LoadHexKey32(pbFileData);
if(pbKey == null)
{
SHA256Managed sha256 = new SHA256Managed();
pbKey = sha256.ComputeHash(pbFileData);
}
return pbKey;
}
private static byte[] LoadBinaryKey32(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
if(pbFileData.Length != 32) { Debug.Assert(false); return null; }
return pbFileData;
}
private static byte[] LoadHexKey32(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
if(pbFileData.Length != 64) { Debug.Assert(false); return null; }
try
{
string strHex = Encoding.ASCII.GetString(pbFileData, 0, 64);
if(!StrUtil.IsHexString(strHex, true)) return null;
byte[] pbKey = MemUtil.HexStringToByteArray(strHex);
if((pbKey == null) || (pbKey.Length != 32))
return null;
return pbKey;
}
catch(Exception) { Debug.Assert(false); }
return null;
}
/// <summary>
/// Create a new, random key-file.
/// </summary>
/// <param name="strFilePath">Path where the key-file should be saved to.
/// If the file exists already, it will be overwritten.</param>
/// <param name="pbAdditionalEntropy">Additional entropy used to generate
/// the random key. May be <c>null</c> (in this case only the KeePass-internal
/// random number generator is used).</param>
/// <returns>Returns a <c>FileSaveResult</c> error code.</returns>
public static void Create(string strFilePath, byte[] pbAdditionalEntropy)
{
byte[] pbKey32 = CryptoRandom.Instance.GetRandomBytes(32);
if(pbKey32 == null) throw new SecurityException();
byte[] pbFinalKey32;
if((pbAdditionalEntropy == null) || (pbAdditionalEntropy.Length == 0))
pbFinalKey32 = pbKey32;
else
{
MemoryStream ms = new MemoryStream();
ms.Write(pbAdditionalEntropy, 0, pbAdditionalEntropy.Length);
ms.Write(pbKey32, 0, 32);
SHA256Managed sha256 = new SHA256Managed();
pbFinalKey32 = sha256.ComputeHash(ms.ToArray());
ms.Close();
}
CreateXmlKeyFile(strFilePath, pbFinalKey32);
}
// ================================================================
// XML Key Files
// ================================================================
// Sample XML file:
// <?xml version="1.0" encoding="utf-8"?>
// <KeyFile>
// <Meta>
// <Version>1.00</Version>
// </Meta>
// <Key>
// <Data>ySFoKuCcJblw8ie6RkMBdVCnAf4EedSch7ItujK6bmI=</Data>
// </Key>
// </KeyFile>
private const string RootElementName = "KeyFile";
private const string MetaElementName = "Meta";
private const string VersionElementName = "Version";
private const string KeyElementName = "Key";
private const string KeyDataElementName = "Data";
private static byte[] LoadXmlKeyFile(byte[] pbFileData)
{
if(pbFileData == null) { Debug.Assert(false); return null; }
MemoryStream ms = new MemoryStream(pbFileData, false);
byte[] pbKeyData = null;
try
{
XmlDocument doc = new XmlDocument();
doc.Load(ms);
XmlElement el = doc.DocumentElement;
if((el == null) || !el.Name.Equals(RootElementName)) return null;
if(el.ChildNodes.Count < 2) return null;
foreach(XmlNode xmlChild in el.ChildNodes)
{
if(xmlChild.Name.Equals(MetaElementName)) { } // Ignore Meta
else if(xmlChild.Name == KeyElementName)
{
foreach(XmlNode xmlKeyChild in xmlChild.ChildNodes)
{
if(xmlKeyChild.Name == KeyDataElementName)
{
if(pbKeyData == null)
pbKeyData = Convert.FromBase64String(xmlKeyChild.InnerText);
}
}
}
}
}
catch(Exception) { pbKeyData = null; }
finally { ms.Close(); }
return pbKeyData;
}
private static void CreateXmlKeyFile(string strFile, byte[] pbKeyData)
{
Debug.Assert(strFile != null);
if(strFile == null) throw new ArgumentNullException("strFile");
Debug.Assert(pbKeyData != null);
if(pbKeyData == null) throw new ArgumentNullException("pbKeyData");
XmlTextWriter xtw = new XmlTextWriter(strFile, StrUtil.Utf8);
xtw.WriteStartDocument();
xtw.WriteWhitespace("\r\n");
xtw.WriteStartElement(RootElementName); // KeyFile
xtw.WriteWhitespace("\r\n\t");
xtw.WriteStartElement(MetaElementName); // Meta
xtw.WriteWhitespace("\r\n\t\t");
xtw.WriteStartElement(VersionElementName); // Version
xtw.WriteString("1.00");
xtw.WriteEndElement(); // End Version
xtw.WriteWhitespace("\r\n\t");
xtw.WriteEndElement(); // End Meta
xtw.WriteWhitespace("\r\n\t");
xtw.WriteStartElement(KeyElementName); // Key
xtw.WriteWhitespace("\r\n\t\t");
xtw.WriteStartElement(KeyDataElementName); // Data
xtw.WriteString(Convert.ToBase64String(pbKeyData));
xtw.WriteEndElement(); // End Data
xtw.WriteWhitespace("\r\n\t");
xtw.WriteEndElement(); // End Key
xtw.WriteWhitespace("\r\n");
xtw.WriteEndElement(); // RootElementName
xtw.WriteWhitespace("\r\n");
xtw.WriteEndDocument(); // End KeyFile
xtw.Close();
}
}
}

View File

@ -0,0 +1,84 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using System.Security.Cryptography;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
/// <summary>
/// Master password / passphrase as provided by the user.
/// </summary>
public sealed class KcpPassword : IUserKey
{
private ProtectedString m_psPassword;
private ProtectedBinary m_pbKeyData;
/// <summary>
/// Get the password as protected string.
/// </summary>
public ProtectedString Password
{
get { return m_psPassword; }
}
/// <summary>
/// Get key data. Querying this property is fast (it returns a
/// reference to a cached <c>ProtectedBinary</c> object).
/// If no key data is available, <c>null</c> is returned.
/// </summary>
public ProtectedBinary KeyData
{
get { return m_pbKeyData; }
}
public KcpPassword(byte[] pbPasswordUtf8)
{
SetKey(pbPasswordUtf8);
}
public KcpPassword(string strPassword)
{
SetKey(StrUtil.Utf8.GetBytes(strPassword));
}
private void SetKey(byte[] pbPasswordUtf8)
{
Debug.Assert(pbPasswordUtf8 != null);
if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8");
SHA256Managed sha256 = new SHA256Managed();
byte[] pbRaw = sha256.ComputeHash(pbPasswordUtf8);
m_psPassword = new ProtectedString(true, pbPasswordUtf8);
m_pbKeyData = new ProtectedBinary(true, pbRaw);
}
// public void Clear()
// {
// m_psPassword = null;
// m_pbKeyData = null;
// }
}
}

View File

@ -0,0 +1,148 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Security;
using System.Security.Cryptography;
using System.IO;
using KeePassLib.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
/// <summary>
/// A user key depending on the currently logged on Windows user account.
/// </summary>
public sealed class KcpUserAccount : IUserKey
{
private ProtectedBinary m_pbKeyData = null;
// Constant initialization vector (unique for KeePass)
private static readonly byte[] m_pbEntropy = new byte[]{
0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
};
private const string UserKeyFileName = "ProtectedUserKey.bin";
/// <summary>
/// Get key data. Querying this property is fast (it returns a
/// reference to a cached <c>ProtectedBinary</c> object).
/// If no key data is available, <c>null</c> is returned.
/// </summary>
public ProtectedBinary KeyData
{
get { return m_pbKeyData; }
}
/// <summary>
/// Construct a user account key.
/// </summary>
public KcpUserAccount()
{
// Test if ProtectedData is supported -- throws an exception
// when running on an old system (Windows 98 / ME).
byte[] pbDummyData = new byte[128];
ProtectedData.Protect(pbDummyData, m_pbEntropy,
DataProtectionScope.CurrentUser);
byte[] pbKey = LoadUserKey(false);
if(pbKey == null) pbKey = CreateUserKey();
if(pbKey == null) throw new SecurityException(KLRes.UserAccountKeyError);
m_pbKeyData = new ProtectedBinary(true, pbKey);
Array.Clear(pbKey, 0, pbKey.Length);
}
// public void Clear()
// {
// m_pbKeyData = null;
// }
private static string GetUserKeyFilePath(bool bCreate)
{
string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
strUserDir += PwDefs.ShortProductName;
if(bCreate && !Directory.Exists(strUserDir))
Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
return strUserDir + UserKeyFileName;
}
private static byte[] LoadUserKey(bool bShowWarning)
{
byte[] pbKey = null;
#if !KeePassLibSD
try
{
string strFilePath = GetUserKeyFilePath(false);
byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
}
catch(Exception exLoad)
{
if(bShowWarning) MessageService.ShowWarning(exLoad);
pbKey = null;
}
#endif
return pbKey;
}
private static byte[] CreateUserKey()
{
byte[] pbKey = null;
#if !KeePassLibSD
try
{
string strFilePath = GetUserKeyFilePath(true);
byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
m_pbEntropy, DataProtectionScope.CurrentUser);
File.WriteAllBytes(strFilePath, pbProtectedKey);
Array.Clear(pbProtectedKey, 0, pbProtectedKey.Length);
Array.Clear(pbRandomKey, 0, pbRandomKey.Length);
pbKey = LoadUserKey(true);
}
catch(Exception) { pbKey = null; }
#endif
return pbKey;
}
}
}

View File

@ -0,0 +1,152 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using KeePassLib.Serialization;
namespace KeePassLib.Keys
{
public sealed class KeyProviderQueryContext
{
private IOConnectionInfo m_ioInfo;
public IOConnectionInfo DatabaseIOInfo
{
get { return m_ioInfo; }
}
public string DatabasePath
{
get { return m_ioInfo.Path; }
}
private bool m_bCreatingNewKey;
public bool CreatingNewKey
{
get { return m_bCreatingNewKey; }
}
private bool m_bSecDesktop;
public bool IsOnSecureDesktop
{
get { return m_bSecDesktop; }
}
public KeyProviderQueryContext(IOConnectionInfo ioInfo, bool bCreatingNewKey,
bool bOnSecDesktop)
{
if(ioInfo == null) throw new ArgumentNullException("ioInfo");
m_ioInfo = ioInfo.CloneDeep();
m_bCreatingNewKey = bCreatingNewKey;
m_bSecDesktop = bOnSecDesktop;
}
}
public abstract class KeyProvider
{
/// <summary>
/// Name of your key provider (should be unique).
/// </summary>
public abstract string Name
{
get;
}
/// <summary>
/// Property indicating whether the provider is exclusive.
/// If the provider is exclusive, KeePass doesn't allow other
/// key sources (master password, Windows user account, ...)
/// to be combined with the provider.
/// Key providers typically should return <c>false</c>
/// (to allow non-exclusive use), i.e. don't override this
/// property.
/// </summary>
public virtual bool Exclusive
{
get { return false; }
}
/// <summary>
/// Property that specifies whether the returned key data
/// gets hashed by KeePass first or is written directly to
/// the user key data stream.
/// Standard key provider plugins should return <c>false</c>
/// (i.e. don't overwrite this property). Returning <c>true</c>
/// may cause severe security problems and is highly
/// discouraged.
/// </summary>
public virtual bool DirectKey
{
get { return false; }
}
// public virtual PwIcon ImageIndex
// {
// get { return PwIcon.UserKey; }
// }
/// <summary>
/// This property specifies whether the <c>GetKey</c> method might
/// show a form or dialog. If there is any chance that the method shows
/// one, this property must return <c>true</c>. Only if it's guaranteed
/// that the <c>GetKey</c> method doesn't show any form or dialog, this
/// property should return <c>false</c>.
/// </summary>
public virtual bool GetKeyMightShowGui
{
get { return true; }
}
/// <summary>
/// This property specifies whether the key provider is compatible
/// with the secure desktop mode. This almost never is the case,
/// so you usually won't override this property.
/// </summary>
public virtual bool SecureDesktopCompatible
{
get { return false; }
}
public abstract byte[] GetKey(KeyProviderQueryContext ctx);
}
#if DEBUG
public sealed class SampleKeyProvider : KeyProvider
{
public override string Name
{
get { return "Built-In Sample Key Provider"; }
}
// Do not just copy this to your own key provider class! See above.
public override bool GetKeyMightShowGui
{
get { return false; }
}
public override byte[] GetKey(KeyProviderQueryContext ctx)
{
return new byte[]{ 2, 3, 5, 7, 11, 13 };
}
}
#endif
}

View File

@ -0,0 +1,105 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace KeePassLib.Keys
{
public sealed class KeyProviderPool : IEnumerable<KeyProvider>
{
private List<KeyProvider> m_vProviders = new List<KeyProvider>();
public int Count
{
get { return m_vProviders.Count; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vProviders.GetEnumerator();
}
public IEnumerator<KeyProvider> GetEnumerator()
{
return m_vProviders.GetEnumerator();
}
public void Add(KeyProvider prov)
{
Debug.Assert(prov != null); if(prov == null) throw new ArgumentNullException("prov");
m_vProviders.Add(prov);
}
public bool Remove(KeyProvider prov)
{
Debug.Assert(prov != null); if(prov == null) throw new ArgumentNullException("prov");
return m_vProviders.Remove(prov);
}
public KeyProvider Get(string strProviderName)
{
if(strProviderName == null) throw new ArgumentNullException("strProviderName");
foreach(KeyProvider prov in m_vProviders)
{
if(prov.Name == strProviderName) return prov;
}
return null;
}
public bool IsKeyProvider(string strName)
{
Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName");
foreach(KeyProvider prov in m_vProviders)
{
if(prov.Name == strName) return true;
}
return false;
}
internal byte[] GetKey(string strProviderName, KeyProviderQueryContext ctx,
out bool bPerformHash)
{
Debug.Assert(strProviderName != null); if(strProviderName == null) throw new ArgumentNullException("strProviderName");
bPerformHash = true;
foreach(KeyProvider prov in m_vProviders)
{
if(prov.Name == strProviderName)
{
bPerformHash = !prov.DirectKey;
return prov.GetKey(ctx);
}
}
Debug.Assert(false);
return null;
}
}
}

View File

@ -0,0 +1,51 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
namespace KeePassLib.Keys
{
public enum KeyValidationType
{
MasterPassword = 0
}
public abstract class KeyValidator
{
/// <summary>
/// Name of your key validator (should be unique).
/// </summary>
public abstract string Name
{
get;
}
/// <summary>
/// Validate a key.
/// </summary>
/// <param name="strKey">Key to validate.</param>
/// <param name="t">Type of the validation to perform.</param>
/// <returns>Returns <c>null</c>, if the validation is successful.
/// If there's a problem with the key, the returned string describes
/// the problem.</returns>
public abstract string Validate(string strKey, KeyValidationType t);
}
}

View File

@ -0,0 +1,86 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Keys
{
public sealed class KeyValidatorPool : IEnumerable<KeyValidator>
{
private List<KeyValidator> m_vValidators = new List<KeyValidator>();
public int Count
{
get { return m_vValidators.Count; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_vValidators.GetEnumerator();
}
public IEnumerator<KeyValidator> GetEnumerator()
{
return m_vValidators.GetEnumerator();
}
public void Add(KeyValidator v)
{
Debug.Assert(v != null); if(v == null) throw new ArgumentNullException("v");
m_vValidators.Add(v);
}
public bool Remove(KeyValidator v)
{
Debug.Assert(v != null); if(v == null) throw new ArgumentNullException("v");
return m_vValidators.Remove(v);
}
public string Validate(string strKey, KeyValidationType t)
{
Debug.Assert(strKey != null); if(strKey == null) throw new ArgumentNullException("strKey");
foreach(KeyValidator v in m_vValidators)
{
string strResult = v.Validate(strKey, t);
if(strResult != null) return strResult;
}
return null;
}
public string Validate(byte[] pbKeyUtf8, KeyValidationType t)
{
Debug.Assert(pbKeyUtf8 != null); if(pbKeyUtf8 == null) throw new ArgumentNullException("pbKeyUtf8");
if(m_vValidators.Count == 0) return null;
string strKey = StrUtil.Utf8.GetString(pbKeyUtf8, 0, pbKeyUtf8.Length);
return Validate(strKey, t);
}
}
}

View File

@ -0,0 +1,33 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib.Keys
{
[Flags]
public enum UserKeyType
{
None = 0,
Other = 1,
Password = 2,
KeyFile = 4,
UserAccount = 8
}
}

View File

@ -0,0 +1,234 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Runtime.InteropServices;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Native
{
/// <summary>
/// Interface to native library (library containing fast versions of
/// several cryptographic functions).
/// </summary>
public static class NativeLib
{
private static bool m_bAllowNative = true;
/// <summary>
/// If this property is set to <c>true</c>, the native library is used.
/// If it is <c>false</c>, all calls to functions in this class will fail.
/// </summary>
public static bool AllowNative
{
get { return m_bAllowNative; }
set { m_bAllowNative = value; }
}
/// <summary>
/// Determine if the native library is installed.
/// </summary>
/// <returns>Returns <c>true</c>, if the native library is installed.</returns>
public static bool IsLibraryInstalled()
{
byte[] pDummy0 = new byte[32];
byte[] pDummy1 = new byte[32];
// Save the native state
bool bCachedNativeState = m_bAllowNative;
// Temporarily allow native functions and try to load the library
m_bAllowNative = true;
bool bResult = TransformKey256(pDummy0, pDummy1, 16);
// Pop native state and return result
m_bAllowNative = bCachedNativeState;
return bResult;
}
private static bool? m_bIsUnix = null;
public static bool IsUnix()
{
if(m_bIsUnix.HasValue) return m_bIsUnix.Value;
PlatformID p = GetPlatformID();
// Mono defines Unix as 128 in early .NET versions
#if !KeePassLibSD
m_bIsUnix = ((p == PlatformID.Unix) || (p == PlatformID.MacOSX) ||
((int)p == 128));
#else
m_bIsUnix = (((int)p == 4) || ((int)p == 6) || ((int)p == 128));
#endif
return m_bIsUnix.Value;
}
private static PlatformID? m_platID = null;
public static PlatformID GetPlatformID()
{
if(m_platID.HasValue) return m_platID.Value;
m_platID = Environment.OSVersion.Platform;
#if !KeePassLibSD
// Mono returns PlatformID.Unix on Mac OS X, workaround this
if(m_platID.Value == PlatformID.Unix)
{
if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals(
"Darwin", StrUtil.CaseIgnoreCmp))
m_platID = PlatformID.MacOSX;
}
#endif
return m_platID.Value;
}
#if !KeePassLibSD
public static string RunConsoleApp(string strAppPath, string strParams)
{
return RunConsoleApp(strAppPath, strParams, null);
}
public static string RunConsoleApp(string strAppPath, string strParams,
string strStdInput)
{
if(strAppPath == null) throw new ArgumentNullException("strAppPath");
if(strAppPath.Length == 0) throw new ArgumentException("strAppPath");
try
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.CreateNoWindow = true;
psi.FileName = strAppPath;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
if(strStdInput != null) psi.RedirectStandardInput = true;
if(!string.IsNullOrEmpty(strParams)) psi.Arguments = strParams;
Process p = Process.Start(psi);
if(strStdInput != null)
{
p.StandardInput.Write(strStdInput);
p.StandardInput.Close();
}
string strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
return strOutput;
}
catch(Exception) { Debug.Assert(false); }
return null;
}
#endif
/// <summary>
/// Transform a key.
/// </summary>
/// <param name="pBuf256">Source and destination buffer.</param>
/// <param name="pKey256">Key to use in the transformation.</param>
/// <param name="uRounds">Number of transformation rounds.</param>
/// <returns>Returns <c>true</c>, if the key was transformed successfully.</returns>
public static bool TransformKey256(byte[] pBuf256, byte[] pKey256,
ulong uRounds)
{
if(m_bAllowNative == false) return false;
KeyValuePair<IntPtr, IntPtr> kvp = PrepareArrays256(pBuf256, pKey256);
bool bResult = false;
try
{
bResult = NativeMethods.TransformKey(kvp.Key, kvp.Value, uRounds);
}
catch(Exception) { bResult = false; }
if(bResult) GetBuffers256(kvp, pBuf256, pKey256);
NativeLib.FreeArrays(kvp);
return bResult;
}
/// <summary>
/// Benchmark key transformation.
/// </summary>
/// <param name="uTimeMs">Number of seconds to perform the benchmark.</param>
/// <param name="puRounds">Number of transformations done.</param>
/// <returns>Returns <c>true</c>, if the benchmark was successful.</returns>
public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds)
{
puRounds = 0;
if(m_bAllowNative == false) return false;
try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); }
catch(Exception) { return false; }
return true;
}
private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256,
byte[] pKey256)
{
Debug.Assert((pBuf256 != null) && (pBuf256.Length == 32));
if(pBuf256 == null) throw new ArgumentNullException("pBuf256");
if(pBuf256.Length != 32) throw new ArgumentException();
Debug.Assert((pKey256 != null) && (pKey256.Length == 32));
if(pKey256 == null) throw new ArgumentNullException("pKey256");
if(pKey256.Length != 32) throw new ArgumentException();
IntPtr hBuf = Marshal.AllocHGlobal(pBuf256.Length);
Marshal.Copy(pBuf256, 0, hBuf, pBuf256.Length);
IntPtr hKey = Marshal.AllocHGlobal(pKey256.Length);
Marshal.Copy(pKey256, 0, hKey, pKey256.Length);
return new KeyValuePair<IntPtr, IntPtr>(hBuf, hKey);
}
private static void GetBuffers256(KeyValuePair<IntPtr, IntPtr> kvpSource,
byte[] pbDestBuf, byte[] pbDestKey)
{
if(kvpSource.Key != IntPtr.Zero)
Marshal.Copy(kvpSource.Key, pbDestBuf, 0, pbDestBuf.Length);
if(kvpSource.Value != IntPtr.Zero)
Marshal.Copy(kvpSource.Value, pbDestKey, 0, pbDestKey.Length);
}
private static void FreeArrays(KeyValuePair<IntPtr, IntPtr> kvpPointers)
{
if(kvpPointers.Key != IntPtr.Zero)
Marshal.FreeHGlobal(kvpPointers.Key);
if(kvpPointers.Value != IntPtr.Zero)
Marshal.FreeHGlobal(kvpPointers.Value);
}
}
}

View File

@ -0,0 +1,179 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib.Native
{
internal static class NativeMethods
{
internal const int MAX_PATH = 260;
/* [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKey")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey32(IntPtr pBuf256,
IntPtr pKey256, UInt64 uRounds);
[DllImport("KeePassNtv64.dll", EntryPoint = "TransformKey")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey64(IntPtr pBuf256,
IntPtr pKey256, UInt64 uRounds);
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
UInt64 uRounds)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
return TransformKey64(pBuf256, pKey256, uRounds);
else
return TransformKey32(pBuf256, pKey256, uRounds);
}
[DllImport("KeePassNtv32.dll", EntryPoint = "TransformKeyTimed")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKeyTimed32(IntPtr pBuf256,
IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds);
[DllImport("KeePassNtv64.dll", EntryPoint = "TransformKeyTimed")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKeyTimed64(IntPtr pBuf256,
IntPtr pKey256, ref UInt64 puRounds, UInt32 uSeconds);
internal static bool TransformKeyTimed(IntPtr pBuf256, IntPtr pKey256,
ref UInt64 puRounds, UInt32 uSeconds)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
return TransformKeyTimed64(pBuf256, pKey256, ref puRounds, uSeconds);
else
return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds);
} */
[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKey256")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey32(IntPtr pBuf256,
IntPtr pKey256, UInt64 uRounds);
[DllImport("KeePassLibC64.dll", EntryPoint = "TransformKey256")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool TransformKey64(IntPtr pBuf256,
IntPtr pKey256, UInt64 uRounds);
internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256,
UInt64 uRounds)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
return TransformKey64(pBuf256, pKey256, uRounds);
else
return TransformKey32(pBuf256, pKey256, uRounds);
}
[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKeyBenchmark256")]
private static extern UInt64 TransformKeyBenchmark32(UInt32 uTimeMs);
[DllImport("KeePassLibC64.dll", EntryPoint = "TransformKeyBenchmark256")]
private static extern UInt64 TransformKeyBenchmark64(UInt32 uTimeMs);
internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs)
{
if(Marshal.SizeOf(typeof(IntPtr)) == 8)
return TransformKeyBenchmark64(uTimeMs);
else
return TransformKeyBenchmark32(uTimeMs);
}
#if !KeePassLibSD
[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
internal static extern int StrCmpLogicalW(string x, string y);
[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath,
[In] string pszFrom, [In] uint dwAttrFrom, [In] string pszTo,
[In] uint dwAttrTo);
#endif
private static bool? m_bSupportsLogicalCmp = null;
private static void TestNaturalComparisonsSupport()
{
#if KeePassLibSD
#warning No native natural comparisons supported.
m_bSupportsLogicalCmp = false;
#else
try
{
StrCmpLogicalW("0", "0"); // Throws exception if unsupported
m_bSupportsLogicalCmp = true;
}
catch(Exception) { m_bSupportsLogicalCmp = false; }
#endif
}
internal static bool SupportsStrCmpNaturally
{
get
{
if(m_bSupportsLogicalCmp.HasValue == false)
TestNaturalComparisonsSupport();
return m_bSupportsLogicalCmp.Value;
}
}
internal static int StrCmpNaturally(string x, string y)
{
if(m_bSupportsLogicalCmp.HasValue == false) TestNaturalComparisonsSupport();
if(m_bSupportsLogicalCmp.Value == false) return 0;
#if KeePassLibSD
#warning No native natural comparisons supported.
return x.CompareTo(y);
#else
return StrCmpLogicalW(x, y);
#endif
}
internal static string GetUserRuntimeDir()
{
#if !KeePassLibSD
string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR");
if(string.IsNullOrEmpty(strRtDir))
strRtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
if(string.IsNullOrEmpty(strRtDir))
{
Debug.Assert(false);
return Path.GetTempPath(); // Not UrlUtil (otherwise cyclic)
}
strRtDir = UrlUtil.EnsureTerminatingSeparator(strRtDir, false);
strRtDir += PwDefs.ShortProductName;
return strRtDir;
#else
return Path.GetTempPath();
#endif
}
}
}

View File

@ -0,0 +1,42 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General assembly properties
[assembly: AssemblyTitle("KeePassLib")]
[assembly: AssemblyDescription("KeePass Password Management Library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Dominik Reichl")]
[assembly: AssemblyProduct("KeePassLib")]
[assembly: AssemblyCopyright("Copyright © 2003-2012 Dominik Reichl")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// COM settings
[assembly: ComVisible(false)]
// Assembly GUID
[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")]
// Assembly version information
[assembly: AssemblyVersion("2.20.1.*")]
[assembly: AssemblyFileVersion("2.20.1.0")]

View File

@ -0,0 +1,76 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Diagnostics;
using System.Drawing;
using System.IO;
using KeePassLib.Utility;
namespace KeePassLib
{
/// <summary>
/// Custom icon. <c>PwCustomIcon</c> objects are immutable.
/// </summary>
public sealed class PwCustomIcon
{
private PwUuid m_pwUuid;
private byte[] m_pbImageDataPng;
private Image m_pCachedImage;
public PwUuid Uuid
{
get { return m_pwUuid; }
}
public byte[] ImageDataPng
{
get { return m_pbImageDataPng; }
}
public Image Image
{
get { return m_pCachedImage; }
}
public PwCustomIcon(PwUuid pwUuid, byte[] pbImageDataPng)
{
Debug.Assert(pwUuid != null);
if(pwUuid == null) throw new ArgumentNullException("pwUuid");
Debug.Assert(pwUuid != PwUuid.Zero);
if(pwUuid == PwUuid.Zero) throw new ArgumentException("pwUuid == 0");
Debug.Assert(pbImageDataPng != null);
if(pbImageDataPng == null) throw new ArgumentNullException("pbImageDataPng");
m_pwUuid = pwUuid;
m_pbImageDataPng = pbImageDataPng;
#if !KeePassLibSD
// MemoryStream ms = new MemoryStream(m_pbImageDataPng, false);
// m_pCachedImage = Image.FromStream(ms);
// ms.Close();
m_pCachedImage = GfxUtil.LoadImage(m_pbImageDataPng);
#else
m_pCachedImage = null;
#endif
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,461 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Xml.Serialization;
using System.ComponentModel;
using System.Diagnostics;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
namespace KeePassLib
{
/// <summary>
/// Contains KeePassLib-global definitions and enums.
/// </summary>
public static class PwDefs
{
/// <summary>
/// The product name.
/// </summary>
public const string ProductName = "KeePass Password Safe";
/// <summary>
/// A short, simple string representing the product name. The string
/// should contain no spaces, directory separator characters, etc.
/// </summary>
public const string ShortProductName = "KeePass";
internal const string UnixName = "keepass2";
internal const string ResClass = "KeePass2"; // With initial capital
/// <summary>
/// Version, encoded as 32-bit unsigned integer.
/// 2.00 = 0x02000000, 2.01 = 0x02000100, ..., 2.18 = 0x02010800.
/// As of 2.19, the version is encoded component-wise per byte,
/// e.g. 2.19 = 0x02130000.
/// It is highly recommended to use <c>FileVersion64</c> instead.
/// </summary>
public const uint Version32 = 0x02140100;
/// <summary>
/// Version, encoded as 64-bit unsigned integer
/// (component-wise, 16 bits per component).
/// </summary>
public const ulong FileVersion64 = 0x0002001400010000UL;
/// <summary>
/// Version, encoded as string.
/// </summary>
public const string VersionString = "2.20.1";
public const string Copyright = @"Copyright © 2003-2012 Dominik Reichl";
/// <summary>
/// Product website URL. Terminated by a forward slash.
/// </summary>
public const string HomepageUrl = "http://keepass.info/";
/// <summary>
/// Product donations URL.
/// </summary>
public const string DonationsUrl = "http://keepass.info/donate.html";
/// <summary>
/// URL to the online plugins page.
/// </summary>
public const string PluginsUrl = "http://keepass.info/plugins.html";
/// <summary>
/// URL to the online translations page.
/// </summary>
public const string TranslationsUrl = "http://keepass.info/translations.html";
/// <summary>
/// URL to a TXT file (eventually compressed) that contains information
/// about the latest KeePass version available on the website.
/// </summary>
public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz";
/// <summary>
/// URL to the root path of the online KeePass help. Terminated by
/// a forward slash.
/// </summary>
public const string HelpUrl = "http://keepass.info/help/";
/// <summary>
/// A <c>DateTime</c> object that represents the time when the assembly
/// was loaded.
/// </summary>
public static readonly DateTime DtDefaultNow = DateTime.Now;
/// <summary>
/// Default number of master key encryption/transformation rounds (making dictionary attacks harder).
/// </summary>
public const ulong DefaultKeyEncryptionRounds = 6000;
/// <summary>
/// Default identifier string for the title field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public const string TitleField = "Title";
/// <summary>
/// Default identifier string for the user name field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public const string UserNameField = "UserName";
/// <summary>
/// Default identifier string for the password field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public const string PasswordField = "Password";
/// <summary>
/// Default identifier string for the URL field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public const string UrlField = "URL";
/// <summary>
/// Default identifier string for the notes field. Should not contain
/// spaces, tabs or other whitespace.
/// </summary>
public const string NotesField = "Notes";
/// <summary>
/// Default identifier string for the field which will contain TAN indices.
/// </summary>
public const string TanIndexField = UserNameField;
/// <summary>
/// Default title of an entry that is really a TAN entry.
/// </summary>
public const string TanTitle = @"<TAN>";
/// <summary>
/// Prefix of a custom auto-type string field.
/// </summary>
public const string AutoTypeStringPrefix = "S:";
/// <summary>
/// Default string representing a hidden password.
/// </summary>
public const string HiddenPassword = "********";
/// <summary>
/// Default auto-type keystroke sequence. If no custom sequence is
/// specified, this sequence is used.
/// </summary>
public const string DefaultAutoTypeSequence = @"{USERNAME}{TAB}{PASSWORD}{ENTER}";
/// <summary>
/// Default auto-type keystroke sequence for TAN entries. If no custom
/// sequence is specified, this sequence is used.
/// </summary>
public const string DefaultAutoTypeSequenceTan = @"{PASSWORD}";
/// <summary>
/// Check if a name is a standard field name.
/// </summary>
/// <param name="strFieldName">Input field name.</param>
/// <returns>Returns <c>true</c>, if the field name is a standard
/// field name (title, user name, password, ...), otherwise <c>false</c>.</returns>
public static bool IsStandardField(string strFieldName)
{
Debug.Assert(strFieldName != null); if(strFieldName == null) return false;
if(strFieldName.Equals(TitleField)) return true;
if(strFieldName.Equals(UserNameField)) return true;
if(strFieldName.Equals(PasswordField)) return true;
if(strFieldName.Equals(UrlField)) return true;
if(strFieldName.Equals(NotesField)) return true;
return false;
}
public static List<string> GetStandardFields()
{
List<string> l = new List<string>();
l.Add(TitleField);
l.Add(UserNameField);
l.Add(PasswordField);
l.Add(UrlField);
l.Add(NotesField);
return l;
}
/// <summary>
/// Check if an entry is a TAN.
/// </summary>
/// <param name="pe">Password entry.</param>
/// <returns>Returns <c>true</c> if the entry is a TAN.</returns>
public static bool IsTanEntry(PwEntry pe)
{
Debug.Assert(pe != null); if(pe == null) return false;
return (pe.Strings.ReadSafe(PwDefs.TitleField) == TanTitle);
}
}
#pragma warning disable 1591 // Missing XML comments warning
/// <summary>
/// Search parameters for group and entry searches.
/// </summary>
public sealed class SearchParameters
{
private string m_strText = string.Empty;
[DefaultValue("")]
public string SearchString
{
get { return m_strText; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strText = value;
}
}
private bool m_bRegex = false;
[DefaultValue(false)]
public bool RegularExpression
{
get { return m_bRegex; }
set { m_bRegex = value; }
}
private bool m_bSearchInTitles = true;
[DefaultValue(true)]
public bool SearchInTitles
{
get { return m_bSearchInTitles; }
set { m_bSearchInTitles = value; }
}
private bool m_bSearchInUserNames = true;
[DefaultValue(true)]
public bool SearchInUserNames
{
get { return m_bSearchInUserNames; }
set { m_bSearchInUserNames = value; }
}
private bool m_bSearchInPasswords = false;
[DefaultValue(false)]
public bool SearchInPasswords
{
get { return m_bSearchInPasswords; }
set { m_bSearchInPasswords = value; }
}
private bool m_bSearchInUrls = true;
[DefaultValue(true)]
public bool SearchInUrls
{
get { return m_bSearchInUrls; }
set { m_bSearchInUrls = value; }
}
private bool m_bSearchInNotes = true;
[DefaultValue(true)]
public bool SearchInNotes
{
get { return m_bSearchInNotes; }
set { m_bSearchInNotes = value; }
}
private bool m_bSearchInOther = true;
[DefaultValue(true)]
public bool SearchInOther
{
get { return m_bSearchInOther; }
set { m_bSearchInOther = value; }
}
private bool m_bSearchInUuids = false;
[DefaultValue(false)]
public bool SearchInUuids
{
get { return m_bSearchInUuids; }
set { m_bSearchInUuids = value; }
}
private bool m_bSearchInGroupNames = false;
[DefaultValue(false)]
public bool SearchInGroupNames
{
get { return m_bSearchInGroupNames; }
set { m_bSearchInGroupNames = value; }
}
private bool m_bSearchInTags = true;
[DefaultValue(true)]
public bool SearchInTags
{
get { return m_bSearchInTags; }
set { m_bSearchInTags = value; }
}
private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase;
/// <summary>
/// String comparison type. Specifies the condition when the specified
/// text matches a group/entry string.
/// </summary>
public StringComparison ComparisonMode
{
get { return m_scType; }
set { m_scType = value; }
}
private bool m_bExcludeExpired = false;
[DefaultValue(false)]
public bool ExcludeExpired
{
get { return m_bExcludeExpired; }
set { m_bExcludeExpired = value; }
}
private bool m_bRespectEntrySearchingDisabled = true;
[DefaultValue(true)]
public bool RespectEntrySearchingDisabled
{
get { return m_bRespectEntrySearchingDisabled; }
set { m_bRespectEntrySearchingDisabled = value; }
}
private StrPwEntryDelegate m_fnDataTrf = null;
[XmlIgnore]
public StrPwEntryDelegate DataTransformationFn
{
get { return m_fnDataTrf; }
set { m_fnDataTrf = value; }
}
private string m_strDataTrf = string.Empty;
/// <summary>
/// Only for serialization.
/// </summary>
[DefaultValue("")]
public string DataTransformation
{
get { return m_strDataTrf; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strDataTrf = value;
}
}
[XmlIgnore]
public static SearchParameters None
{
get
{
SearchParameters sp = new SearchParameters();
// sp.m_strText = string.Empty;
// sp.m_bRegex = false;
sp.m_bSearchInTitles = false;
sp.m_bSearchInUserNames = false;
// sp.m_bSearchInPasswords = false;
sp.m_bSearchInUrls = false;
sp.m_bSearchInNotes = false;
sp.m_bSearchInOther = false;
// sp.m_bSearchInUuids = false;
// sp.SearchInGroupNames = false;
sp.m_bSearchInTags = false;
// sp.m_scType = StringComparison.InvariantCultureIgnoreCase;
// sp.m_bExcludeExpired = false;
// m_bRespectEntrySearchingDisabled = true;
return sp;
}
}
/// <summary>
/// Construct a new search parameters object.
/// </summary>
public SearchParameters()
{
}
public SearchParameters Clone()
{
return (SearchParameters)this.MemberwiseClone();
}
}
#pragma warning restore 1591 // Missing XML comments warning
#pragma warning disable 1591 // Missing XML comments warning
/// <summary>
/// Memory protection configuration structure (for default fields).
/// </summary>
public sealed class MemoryProtectionConfig : IDeepCloneable<MemoryProtectionConfig>
{
public bool ProtectTitle = false;
public bool ProtectUserName = false;
public bool ProtectPassword = true;
public bool ProtectUrl = false;
public bool ProtectNotes = false;
// public bool AutoEnableVisualHiding = false;
public MemoryProtectionConfig CloneDeep()
{
return (MemoryProtectionConfig)this.MemberwiseClone();
}
public bool GetProtection(string strField)
{
if(strField == PwDefs.TitleField) return this.ProtectTitle;
if(strField == PwDefs.UserNameField) return this.ProtectUserName;
if(strField == PwDefs.PasswordField) return this.ProtectPassword;
if(strField == PwDefs.UrlField) return this.ProtectUrl;
if(strField == PwDefs.NotesField) return this.ProtectNotes;
return false;
}
}
#pragma warning restore 1591 // Missing XML comments warning
public sealed class ObjectTouchedEventArgs : EventArgs
{
private object m_o;
public object Object { get { return m_o; } }
private bool m_bModified;
public bool Modified { get { return m_bModified; } }
private bool m_bParentsTouched;
public bool ParentsTouched { get { return m_bParentsTouched; } }
public ObjectTouchedEventArgs(object o, bool bModified,
bool bParentsTouched)
{
m_o = o;
m_bModified = bModified;
m_bParentsTouched = bParentsTouched;
}
}
}

View File

@ -0,0 +1,86 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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 KeePassLib.Interfaces;
namespace KeePassLib
{
/// <summary>
/// Represents an object that has been deleted.
/// </summary>
public sealed class PwDeletedObject : IDeepCloneable<PwDeletedObject>
{
private PwUuid m_uuid = PwUuid.Zero;
/// <summary>
/// UUID of the entry that has been deleted.
/// </summary>
public PwUuid Uuid
{
get { return m_uuid; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_uuid = value;
}
}
private DateTime m_dtDeletionTime = PwDefs.DtDefaultNow;
/// <summary>
/// The date/time when the entry has been deleted.
/// </summary>
public DateTime DeletionTime
{
get { return m_dtDeletionTime; }
set { m_dtDeletionTime = value; }
}
/// <summary>
/// Construct a new <c>PwDeletedObject</c> object.
/// </summary>
public PwDeletedObject()
{
}
public PwDeletedObject(PwUuid uuid, DateTime dtDeletionTime)
{
if(uuid == null) throw new ArgumentNullException("uuid");
m_uuid = uuid;
m_dtDeletionTime = dtDeletionTime;
}
/// <summary>
/// Clone the object.
/// </summary>
/// <returns>Value copy of the current object.</returns>
public PwDeletedObject CloneDeep()
{
PwDeletedObject pdo = new PwDeletedObject();
pdo.m_uuid = m_uuid; // PwUuid objects are immutable
pdo.m_dtDeletionTime = m_dtDeletionTime;
return pdo;
}
}
}

View File

@ -0,0 +1,874 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Xml;
using System.Drawing;
using KeePassLib.Collections;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib
{
/// <summary>
/// A class representing a password entry. A password entry consists of several
/// fields like title, user name, password, etc. Each password entry has a
/// unique ID (UUID).
/// </summary>
public sealed class PwEntry : ITimeLogger, IStructureItem, IDeepCloneable<PwEntry>
{
private PwUuid m_uuid = PwUuid.Zero;
private PwGroup m_pParentGroup = null;
private DateTime m_tParentGroupLastMod = PwDefs.DtDefaultNow;
private ProtectedStringDictionary m_listStrings = new ProtectedStringDictionary();
private ProtectedBinaryDictionary m_listBinaries = new ProtectedBinaryDictionary();
private AutoTypeConfig m_listAutoType = new AutoTypeConfig();
private PwObjectList<PwEntry> m_listHistory = new PwObjectList<PwEntry>();
private PwIcon m_pwIcon = PwIcon.Key;
private PwUuid m_pwCustomIconID = PwUuid.Zero;
private Color m_clrForeground = Color.Empty;
private Color m_clrBackground = Color.Empty;
private DateTime m_tCreation = PwDefs.DtDefaultNow;
private DateTime m_tLastMod = PwDefs.DtDefaultNow;
private DateTime m_tLastAccess = PwDefs.DtDefaultNow;
private DateTime m_tExpire = PwDefs.DtDefaultNow;
private bool m_bExpires = false;
private ulong m_uUsageCount = 0;
private string m_strOverrideUrl = string.Empty;
private List<string> m_vTags = new List<string>();
/// <summary>
/// UUID of this entry.
/// </summary>
public PwUuid Uuid
{
get { return m_uuid; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_uuid = value;
}
}
/// <summary>
/// Reference to a group which contains the current entry.
/// </summary>
public PwGroup ParentGroup
{
get { return m_pParentGroup; }
/// Plugins: use <c>PwGroup.AddEntry</c> instead.
internal set { m_pParentGroup = value; }
}
/// <summary>
/// The date/time when the location of the object was last changed.
/// </summary>
public DateTime LocationChanged
{
get { return m_tParentGroupLastMod; }
set { m_tParentGroupLastMod = value; }
}
/// <summary>
/// Get or set all entry strings.
/// </summary>
public ProtectedStringDictionary Strings
{
get { return m_listStrings; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_listStrings = value;
}
}
/// <summary>
/// Get or set all entry binaries.
/// </summary>
public ProtectedBinaryDictionary Binaries
{
get { return m_listBinaries; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_listBinaries = value;
}
}
/// <summary>
/// Get or set all auto-type window/keystroke sequence associations.
/// </summary>
public AutoTypeConfig AutoType
{
get { return m_listAutoType; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_listAutoType = value;
}
}
/// <summary>
/// Get all previous versions of this entry (backups).
/// </summary>
public PwObjectList<PwEntry> History
{
get { return m_listHistory; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_listHistory = value;
}
}
/// <summary>
/// Image ID specifying the icon that will be used for this entry.
/// </summary>
public PwIcon IconId
{
get { return m_pwIcon; }
set { m_pwIcon = value; }
}
/// <summary>
/// Get the custom icon ID. This value is 0, if no custom icon is
/// being used (i.e. the icon specified by the <c>IconID</c> property
/// should be displayed).
/// </summary>
public PwUuid CustomIconUuid
{
get { return m_pwCustomIconID; }
set
{
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_pwCustomIconID = value;
}
}
/// <summary>
/// Get or set the foreground color of this entry.
/// </summary>
public Color ForegroundColor
{
get { return m_clrForeground; }
set { m_clrForeground = value; }
}
/// <summary>
/// Get or set the background color of this entry.
/// </summary>
public Color BackgroundColor
{
get { return m_clrBackground; }
set { m_clrBackground = value; }
}
/// <summary>
/// The date/time when this entry was created.
/// </summary>
public DateTime CreationTime
{
get { return m_tCreation; }
set { m_tCreation = value; }
}
/// <summary>
/// The date/time when this entry was last accessed (read).
/// </summary>
public DateTime LastAccessTime
{
get { return m_tLastAccess; }
set { m_tLastAccess = value; }
}
/// <summary>
/// The date/time when this entry was last modified.
/// </summary>
public DateTime LastModificationTime
{
get { return m_tLastMod; }
set { m_tLastMod = value; }
}
/// <summary>
/// The date/time when this entry expires. Use the <c>Expires</c> property
/// to specify if the entry does actually expire or not.
/// </summary>
public DateTime ExpiryTime
{
get { return m_tExpire; }
set { m_tExpire = value; }
}
/// <summary>
/// Specifies whether the entry expires or not.
/// </summary>
public bool Expires
{
get { return m_bExpires; }
set { m_bExpires = value; }
}
/// <summary>
/// Get or set the usage count of the entry. To increase the usage
/// count by one, use the <c>Touch</c> function.
/// </summary>
public ulong UsageCount
{
get { return m_uUsageCount; }
set { m_uUsageCount = value; }
}
/// <summary>
/// Entry-specific override URL. If this string is non-empty,
/// </summary>
public string OverrideUrl
{
get { return m_strOverrideUrl; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strOverrideUrl = value;
}
}
/// <summary>
/// List of tags associated with this entry.
/// </summary>
public List<string> Tags
{
get { return m_vTags; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_vTags = value;
}
}
public static EventHandler<ObjectTouchedEventArgs> EntryTouched;
public EventHandler<ObjectTouchedEventArgs> Touched;
/// <summary>
/// Construct a new, empty password entry. Member variables will be initialized
/// to their default values.
/// </summary>
/// <param name="bCreateNewUuid">If <c>true</c>, a new UUID will be created
/// for this entry. If <c>false</c>, the UUID is zero and you must set it
/// manually later.</param>
/// <param name="bSetTimes">If <c>true</c>, the creation, last modification
/// and last access times will be set to the current system time.</param>
public PwEntry(bool bCreateNewUuid, bool bSetTimes)
{
if(bCreateNewUuid) m_uuid = new PwUuid(true);
if(bSetTimes)
{
m_tCreation = m_tLastMod = m_tLastAccess =
m_tParentGroupLastMod = DateTime.Now;
}
}
/// <summary>
/// Construct a new, empty password entry. Member variables will be initialized
/// to their default values.
/// </summary>
/// <param name="pwParentGroup">Reference to the containing group, this
/// parameter may be <c>null</c> and set later manually.</param>
/// <param name="bCreateNewUuid">If <c>true</c>, a new UUID will be created
/// for this entry. If <c>false</c>, the UUID is zero and you must set it
/// manually later.</param>
/// <param name="bSetTimes">If <c>true</c>, the creation, last modification
/// and last access times will be set to the current system time.</param>
[Obsolete("Use a different constructor. To add an entry to a group, use AddEntry of PwGroup.")]
public PwEntry(PwGroup pwParentGroup, bool bCreateNewUuid, bool bSetTimes)
{
m_pParentGroup = pwParentGroup;
if(bCreateNewUuid) m_uuid = new PwUuid(true);
if(bSetTimes)
{
m_tCreation = m_tLastMod = m_tLastAccess =
m_tParentGroupLastMod = DateTime.Now;
}
}
/// <summary>
/// Clone the current entry. The returned entry is an exact value copy
/// of the current entry (including UUID and parent group reference).
/// All mutable members are cloned.
/// </summary>
/// <returns>Exact value clone. All references to mutable values changed.</returns>
public PwEntry CloneDeep()
{
PwEntry peNew = new PwEntry(false, false);
peNew.m_uuid = m_uuid; // PwUuid is immutable
peNew.m_pParentGroup = m_pParentGroup;
peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
peNew.m_listStrings = m_listStrings.CloneDeep();
peNew.m_listBinaries = m_listBinaries.CloneDeep();
peNew.m_listAutoType = m_listAutoType.CloneDeep();
peNew.m_listHistory = m_listHistory.CloneDeep();
peNew.m_pwIcon = m_pwIcon;
peNew.m_pwCustomIconID = m_pwCustomIconID;
peNew.m_clrForeground = m_clrForeground;
peNew.m_clrBackground = m_clrBackground;
peNew.m_tCreation = m_tCreation;
peNew.m_tLastMod = m_tLastMod;
peNew.m_tLastAccess = m_tLastAccess;
peNew.m_tExpire = m_tExpire;
peNew.m_bExpires = m_bExpires;
peNew.m_uUsageCount = m_uUsageCount;
peNew.m_strOverrideUrl = m_strOverrideUrl;
peNew.m_vTags = new List<string>(m_vTags);
return peNew;
}
public PwEntry CloneStructure()
{
PwEntry peNew = new PwEntry(false, false);
peNew.m_uuid = m_uuid; // PwUuid is immutable
peNew.m_tParentGroupLastMod = m_tParentGroupLastMod;
// Do not assign m_pParentGroup
return peNew;
}
private static PwCompareOptions BuildCmpOpt(bool bIgnoreParentGroup,
bool bIgnoreLastMod, bool bIgnoreLastAccess, bool bIgnoreHistory,
bool bIgnoreThisLastBackup)
{
PwCompareOptions pwOpt = PwCompareOptions.None;
if(bIgnoreParentGroup) pwOpt |= PwCompareOptions.IgnoreParentGroup;
if(bIgnoreLastMod) pwOpt |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) pwOpt |= PwCompareOptions.IgnoreLastAccess;
if(bIgnoreHistory) pwOpt |= PwCompareOptions.IgnoreHistory;
if(bIgnoreThisLastBackup) pwOpt |= PwCompareOptions.IgnoreLastBackup;
return pwOpt;
}
[Obsolete]
public bool EqualsEntry(PwEntry pe, bool bIgnoreParentGroup, bool bIgnoreLastMod,
bool bIgnoreLastAccess, bool bIgnoreHistory, bool bIgnoreThisLastBackup)
{
return EqualsEntry(pe, BuildCmpOpt(bIgnoreParentGroup, bIgnoreLastMod,
bIgnoreLastAccess, bIgnoreHistory, bIgnoreThisLastBackup),
MemProtCmpMode.None);
}
[Obsolete]
public bool EqualsEntry(PwEntry pe, bool bIgnoreParentGroup, bool bIgnoreLastMod,
bool bIgnoreLastAccess, bool bIgnoreHistory, bool bIgnoreThisLastBackup,
MemProtCmpMode mpCmpStr)
{
return EqualsEntry(pe, BuildCmpOpt(bIgnoreParentGroup, bIgnoreLastMod,
bIgnoreLastAccess, bIgnoreHistory, bIgnoreThisLastBackup), mpCmpStr);
}
public bool EqualsEntry(PwEntry pe, PwCompareOptions pwOpt,
MemProtCmpMode mpCmpStr)
{
if(pe == null) { Debug.Assert(false); return false; }
bool bNeEqStd = ((pwOpt & PwCompareOptions.NullEmptyEquivStd) !=
PwCompareOptions.None);
bool bIgnoreLastAccess = ((pwOpt & PwCompareOptions.IgnoreLastAccess) !=
PwCompareOptions.None);
bool bIgnoreLastMod = ((pwOpt & PwCompareOptions.IgnoreLastMod) !=
PwCompareOptions.None);
if(!m_uuid.EqualsValue(pe.m_uuid)) return false;
if((pwOpt & PwCompareOptions.IgnoreParentGroup) == PwCompareOptions.None)
{
if(m_pParentGroup != pe.m_pParentGroup) return false;
if(!bIgnoreLastMod && (m_tParentGroupLastMod != pe.m_tParentGroupLastMod))
return false;
}
if(!m_listStrings.EqualsDictionary(pe.m_listStrings, pwOpt, mpCmpStr))
return false;
if(!m_listBinaries.EqualsDictionary(pe.m_listBinaries)) return false;
if(!m_listAutoType.Equals(pe.m_listAutoType)) return false;
if((pwOpt & PwCompareOptions.IgnoreHistory) == PwCompareOptions.None)
{
bool bIgnoreLastBackup = ((pwOpt & PwCompareOptions.IgnoreLastBackup) !=
PwCompareOptions.None);
if(!bIgnoreLastBackup && (m_listHistory.UCount != pe.m_listHistory.UCount))
return false;
if(bIgnoreLastBackup && (m_listHistory.UCount == 0))
{
Debug.Assert(false);
return false;
}
if(bIgnoreLastBackup && ((m_listHistory.UCount - 1) != pe.m_listHistory.UCount))
return false;
PwCompareOptions cmpSub = PwCompareOptions.IgnoreParentGroup;
if(bNeEqStd) cmpSub |= PwCompareOptions.NullEmptyEquivStd;
if(bIgnoreLastMod) cmpSub |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) cmpSub |= PwCompareOptions.IgnoreLastAccess;
for(uint uHist = 0; uHist < pe.m_listHistory.UCount; ++uHist)
{
if(!m_listHistory.GetAt(uHist).EqualsEntry(pe.m_listHistory.GetAt(
uHist), cmpSub, MemProtCmpMode.None))
return false;
}
}
if(m_pwIcon != pe.m_pwIcon) return false;
if(!m_pwCustomIconID.EqualsValue(pe.m_pwCustomIconID)) return false;
if(m_clrForeground != pe.m_clrForeground) return false;
if(m_clrBackground != pe.m_clrBackground) return false;
if(m_tCreation != pe.m_tCreation) return false;
if(!bIgnoreLastMod && (m_tLastMod != pe.m_tLastMod)) return false;
if(!bIgnoreLastAccess && (m_tLastAccess != pe.m_tLastAccess)) return false;
if(m_tExpire != pe.m_tExpire) return false;
if(m_bExpires != pe.m_bExpires) return false;
if(!bIgnoreLastAccess && (m_uUsageCount != pe.m_uUsageCount)) return false;
if(m_strOverrideUrl != pe.m_strOverrideUrl) return false;
if(m_vTags.Count != pe.m_vTags.Count) return false;
for(int iTag = 0; iTag < m_vTags.Count; ++iTag)
{
if(m_vTags[iTag] != pe.m_vTags[iTag]) return false;
}
return true;
}
/// <summary>
/// Assign properties to the current entry based on a template entry.
/// </summary>
/// <param name="peTemplate">Template entry. Must not be <c>null</c>.</param>
/// <param name="bOnlyIfNewer">Only set the properties of the template entry
/// if it is newer than the current one.</param>
/// <param name="bIncludeHistory">If <c>true</c>, the history will be
/// copied, too.</param>
/// <param name="bAssignLocationChanged">If <c>true</c>, the
/// <c>LocationChanged</c> property is copied, otherwise not.</param>
public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer,
bool bIncludeHistory, bool bAssignLocationChanged)
{
Debug.Assert(peTemplate != null); if(peTemplate == null) throw new ArgumentNullException("peTemplate");
if(bOnlyIfNewer && (peTemplate.m_tLastMod < m_tLastMod)) return;
// Template UUID should be the same as the current one
Debug.Assert(m_uuid.EqualsValue(peTemplate.m_uuid));
m_uuid = peTemplate.m_uuid;
if(bAssignLocationChanged)
m_tParentGroupLastMod = peTemplate.m_tParentGroupLastMod;
m_listStrings = peTemplate.m_listStrings;
m_listBinaries = peTemplate.m_listBinaries;
m_listAutoType = peTemplate.m_listAutoType;
if(bIncludeHistory) m_listHistory = peTemplate.m_listHistory;
m_pwIcon = peTemplate.m_pwIcon;
m_pwCustomIconID = peTemplate.m_pwCustomIconID; // Immutable
m_clrForeground = peTemplate.m_clrForeground;
m_clrBackground = peTemplate.m_clrBackground;
m_tCreation = peTemplate.m_tCreation;
m_tLastMod = peTemplate.m_tLastMod;
m_tLastAccess = peTemplate.m_tLastAccess;
m_tExpire = peTemplate.m_tExpire;
m_bExpires = peTemplate.m_bExpires;
m_uUsageCount = peTemplate.m_uUsageCount;
m_strOverrideUrl = peTemplate.m_strOverrideUrl;
m_vTags = new List<string>(peTemplate.m_vTags);
}
/// <summary>
/// Touch the entry. This function updates the internal last access
/// time. If the <paramref name="bModified" /> parameter is <c>true</c>,
/// the last modification time gets updated, too.
/// </summary>
/// <param name="bModified">Modify last modification time.</param>
public void Touch(bool bModified)
{
Touch(bModified, true);
}
/// <summary>
/// Touch the entry. This function updates the internal last access
/// time. If the <paramref name="bModified" /> parameter is <c>true</c>,
/// the last modification time gets updated, too.
/// </summary>
/// <param name="bModified">Modify last modification time.</param>
/// <param name="bTouchParents">If <c>true</c>, all parent objects
/// get touched, too.</param>
public void Touch(bool bModified, bool bTouchParents)
{
m_tLastAccess = DateTime.Now;
++m_uUsageCount;
if(bModified) m_tLastMod = m_tLastAccess;
if(this.Touched != null)
this.Touched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents));
if(PwEntry.EntryTouched != null)
PwEntry.EntryTouched(this, new ObjectTouchedEventArgs(this,
bModified, bTouchParents));
if(bTouchParents && (m_pParentGroup != null))
m_pParentGroup.Touch(bModified, true);
}
/// <summary>
/// Create a backup of this entry. The backup item doesn't contain any
/// history items.
/// </summary>
[Obsolete]
public void CreateBackup()
{
CreateBackup(null);
}
/// <summary>
/// Create a backup of this entry. The backup item doesn't contain any
/// history items.
/// <param name="pwHistMntcSettings">If this parameter isn't <c>null</c>,
/// the history list is maintained automatically (i.e. old backups are
/// deleted if there are too many or the history size is too large).
/// This parameter may be <c>null</c> (no maintenance then).</param>
/// </summary>
public void CreateBackup(PwDatabase pwHistMntcSettings)
{
PwEntry peCopy = CloneDeep();
peCopy.History = new PwObjectList<PwEntry>(); // Remove history
m_listHistory.Add(peCopy); // Must be added at end, see EqualsEntry
if(pwHistMntcSettings != null) MaintainBackups(pwHistMntcSettings);
}
/// <summary>
/// Restore an entry snapshot from backups.
/// </summary>
/// <param name="uBackupIndex">Index of the backup item, to which
/// should be reverted.</param>
[Obsolete]
public void RestoreFromBackup(uint uBackupIndex)
{
RestoreFromBackup(uBackupIndex, null);
}
/// <summary>
/// Restore an entry snapshot from backups.
/// </summary>
/// <param name="uBackupIndex">Index of the backup item, to which
/// should be reverted.</param>
/// <param name="pwHistMntcSettings">If this parameter isn't <c>null</c>,
/// the history list is maintained automatically (i.e. old backups are
/// deleted if there are too many or the history size is too large).
/// This parameter may be <c>null</c> (no maintenance then).</param>
public void RestoreFromBackup(uint uBackupIndex, PwDatabase pwHistMntcSettings)
{
Debug.Assert(uBackupIndex < m_listHistory.UCount);
if(uBackupIndex >= m_listHistory.UCount)
throw new ArgumentOutOfRangeException("uBackupIndex");
PwEntry pe = m_listHistory.GetAt(uBackupIndex);
Debug.Assert(pe != null); if(pe == null) throw new InvalidOperationException();
CreateBackup(pwHistMntcSettings); // Backup current data before restoring
AssignProperties(pe, false, false, false);
}
public bool HasBackupOfData(PwEntry peData, bool bIgnoreLastMod,
bool bIgnoreLastAccess)
{
if(peData == null) { Debug.Assert(false); return false; }
PwCompareOptions cmpOpt = (PwCompareOptions.IgnoreParentGroup |
PwCompareOptions.IgnoreHistory | PwCompareOptions.NullEmptyEquivStd);
if(bIgnoreLastMod) cmpOpt |= PwCompareOptions.IgnoreLastMod;
if(bIgnoreLastAccess) cmpOpt |= PwCompareOptions.IgnoreLastAccess;
foreach(PwEntry pe in m_listHistory)
{
if(pe.EqualsEntry(peData, cmpOpt, MemProtCmpMode.None)) return true;
}
return false;
}
/// <summary>
/// Delete old history items if there are too many or the history
/// size is too large.
/// <returns>If one or more history items have been deleted, <c>true</c>
/// is returned. Otherwise <c>false</c>.</returns>
/// </summary>
public bool MaintainBackups(PwDatabase pwSettings)
{
if(pwSettings == null) { Debug.Assert(false); return false; }
bool bDeleted = false;
int nMaxItems = pwSettings.HistoryMaxItems;
if(nMaxItems >= 0)
{
while(m_listHistory.UCount > (uint)nMaxItems)
{
RemoveOldestBackup();
bDeleted = true;
}
}
long lMaxSize = pwSettings.HistoryMaxSize;
if(lMaxSize >= 0)
{
while(true)
{
ulong uHistSize = 0;
foreach(PwEntry pe in m_listHistory) { uHistSize += pe.GetSize(); }
if(uHistSize > (ulong)lMaxSize)
{
RemoveOldestBackup();
bDeleted = true;
}
else break;
}
}
return bDeleted;
}
private void RemoveOldestBackup()
{
DateTime dtMin = DateTime.MaxValue;
uint idxRemove = uint.MaxValue;
for(uint u = 0; u < m_listHistory.UCount; ++u)
{
PwEntry pe = m_listHistory.GetAt(u);
if(pe.LastModificationTime < dtMin)
{
idxRemove = u;
dtMin = pe.LastModificationTime;
}
}
if(idxRemove != uint.MaxValue) m_listHistory.RemoveAt(idxRemove);
}
public bool GetAutoTypeEnabled()
{
if(!m_listAutoType.Enabled) return false;
if(m_pParentGroup != null)
return m_pParentGroup.GetAutoTypeEnabledInherited();
return PwGroup.DefaultAutoTypeEnabled;
}
public string GetAutoTypeSequence()
{
string strSeq = m_listAutoType.DefaultSequence;
PwGroup pg = m_pParentGroup;
while(pg != null)
{
if(strSeq.Length != 0) break;
strSeq = pg.DefaultAutoTypeSequence;
pg = pg.ParentGroup;
}
if(strSeq.Length != 0) return strSeq;
if(PwDefs.IsTanEntry(this)) return PwDefs.DefaultAutoTypeSequenceTan;
return PwDefs.DefaultAutoTypeSequence;
}
public bool GetSearchingEnabled()
{
if(m_pParentGroup != null)
return m_pParentGroup.GetSearchingEnabledInherited();
return PwGroup.DefaultSearchingEnabled;
}
/// <summary>
/// Approximate the total size of this entry in bytes (including
/// strings, binaries and history entries).
/// </summary>
/// <returns>Size in bytes.</returns>
public ulong GetSize()
{
ulong uSize = 128; // Approx fixed length data
foreach(KeyValuePair<string, ProtectedString> kvpStr in m_listStrings)
{
uSize += (ulong)kvpStr.Key.Length;
uSize += (ulong)kvpStr.Value.Length;
}
foreach(KeyValuePair<string, ProtectedBinary> kvpBin in m_listBinaries)
{
uSize += (ulong)kvpBin.Key.Length;
uSize += kvpBin.Value.Length;
}
uSize += (ulong)m_listAutoType.DefaultSequence.Length;
foreach(AutoTypeAssociation a in m_listAutoType.Associations)
{
uSize += (ulong)a.WindowName.Length;
uSize += (ulong)a.Sequence.Length;
}
foreach(PwEntry peHistory in m_listHistory)
uSize += peHistory.GetSize();
uSize += (ulong)m_strOverrideUrl.Length;
foreach(string strTag in m_vTags)
uSize += (ulong)strTag.Length;
return uSize;
}
public bool HasTag(string strTag)
{
if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
for(int i = 0; i < m_vTags.Count; ++i)
{
if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return true;
}
return false;
}
public bool AddTag(string strTag)
{
if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
for(int i = 0; i < m_vTags.Count; ++i)
{
if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp)) return false;
}
m_vTags.Add(strTag);
return true;
}
public bool RemoveTag(string strTag)
{
if(string.IsNullOrEmpty(strTag)) { Debug.Assert(false); return false; }
for(int i = 0; i < m_vTags.Count; ++i)
{
if(m_vTags[i].Equals(strTag, StrUtil.CaseIgnoreCmp))
{
m_vTags.RemoveAt(i);
return true;
}
}
return false;
}
public bool IsContainedIn(PwGroup pgContainer)
{
PwGroup pgCur = m_pParentGroup;
while(pgCur != null)
{
if(pgCur == pgContainer) return true;
pgCur = pgCur.ParentGroup;
}
return false;
}
public void SetUuid(PwUuid pwNewUuid, bool bAlsoChangeHistoryUuids)
{
this.Uuid = pwNewUuid;
if(bAlsoChangeHistoryUuids)
{
foreach(PwEntry peHist in m_listHistory)
{
peHist.Uuid = pwNewUuid;
}
}
}
}
public sealed class PwEntryComparer : IComparer<PwEntry>
{
private string m_strFieldName;
private bool m_bCaseInsensitive;
private bool m_bCompareNaturally;
public PwEntryComparer(string strFieldName, bool bCaseInsensitive,
bool bCompareNaturally)
{
if(strFieldName == null) throw new ArgumentNullException("strFieldName");
m_strFieldName = strFieldName;
m_bCaseInsensitive = bCaseInsensitive;
m_bCompareNaturally = bCompareNaturally;
}
public int Compare(PwEntry a, PwEntry b)
{
string strA = a.Strings.ReadSafe(m_strFieldName);
string strB = b.Strings.ReadSafe(m_strFieldName);
if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB);
return string.Compare(strA, strB, m_bCaseInsensitive);
}
}
}

View File

@ -0,0 +1,207 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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;
namespace KeePassLib
{
/// <summary>
/// Compression algorithm specifiers.
/// </summary>
public enum PwCompressionAlgorithm
{
/// <summary>
/// No compression.
/// </summary>
None = 0,
/// <summary>
/// GZip compression.
/// </summary>
GZip = 1,
/// <summary>
/// Virtual field: currently known number of algorithms. Should not be used
/// by plugins or libraries -- it's used internally only.
/// </summary>
Count = 2
}
/// <summary>
/// Tree traversal methods.
/// </summary>
public enum TraversalMethod
{
/// <summary>
/// Don't traverse the tree.
/// </summary>
None = 0,
/// <summary>
/// Traverse the tree in pre-order mode, i.e. first visit all items
/// in the current node, then visit all subnodes.
/// </summary>
PreOrder = 1
}
/// <summary>
/// Methods for merging password databases/entries.
/// </summary>
public enum PwMergeMethod
{
None = 0,
OverwriteExisting = 1,
KeepExisting = 2,
OverwriteIfNewer = 3,
CreateNewUuids = 4,
Synchronize = 5
}
/// <summary>
/// Icon identifiers for groups and password entries.
/// </summary>
public enum PwIcon
{
Key = 0,
World,
Warning,
NetworkServer,
MarkedDirectory,
UserCommunication,
Parts,
Notepad,
WorldSocket,
Identity,
PaperReady,
Digicam,
IRCommunication,
MultiKeys,
Energy,
Scanner,
WorldStar,
CDRom,
Monitor,
EMail,
Configuration,
ClipboardReady,
PaperNew,
Screen,
EnergyCareful,
EMailBox,
Disk,
Drive,
PaperQ,
TerminalEncrypted,
Console,
Printer,
ProgramIcons,
Run,
Settings,
WorldComputer,
Archive,
Homebanking,
DriveWindows,
Clock,
EMailSearch,
PaperFlag,
Memory,
TrashBin,
Note,
Expired,
Info,
Package,
Folder,
FolderOpen,
FolderPackage,
LockOpen,
PaperLocked,
Checked,
Pen,
Thumbnail,
Book,
List,
UserKey,
Tool,
Home,
Star,
Tux,
Feather,
Apple,
Wiki,
Money,
Certificate,
BlackBerry,
/// <summary>
/// Virtual identifier -- represents the number of icons.
/// </summary>
Count
}
public enum ProxyServerType
{
None = 0,
System = 1,
Manual = 2
}
/// <summary>
/// Comparison modes for in-memory protected objects.
/// </summary>
public enum MemProtCmpMode
{
/// <summary>
/// Ignore the in-memory protection states.
/// </summary>
None = 0,
/// <summary>
/// Ignore the in-memory protection states of standard
/// objects; do compare in-memory protection states of
/// custom objects.
/// </summary>
CustomOnly,
/// <summary>
/// Compare in-memory protection states.
/// </summary>
Full
}
[Flags]
public enum PwCompareOptions
{
None = 0x0,
/// <summary>
/// Empty standard string fields are considered to be the
/// same as non-existing standard string fields.
/// This doesn't affect custom string comparisons.
/// </summary>
NullEmptyEquivStd = 0x1,
IgnoreParentGroup = 0x2,
IgnoreLastAccess = 0x4,
IgnoreLastMod = 0x8,
IgnoreHistory = 0x10,
IgnoreLastBackup = 0x20,
IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,179 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Xml;
using System.Diagnostics;
using KeePassLib.Utility;
namespace KeePassLib
{
// [ImmutableObject(true)]
/// <summary>
/// Represents an UUID of a password entry or group. Once created, <c>PwUuid</c>
/// objects aren't modifyable anymore (immutable).
/// </summary>
public sealed class PwUuid
{
/// <summary>
/// Standard size in bytes of a UUID.
/// </summary>
public const uint UuidSize = 16;
/// <summary>
/// Zero UUID (all bytes are zero).
/// </summary>
public static readonly PwUuid Zero = new PwUuid();
private byte[] m_pbUuid = new byte[UuidSize];
/// <summary>
/// Get the 16 UUID bytes.
/// </summary>
public byte[] UuidBytes
{
get { return m_pbUuid; }
}
/// <summary>
/// Construct a new UUID object. Its value is initialized to zero.
/// </summary>
private PwUuid()
{
SetZero();
}
/// <summary>
/// Construct a new UUID object.
/// </summary>
/// <param name="bCreateNew">If this parameter is <c>true</c>, a new
/// UUID is generated. If it is <c>false</c>, the UUID is initialized
/// to zero.</param>
public PwUuid(bool bCreateNew)
{
if(bCreateNew) CreateNew();
else SetZero();
}
/// <summary>
/// Construct a new UUID object.
/// </summary>
/// <param name="uuidBytes">Initial value of the <c>PwUuid</c> object.</param>
public PwUuid(byte[] uuidBytes)
{
SetValue(uuidBytes);
}
/// <summary>
/// Create a new, random UUID.
/// </summary>
/// <returns>Returns <c>true</c> if a random UUID has been generated,
/// otherwise it returns <c>false</c>.</returns>
private void CreateNew()
{
while(true)
{
m_pbUuid = Guid.NewGuid().ToByteArray();
if((m_pbUuid == null) || (m_pbUuid.Length != UuidSize))
throw new InvalidOperationException();
// Zero is a reserved value -- do not generate Zero
if(this.EqualsValue(PwUuid.Zero) == false)
break;
}
}
/// <summary>
/// Compare this UUID with another.
/// </summary>
/// <param name="uuid">Second UUID object.</param>
/// <returns>Returns <c>true</c> if both PwUuid object contain the same
/// value, otherwise <c>false</c> is returned.</returns>
public bool EqualsValue(PwUuid uuid)
{
Debug.Assert(uuid != null);
if(uuid == null) throw new ArgumentNullException("uuid");
for(int i = 0; i < UuidSize; ++i)
{
if(m_pbUuid[i] != uuid.m_pbUuid[i]) return false;
}
return true;
}
/// <summary>
/// Convert the UUID to its string representation.
/// </summary>
/// <returns>String containing the UUID value.</returns>
public string ToHexString()
{
return MemUtil.ByteArrayToHexString(m_pbUuid);
}
/// <summary>
/// Set the UUID value. The input parameter will not be modified.
/// </summary>
/// <param name="uuidBytes">UUID bytes. The byte array must contain
/// exactly <c>UUIDSize</c> bytes, otherwise the function will fail.</param>
private void SetValue(byte[] uuidBytes)
{
Debug.Assert((uuidBytes != null) && (uuidBytes.Length == UuidSize));
if(uuidBytes == null) throw new ArgumentNullException("uuidBytes");
if(uuidBytes.Length != UuidSize) throw new ArgumentException();
Array.Copy(uuidBytes, m_pbUuid, (int)UuidSize);
}
/// <summary>
/// Set the UUID value to zero.
/// </summary>
private void SetZero()
{
Array.Clear(m_pbUuid, 0, (int)UuidSize);
}
}
public sealed class PwUuidComparable : IComparable<PwUuidComparable>
{
private byte[] m_pbUuid = new byte[PwUuid.UuidSize];
public PwUuidComparable(PwUuid pwUuid)
{
if(pwUuid == null) throw new ArgumentNullException("pwUuid");
Array.Copy(pwUuid.UuidBytes, m_pbUuid, (int)PwUuid.UuidSize);
}
public int CompareTo(PwUuidComparable other)
{
if(other == null) throw new ArgumentNullException("other");
for(int i = 0; i < (int)PwUuid.UuidSize; ++i)
{
if(m_pbUuid[i] < other.m_pbUuid[i]) return -1;
if(m_pbUuid[i] > other.m_pbUuid[i]) return 1;
}
return 0;
}
}
}

View File

@ -0,0 +1,44 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.axml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable/
icon.png
layout/
main.axml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called "R"
(this is an Android convention) that contains the tokens for each one of the resources
included. For example, for the above Resources layout, this is what the R class would expose:
public class R {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
to reference the layout/main.axml file, or R.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

View File

@ -0,0 +1,390 @@
// This is a generated file!
// Do not edit manually, changes will be overwritten.
using System;
using System.Collections.Generic;
namespace KeePassLib.Resources
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
public static class KLRes
{
private static string TryGetEx(Dictionary<string, string> dictNew,
string strName, string strDefault)
{
string strTemp;
if(dictNew.TryGetValue(strName, out strTemp))
return strTemp;
return strDefault;
}
public static void SetTranslatedStrings(Dictionary<string, string> dictNew)
{
if(dictNew == null) throw new ArgumentNullException("dictNew");
m_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed);
m_strEncAlgorithmAes = TryGetEx(dictNew, "EncAlgorithmAes", m_strEncAlgorithmAes);
m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard);
m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError);
m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText);
m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted);
m_strFileHeaderEndEarly = TryGetEx(dictNew, "FileHeaderEndEarly", m_strFileHeaderEndEarly);
m_strFileLoadFailed = TryGetEx(dictNew, "FileLoadFailed", m_strFileLoadFailed);
m_strFileLockedWrite = TryGetEx(dictNew, "FileLockedWrite", m_strFileLockedWrite);
m_strFileNewVerReq = TryGetEx(dictNew, "FileNewVerReq", m_strFileNewVerReq);
m_strFileSaveCorruptionWarning = TryGetEx(dictNew, "FileSaveCorruptionWarning", m_strFileSaveCorruptionWarning);
m_strFileSaveFailed = TryGetEx(dictNew, "FileSaveFailed", m_strFileSaveFailed);
m_strFileSigInvalid = TryGetEx(dictNew, "FileSigInvalid", m_strFileSigInvalid);
m_strFileUnknownCipher = TryGetEx(dictNew, "FileUnknownCipher", m_strFileUnknownCipher);
m_strFileUnknownCompression = TryGetEx(dictNew, "FileUnknownCompression", m_strFileUnknownCompression);
m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported);
m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed);
m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp);
m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey);
m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint);
m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding);
m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint);
m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid);
m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat);
m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs);
m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId);
m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError);
}
private static readonly string[] m_vKeyNames = {
"CryptoStreamFailed",
"EncAlgorithmAes",
"ErrorInClipboard",
"FatalError",
"FatalErrorText",
"FileCorrupted",
"FileHeaderEndEarly",
"FileLoadFailed",
"FileLockedWrite",
"FileNewVerReq",
"FileSaveCorruptionWarning",
"FileSaveFailed",
"FileSigInvalid",
"FileUnknownCipher",
"FileUnknownCompression",
"FileVersionUnsupported",
"FinalKeyCreationFailed",
"FrameworkNotImplExcp",
"InvalidCompositeKey",
"InvalidCompositeKeyHint",
"InvalidDataWhileDecoding",
"KeePass1xHint",
"MasterSeedLengthInvalid",
"OldFormat",
"TryAgainSecs",
"UnknownHeaderId",
"UserAccountKeyError"
};
public static string[] GetKeyNames()
{
return m_vKeyNames;
}
private static string m_strCryptoStreamFailed =
@"Failed to initialize encryption/decryption stream!";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to initialize encryption/decryption stream!'.
/// </summary>
public static string CryptoStreamFailed
{
get { return m_strCryptoStreamFailed; }
}
private static string m_strEncAlgorithmAes =
@"AES/Rijndael (256-Bit Key)";
/// <summary>
/// Look up a localized string similar to
/// 'AES/Rijndael (256-Bit Key)'.
/// </summary>
public static string EncAlgorithmAes
{
get { return m_strEncAlgorithmAes; }
}
private static string m_strErrorInClipboard =
@"An extended error report has been copied to the clipboard.";
/// <summary>
/// Look up a localized string similar to
/// 'An extended error report has been copied to the clipboard.'.
/// </summary>
public static string ErrorInClipboard
{
get { return m_strErrorInClipboard; }
}
private static string m_strFatalError =
@"Fatal Error";
/// <summary>
/// Look up a localized string similar to
/// 'Fatal Error'.
/// </summary>
public static string FatalError
{
get { return m_strFatalError; }
}
private static string m_strFatalErrorText =
@"A fatal error has occurred!";
/// <summary>
/// Look up a localized string similar to
/// 'A fatal error has occurred!'.
/// </summary>
public static string FatalErrorText
{
get { return m_strFatalErrorText; }
}
private static string m_strFileCorrupted =
@"The file is corrupted.";
/// <summary>
/// Look up a localized string similar to
/// 'The file is corrupted.'.
/// </summary>
public static string FileCorrupted
{
get { return m_strFileCorrupted; }
}
private static string m_strFileHeaderEndEarly =
@"The file header is corrupted! Some header data was declared but is not present.";
/// <summary>
/// Look up a localized string similar to
/// 'The file header is corrupted! Some header data was declared but is not present.'.
/// </summary>
public static string FileHeaderEndEarly
{
get { return m_strFileHeaderEndEarly; }
}
private static string m_strFileLoadFailed =
@"Failed to load the specified file!";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to load the specified file!'.
/// </summary>
public static string FileLoadFailed
{
get { return m_strFileLoadFailed; }
}
private static string m_strFileLockedWrite =
@"The file is locked, because the following user is currently writing to it:";
/// <summary>
/// Look up a localized string similar to
/// 'The file is locked, because the following user is currently writing to it:'.
/// </summary>
public static string FileLockedWrite
{
get { return m_strFileLockedWrite; }
}
private static string m_strFileNewVerReq =
@"A newer KeePass version is required to open this file.";
/// <summary>
/// Look up a localized string similar to
/// 'A newer KeePass version is required to open this file.'.
/// </summary>
public static string FileNewVerReq
{
get { return m_strFileNewVerReq; }
}
private static string m_strFileSaveCorruptionWarning =
@"The target file might be corrupted. Please try saving again. If that fails, save the database to a different location.";
/// <summary>
/// Look up a localized string similar to
/// 'The target file might be corrupted. Please try saving again. If that fails, save the database to a different location.'.
/// </summary>
public static string FileSaveCorruptionWarning
{
get { return m_strFileSaveCorruptionWarning; }
}
private static string m_strFileSaveFailed =
@"Failed to save the current database to the specified location!";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to save the current database to the specified location!'.
/// </summary>
public static string FileSaveFailed
{
get { return m_strFileSaveFailed; }
}
private static string m_strFileSigInvalid =
@"The file signature is invalid. Either the file isn't a KeePass database file at all or it is corrupted.";
/// <summary>
/// Look up a localized string similar to
/// 'The file signature is invalid. Either the file isn&#39;t a KeePass database file at all or it is corrupted.'.
/// </summary>
public static string FileSigInvalid
{
get { return m_strFileSigInvalid; }
}
private static string m_strFileUnknownCipher =
@"The file is encrypted using an unknown encryption algorithm!";
/// <summary>
/// Look up a localized string similar to
/// 'The file is encrypted using an unknown encryption algorithm!'.
/// </summary>
public static string FileUnknownCipher
{
get { return m_strFileUnknownCipher; }
}
private static string m_strFileUnknownCompression =
@"The file is compressed using an unknown compression algorithm!";
/// <summary>
/// Look up a localized string similar to
/// 'The file is compressed using an unknown compression algorithm!'.
/// </summary>
public static string FileUnknownCompression
{
get { return m_strFileUnknownCompression; }
}
private static string m_strFileVersionUnsupported =
@"The file version is unsupported.";
/// <summary>
/// Look up a localized string similar to
/// 'The file version is unsupported.'.
/// </summary>
public static string FileVersionUnsupported
{
get { return m_strFileVersionUnsupported; }
}
private static string m_strFinalKeyCreationFailed =
@"Failed to create the final encryption/decryption key!";
/// <summary>
/// Look up a localized string similar to
/// 'Failed to create the final encryption/decryption key!'.
/// </summary>
public static string FinalKeyCreationFailed
{
get { return m_strFinalKeyCreationFailed; }
}
private static string m_strFrameworkNotImplExcp =
@"The .NET framework/runtime under which KeePass is currently running does not support this operation.";
/// <summary>
/// Look up a localized string similar to
/// 'The .NET framework/runtime under which KeePass is currently running does not support this operation.'.
/// </summary>
public static string FrameworkNotImplExcp
{
get { return m_strFrameworkNotImplExcp; }
}
private static string m_strInvalidCompositeKey =
@"The composite key is invalid!";
/// <summary>
/// Look up a localized string similar to
/// 'The composite key is invalid!'.
/// </summary>
public static string InvalidCompositeKey
{
get { return m_strInvalidCompositeKey; }
}
private static string m_strInvalidCompositeKeyHint =
@"Make sure the composite key is correct and try again.";
/// <summary>
/// Look up a localized string similar to
/// 'Make sure the composite key is correct and try again.'.
/// </summary>
public static string InvalidCompositeKeyHint
{
get { return m_strInvalidCompositeKeyHint; }
}
private static string m_strInvalidDataWhileDecoding =
@"Found invalid data while decoding.";
/// <summary>
/// Look up a localized string similar to
/// 'Found invalid data while decoding.'.
/// </summary>
public static string InvalidDataWhileDecoding
{
get { return m_strInvalidDataWhileDecoding; }
}
private static string m_strKeePass1xHint =
@"In order to import KeePass 1.x KDB files, create a new 2.x database file and click 'File' -> 'Import' in the main menu. In the import dialog, choose 'KeePass KDB (1.x)' as file format.";
/// <summary>
/// Look up a localized string similar to
/// 'In order to import KeePass 1.x KDB files, create a new 2.x database file and click &#39;File&#39; -&gt; &#39;Import&#39; in the main menu. In the import dialog, choose &#39;KeePass KDB (1.x)&#39; as file format.'.
/// </summary>
public static string KeePass1xHint
{
get { return m_strKeePass1xHint; }
}
private static string m_strMasterSeedLengthInvalid =
@"The length of the master key seed is invalid!";
/// <summary>
/// Look up a localized string similar to
/// 'The length of the master key seed is invalid!'.
/// </summary>
public static string MasterSeedLengthInvalid
{
get { return m_strMasterSeedLengthInvalid; }
}
private static string m_strOldFormat =
@"The selected file appears to be an old format";
/// <summary>
/// Look up a localized string similar to
/// 'The selected file appears to be an old format'.
/// </summary>
public static string OldFormat
{
get { return m_strOldFormat; }
}
private static string m_strTryAgainSecs =
@"Please try it again in a few seconds.";
/// <summary>
/// Look up a localized string similar to
/// 'Please try it again in a few seconds.'.
/// </summary>
public static string TryAgainSecs
{
get { return m_strTryAgainSecs; }
}
private static string m_strUnknownHeaderId =
@"Unknown header ID!";
/// <summary>
/// Look up a localized string similar to
/// 'Unknown header ID!'.
/// </summary>
public static string UnknownHeaderId
{
get { return m_strUnknownHeaderId; }
}
private static string m_strUserAccountKeyError =
@"The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored.";
/// <summary>
/// Look up a localized string similar to
/// 'The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored.'.
/// </summary>
public static string UserAccountKeyError
{
get { return m_strUserAccountKeyError; }
}
}
}

View File

@ -0,0 +1,52 @@
// This is a generated file!
// Do not edit manually, changes will be overwritten.
using System;
using System.Collections.Generic;
namespace KeePassLib.Resources
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
public static class KSRes
{
private static string TryGetEx(Dictionary<string, string> dictNew,
string strName, string strDefault)
{
string strTemp;
if(dictNew.TryGetValue(strName, out strTemp))
return strTemp;
return strDefault;
}
public static void SetTranslatedStrings(Dictionary<string, string> dictNew)
{
if(dictNew == null) throw new ArgumentNullException("dictNew");
m_strTest = TryGetEx(dictNew, "Test", m_strTest);
}
private static readonly string[] m_vKeyNames = {
"Test"
};
public static string[] GetKeyNames()
{
return m_vKeyNames;
}
private static string m_strTest =
@"Test";
/// <summary>
/// Look up a localized string similar to
/// 'Test'.
/// </summary>
public static string Test
{
get { return m_strTest; }
}
}
}

View File

@ -0,0 +1,37 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion:4.0.30319.296
//
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn
// der Code erneut generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace KeePassLib2Android
{
public partial class Resource
{
public partial class Attribute
{
private Attribute()
{
}
}
public partial class String
{
// aapt resource value: 0x7f020000
public const int library_name = 2130837504;
private String()
{
}
}
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="library_name">KeePassLib2Android</string>
</resources>

View File

@ -0,0 +1,242 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Security.Cryptography;
using System.Diagnostics;
using KeePassLib.Cryptography;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Security
{
/// <summary>
/// Represents a protected binary, i.e. a byte array that is encrypted
/// in memory. A <c>ProtectedBinary</c> object is immutable and
/// thread-safe.
/// </summary>
public sealed class ProtectedBinary : IEquatable<ProtectedBinary>
{
private const int PmBlockSize = 16;
// In-memory protection is supported only on Windows 2000 SP3 and
// higher.
private static bool m_bProtectionSupported;
private byte[] m_pbData; // Never null
// The real length of the data. This value can be different than
// m_pbData.Length, as the length of m_pbData always is a multiple
// of PmBlockSize (required for fast in-memory protection).
private uint m_uDataLen;
private bool m_bProtected;
private object m_objSync = new object();
/// <summary>
/// A flag specifying whether the <c>ProtectedBinary</c> object has
/// turned on in-memory protection or not.
/// </summary>
public bool IsProtected
{
get { return m_bProtected; }
}
/// <summary>
/// Length of the stored data.
/// </summary>
public uint Length
{
get { return m_uDataLen; }
}
static ProtectedBinary()
{
try // Test whether ProtectedMemory is supported
{
byte[] pbDummy = new byte[PmBlockSize * 2];
ProtectedMemory.Protect(pbDummy, MemoryProtectionScope.SameProcess);
m_bProtectionSupported = true;
}
catch(Exception) // Windows 98 / ME
{
m_bProtectionSupported = false;
}
}
/// <summary>
/// Construct a new, empty protected binary data object. Protection
/// is disabled.
/// </summary>
public ProtectedBinary()
{
Init(false, new byte[0]);
}
/// <summary>
/// Construct a new protected binary data object.
/// </summary>
/// <param name="bEnableProtection">If this paremeter is <c>true</c>,
/// the data will be encrypted in memory. If it is <c>false</c>, the
/// data is stored in plain-text in the process memory.</param>
/// <param name="pbData">Value of the protected object.
/// The input parameter is not modified and
/// <c>ProtectedBinary</c> doesn't take ownership of the data,
/// i.e. the caller is responsible for clearing it.</param>
public ProtectedBinary(bool bEnableProtection, byte[] pbData)
{
Init(bEnableProtection, pbData);
}
/// <summary>
/// Construct a new protected binary data object. Copy the data from
/// a <c>XorredBuffer</c> object.
/// </summary>
/// <param name="bEnableProtection">Enable protection or not.</param>
/// <param name="xbProtected"><c>XorredBuffer</c> object used to
/// initialize the <c>ProtectedBinary</c> object.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected)
{
Debug.Assert(xbProtected != null); if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
}
private void Init(bool bEnableProtection, byte[] pbData)
{
if(pbData == null) throw new ArgumentNullException("pbData");
m_bProtected = bEnableProtection;
m_uDataLen = (uint)pbData.Length;
int nBlocks = (int)m_uDataLen / PmBlockSize;
if((nBlocks * PmBlockSize) < (int)m_uDataLen) ++nBlocks;
Debug.Assert((nBlocks * PmBlockSize) >= (int)m_uDataLen);
m_pbData = new byte[nBlocks * PmBlockSize];
Array.Copy(pbData, m_pbData, (int)m_uDataLen);
// Data size must be > 0, otherwise 'Protect' throws
if(m_bProtected && m_bProtectionSupported && (m_uDataLen > 0))
ProtectedMemory.Protect(m_pbData, MemoryProtectionScope.SameProcess);
}
/// <summary>
/// Get a copy of the protected data as a byte array.
/// Please note that the returned byte array is not protected and
/// can therefore been read by any other application.
/// Make sure that your clear it properly after usage.
/// </summary>
/// <returns>Unprotected byte array. This is always a copy of the internal
/// protected data and can therefore be cleared safely.</returns>
public byte[] ReadData()
{
if(m_uDataLen == 0) return new byte[0];
byte[] pbReturn = new byte[m_uDataLen];
if(m_bProtected && m_bProtectionSupported)
{
lock(m_objSync)
{
ProtectedMemory.Unprotect(m_pbData, MemoryProtectionScope.SameProcess);
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;
}
/// <summary>
/// Read the protected data and return it protected with a sequence
/// of bytes generated by a random stream.
/// </summary>
/// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected data.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public byte[] ReadXorredData(CryptoRandomStream crsRandomSource)
{
Debug.Assert(crsRandomSource != null);
if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
byte[] pbData = ReadData();
uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen);
for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i];
return pbData;
}
public override int GetHashCode()
{
int h = (m_bProtected ? 0x7B11D289 : 0);
byte[] pb = ReadData();
unchecked
{
for(int i = 0; i < pb.Length; ++i)
h = (h << 3) + h + (int)pb[i];
}
MemUtil.ZeroByteArray(pb);
return h;
}
public override bool Equals(object obj)
{
return Equals(obj as ProtectedBinary);
}
public bool Equals(ProtectedBinary other)
{
if(other == null) return false; // No assert
if(m_bProtected != other.m_bProtected) return false;
if(m_uDataLen != other.m_uDataLen) return false;
byte[] pbL = ReadData();
byte[] pbR = other.ReadData();
bool bEq = MemUtil.ArraysEqual(pbL, pbR);
MemUtil.ZeroByteArray(pbL);
MemUtil.ZeroByteArray(pbR);
#if DEBUG
if(bEq) { Debug.Assert(GetHashCode() == other.GetHashCode()); }
#endif
return bEq;
}
}
}

View File

@ -0,0 +1,253 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Diagnostics;
using KeePassLib.Cryptography;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;
#endif
// SecureString objects are limited to 65536 characters, don't use
namespace KeePassLib.Security
{
/// <summary>
/// Represents an in-memory encrypted string.
/// <c>ProtectedString</c> objects are immutable and thread-safe.
/// </summary>
#if (DEBUG && !KeePassLibSD)
[DebuggerDisplay(@"{ReadString()}")]
#endif
public sealed class ProtectedString
{
// Exactly one of the following will be non-null
private ProtectedBinary m_pbUtf8 = null;
private string m_strPlainText = null;
private bool m_bIsProtected;
private static ProtectedString m_psEmpty = new ProtectedString();
public static ProtectedString Empty
{
get { return m_psEmpty; }
}
/// <summary>
/// A flag specifying whether the <c>ProtectedString</c> object
/// has turned on in-memory protection or not.
/// </summary>
public bool IsProtected
{
get { return m_bIsProtected; }
}
public bool IsEmpty
{
get
{
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null) return (pBin.Length == 0);
Debug.Assert(m_strPlainText != null);
return (m_strPlainText.Length == 0);
}
}
private int m_nCachedLength = -1;
public int Length
{
get
{
if(m_nCachedLength >= 0) return m_nCachedLength;
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null)
{
byte[] pbPlain = pBin.ReadData();
m_nCachedLength = StrUtil.Utf8.GetCharCount(pbPlain);
MemUtil.ZeroByteArray(pbPlain);
}
else
{
Debug.Assert(m_strPlainText != null);
m_nCachedLength = m_strPlainText.Length;
}
return m_nCachedLength;
}
}
/// <summary>
/// Construct a new protected string object. Protection is
/// disabled.
/// </summary>
public ProtectedString()
{
Init(false, string.Empty);
}
/// <summary>
/// Construct a new protected string. The string is initialized
/// to the value supplied in the parameters.
/// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
/// the string will be protected in-memory (encrypted). If it
/// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="strValue">The initial string value. This
/// parameter won't be modified.</param>
public ProtectedString(bool bEnableProtection, string strValue)
{
Init(bEnableProtection, strValue);
}
/// <summary>
/// Construct a new protected string. The string is initialized
/// to the value supplied in the parameters (UTF-8 encoded string).
/// </summary>
/// <param name="bEnableProtection">If this parameter is <c>true</c>,
/// the string will be protected in-memory (encrypted). If it
/// is <c>false</c>, the string will be stored as plain-text.</param>
/// <param name="vUtf8Value">The initial string value, encoded as
/// UTF-8 byte array. This parameter won't be modified; the caller
/// is responsible for clearing it.</param>
public ProtectedString(bool bEnableProtection, byte[] vUtf8Value)
{
Init(bEnableProtection, vUtf8Value);
}
/// <summary>
/// Construct a new protected string. The string is initialized
/// to the value passed in the <c>XorredBuffer</c> object.
/// </summary>
/// <param name="bEnableProtection">Enable protection or not.</param>
/// <param name="xbProtected"><c>XorredBuffer</c> object containing the
/// string in UTF-8 representation. The UTF-8 string must not
/// be <c>null</c>-terminated.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected)
{
if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb);
MemUtil.ZeroByteArray(pb);
}
private void Init(bool bEnableProtection, string str)
{
if(str == null) throw new ArgumentNullException("str");
m_bIsProtected = bEnableProtection;
// The string already is in memory and immutable,
// protection would be useless
m_strPlainText = str;
}
private void Init(bool bEnableProtection, byte[] pbUtf8)
{
if(pbUtf8 == null) throw new ArgumentNullException("pbUtf8");
m_bIsProtected = bEnableProtection;
if(bEnableProtection)
m_pbUtf8 = new ProtectedBinary(true, pbUtf8);
else
m_strPlainText = StrUtil.Utf8.GetString(pbUtf8, 0, pbUtf8.Length);
}
/// <summary>
/// Convert the protected string to a normal string object.
/// Be careful with this function, the returned string object
/// isn't protected anymore and stored in plain-text in the
/// process memory.
/// </summary>
/// <returns>Plain-text string. Is never <c>null</c>.</returns>
public string ReadString()
{
if(m_strPlainText != null) return m_strPlainText;
byte[] pb = ReadUtf8();
string str = ((pb.Length == 0) ? string.Empty :
StrUtil.Utf8.GetString(pb, 0, pb.Length));
// No need to clear pb
// As the text is now visible in process memory anyway,
// there's no need to protect it anymore
m_strPlainText = str;
m_pbUtf8 = null; // Thread-safe order
return str;
}
/// <summary>
/// Read out the string and return a byte array that contains the
/// string encoded using UTF-8. The returned string is not protected
/// anymore!
/// </summary>
/// <returns>Plain-text UTF-8 byte array.</returns>
public byte[] ReadUtf8()
{
ProtectedBinary pBin = m_pbUtf8; // Local ref for thread-safety
if(pBin != null) return pBin.ReadData();
return StrUtil.Utf8.GetBytes(m_strPlainText);
}
/// <summary>
/// Read the protected string and return it protected with a sequence
/// of bytes generated by a random stream.
/// </summary>
/// <param name="crsRandomSource">Random number source.</param>
/// <returns>Protected string.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if the input
/// parameter is <c>null</c>.</exception>
public byte[] ReadXorredString(CryptoRandomStream crsRandomSource)
{
Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource");
byte[] pbData = ReadUtf8();
uint uLen = (uint)pbData.Length;
byte[] randomPad = crsRandomSource.GetRandomBytes(uLen);
Debug.Assert(randomPad.Length == uLen);
for(uint i = 0; i < uLen; ++i)
pbData[i] ^= randomPad[i];
return pbData;
}
public ProtectedString WithProtection(bool bProtect)
{
if(bProtect == m_bIsProtected) return this;
byte[] pb = ReadUtf8();
ProtectedString ps = new ProtectedString(bProtect, pb);
MemUtil.ZeroByteArray(pb);
return ps;
}
}
}

View File

@ -0,0 +1,116 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Diagnostics;
namespace KeePassLib.Security
{
/// <summary>
/// Represents an object that is encrypted using a XOR pad until
/// it is read. <c>XorredBuffer</c> objects are immutable and
/// thread-safe.
/// </summary>
public sealed class XorredBuffer
{
private byte[] m_pbData; // Never null
private byte[] m_pbXorPad; // Always valid for m_pbData
/// <summary>
/// Length of the protected data in bytes.
/// </summary>
public uint Length
{
get { return (uint)m_pbData.Length; }
}
/// <summary>
/// Construct a new XOR-protected object using a protected byte array
/// and a XOR pad that decrypts the protected data. The
/// <paramref name="pbProtectedData" /> byte array must have the same size
/// as the <paramref name="pbXorPad" /> byte array.
/// The <c>XorredBuffer</c> object takes ownership of the two byte
/// arrays, i.e. the caller must not use or modify them afterwards.
/// </summary>
/// <param name="pbProtectedData">Protected data (XOR pad applied).</param>
/// <param name="pbXorPad">XOR pad that can be used to decrypt the
/// <paramref name="pbProtectedData" /> parameter.</param>
/// <exception cref="System.ArgumentNullException">Thrown if one of the input
/// parameters is <c>null</c>.</exception>
/// <exception cref="System.ArgumentException">Thrown if the byte arrays are
/// of different size.</exception>
public XorredBuffer(byte[] pbProtectedData, byte[] pbXorPad)
{
if(pbProtectedData == null) { Debug.Assert(false); throw new ArgumentNullException("pbProtectedData"); }
if(pbXorPad == null) { Debug.Assert(false); throw new ArgumentNullException("pbXorPad"); }
Debug.Assert(pbProtectedData.Length == pbXorPad.Length);
if(pbProtectedData.Length != pbXorPad.Length) throw new ArgumentException();
m_pbData = pbProtectedData;
m_pbXorPad = pbXorPad;
}
/// <summary>
/// Get a copy of the plain-text. The caller is responsible
/// for clearing the byte array safely after using it.
/// </summary>
/// <returns>Unprotected plain-text byte array.</returns>
public byte[] ReadPlainText()
{
byte[] pbPlain = new byte[m_pbData.Length];
for(int i = 0; i < pbPlain.Length; ++i)
pbPlain[i] = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
return pbPlain;
}
/* public bool EqualsValue(XorredBuffer xb)
{
if(xb == null) { Debug.Assert(false); throw new ArgumentNullException("xb"); }
if(xb.m_pbData.Length != m_pbData.Length) return false;
for(int i = 0; i < m_pbData.Length; ++i)
{
byte bt1 = (byte)(m_pbData[i] ^ m_pbXorPad[i]);
byte bt2 = (byte)(xb.m_pbData[i] ^ xb.m_pbXorPad[i]);
if(bt1 != bt2) return false;
}
return true;
}
public bool EqualsValue(byte[] pb)
{
if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); }
if(pb.Length != m_pbData.Length) return false;
for(int i = 0; i < m_pbData.Length; ++i)
{
if((byte)(m_pbData[i] ^ m_pbXorPad[i]) != pb[i]) return false;
}
return true;
} */
}
}

View File

@ -0,0 +1,90 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public sealed class BinaryReaderEx
{
private Stream m_s;
private Encoding m_enc;
private string m_strReadExcp;
public string ReadExceptionText
{
get { return m_strReadExcp; }
set { m_strReadExcp = value; }
}
private Stream m_sCopyTo = null;
/// <summary>
/// If this property is set to a non-null stream, all data that
/// is read from the input stream is automatically written to
/// the copy stream (before returning the read data).
/// </summary>
public Stream CopyDataTo
{
get { return m_sCopyTo; }
set { m_sCopyTo = value; }
}
public BinaryReaderEx(Stream input, Encoding encoding,
string strReadExceptionText)
{
if(input == null) throw new ArgumentNullException("input");
m_s = input;
m_enc = encoding;
m_strReadExcp = strReadExceptionText;
}
public byte[] ReadBytes(int nCount)
{
try
{
byte[] pb = MemUtil.Read(m_s, nCount);
if((pb == null) || (pb.Length != nCount))
{
if(m_strReadExcp != null) throw new IOException(m_strReadExcp);
else throw new EndOfStreamException();
}
if(m_sCopyTo != null) m_sCopyTo.Write(pb, 0, pb.Length);
return pb;
}
catch(Exception)
{
if(m_strReadExcp != null) throw new IOException(m_strReadExcp);
else throw;
}
}
public byte ReadByte()
{
byte[] pb = ReadBytes(1);
return pb[0];
}
}
}

View File

@ -0,0 +1,260 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Threading;
using System.Diagnostics;
using KeePassLib.Cryptography;
using KeePassLib.Resources;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public sealed class FileLockException : Exception
{
private readonly string m_strMsg;
public override string Message
{
get { return m_strMsg; }
}
public FileLockException(string strBaseFile, string strUser)
{
StringBuilder sb = new StringBuilder();
if(!string.IsNullOrEmpty(strBaseFile))
{
sb.Append(strBaseFile);
sb.Append(MessageService.NewParagraph);
}
sb.Append(KLRes.FileLockedWrite);
sb.Append(MessageService.NewLine);
if(!string.IsNullOrEmpty(strUser)) sb.Append(strUser);
else sb.Append("?");
sb.Append(MessageService.NewParagraph);
sb.Append(KLRes.TryAgainSecs);
m_strMsg = sb.ToString();
}
}
public sealed class FileLock : IDisposable
{
private const string LockFileExt = ".lock";
private const string LockFileHeader = "KeePass Lock File";
private IOConnectionInfo m_iocLockFile;
private sealed class LockFileInfo
{
public readonly string ID;
public readonly DateTime Time;
public readonly string UserName;
public readonly string Machine;
public readonly string Domain;
private LockFileInfo(string strID, string strTime, string strUserName,
string strMachine, string strDomain)
{
this.ID = (strID ?? string.Empty).Trim();
DateTime dt;
if(TimeUtil.TryDeserializeUtc(strTime.Trim(), out dt))
this.Time = dt;
else
{
Debug.Assert(false);
this.Time = DateTime.UtcNow;
}
this.UserName = (strUserName ?? string.Empty).Trim();
this.Machine = (strMachine ?? string.Empty).Trim();
this.Domain = (strDomain ?? string.Empty).Trim();
if(this.Domain.Equals(this.Machine, StrUtil.CaseIgnoreCmp))
this.Domain = string.Empty;
}
public string GetOwner()
{
StringBuilder sb = new StringBuilder();
sb.Append((this.UserName.Length > 0) ? this.UserName : "?");
bool bMachine = (this.Machine.Length > 0);
bool bDomain = (this.Domain.Length > 0);
if(bMachine || bDomain)
{
sb.Append(" (");
sb.Append(this.Machine);
if(bMachine && bDomain) sb.Append(" @ ");
sb.Append(this.Domain);
sb.Append(")");
}
return sb.ToString();
}
public static LockFileInfo Load(IOConnectionInfo iocLockFile)
{
Stream s = null;
try
{
s = IOConnection.OpenRead(iocLockFile);
if(s == null) return null;
StreamReader sr = new StreamReader(s, StrUtil.Utf8);
string str = sr.ReadToEnd();
sr.Close();
if(str == null) { Debug.Assert(false); return null; }
str = StrUtil.NormalizeNewLines(str, false);
string[] v = str.Split('\n');
if((v == null) || (v.Length < 6)) { Debug.Assert(false); return null; }
if(!v[0].StartsWith(LockFileHeader)) { Debug.Assert(false); return null; }
return new LockFileInfo(v[1], v[2], v[3], v[4], v[5]);
}
catch(FileNotFoundException) { }
catch(Exception) { Debug.Assert(false); }
finally { if(s != null) s.Close(); }
return null;
}
// Throws on error
public static LockFileInfo Create(IOConnectionInfo iocLockFile)
{
LockFileInfo lfi;
Stream s = null;
try
{
byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16);
string strTime = TimeUtil.SerializeUtc(DateTime.Now);
#if !KeePassLibSD
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime,
Environment.UserName, Environment.MachineName,
Environment.UserDomainName);
#else
lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime,
string.Empty, string.Empty, string.Empty);
#endif
StringBuilder sb = new StringBuilder();
#if !KeePassLibSD
sb.AppendLine(LockFileHeader);
sb.AppendLine(lfi.ID);
sb.AppendLine(strTime);
sb.AppendLine(lfi.UserName);
sb.AppendLine(lfi.Machine);
sb.AppendLine(lfi.Domain);
#else
sb.Append(LockFileHeader + MessageService.NewLine);
sb.Append(lfi.ID + MessageService.NewLine);
sb.Append(strTime + MessageService.NewLine);
sb.Append(lfi.UserName + MessageService.NewLine);
sb.Append(lfi.Machine + MessageService.NewLine);
sb.Append(lfi.Domain + MessageService.NewLine);
#endif
byte[] pbFile = StrUtil.Utf8.GetBytes(sb.ToString());
s = IOConnection.OpenWrite(iocLockFile);
if(s == null) throw new IOException(iocLockFile.GetDisplayName());
s.Write(pbFile, 0, pbFile.Length);
}
finally { if(s != null) s.Close(); }
return lfi;
}
}
public FileLock(IOConnectionInfo iocBaseFile)
{
if(iocBaseFile == null) throw new ArgumentNullException("strBaseFile");
m_iocLockFile = iocBaseFile.CloneDeep();
m_iocLockFile.Path += LockFileExt;
LockFileInfo lfiEx = LockFileInfo.Load(m_iocLockFile);
if(lfiEx != null)
{
m_iocLockFile = null; // Otherwise Dispose deletes the existing one
throw new FileLockException(iocBaseFile.GetDisplayName(),
lfiEx.GetOwner());
}
LockFileInfo.Create(m_iocLockFile);
}
~FileLock()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool bDisposing)
{
if(m_iocLockFile == null) return;
bool bFileDeleted = false;
for(int r = 0; r < 5; ++r)
{
// if(!OwnLockFile()) { bFileDeleted = true; break; }
try
{
IOConnection.DeleteFile(m_iocLockFile);
bFileDeleted = true;
}
catch(Exception) { Debug.Assert(false); }
if(bFileDeleted) break;
if(bDisposing) Thread.Sleep(50);
}
if(bDisposing && !bFileDeleted)
IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception
m_iocLockFile = null;
}
// private bool OwnLockFile()
// {
// if(m_iocLockFile == null) { Debug.Assert(false); return false; }
// if(m_strLockID == null) { Debug.Assert(false); return false; }
// LockFileInfo lfi = LockFileInfo.Load(m_iocLockFile);
// if(lfi == null) return false;
// return m_strLockID.Equals(lfi.ID);
// }
}
}

View File

@ -0,0 +1,144 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Diagnostics;
#if !KeePassLibSD
using System.Security.AccessControl;
#endif
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public sealed class FileTransactionEx
{
private bool m_bTransacted;
private IOConnectionInfo m_iocBase;
private IOConnectionInfo m_iocTemp;
private bool m_bMadeUnhidden = false;
private const string StrTempSuffix = ".tmp";
public FileTransactionEx(IOConnectionInfo iocBaseFile)
{
Initialize(iocBaseFile, true);
}
public FileTransactionEx(IOConnectionInfo iocBaseFile, bool bTransacted)
{
Initialize(iocBaseFile, bTransacted);
}
private void Initialize(IOConnectionInfo iocBaseFile, bool bTransacted)
{
if(iocBaseFile == null) throw new ArgumentNullException("iocBaseFile");
m_bTransacted = bTransacted;
m_iocBase = iocBaseFile.CloneDeep();
if(m_bTransacted)
{
m_iocTemp = m_iocBase.CloneDeep();
m_iocTemp.Path += StrTempSuffix;
}
else m_iocTemp = m_iocBase;
}
public Stream OpenWrite()
{
if(!m_bTransacted) m_bMadeUnhidden = UrlUtil.UnhideFile(m_iocTemp.Path);
else // m_bTransacted
{
try { IOConnection.DeleteFile(m_iocTemp); }
catch(Exception) { }
}
return IOConnection.OpenWrite(m_iocTemp);
}
public void CommitWrite()
{
if(m_bTransacted) CommitWriteTransaction();
else // !m_bTransacted
{
if(m_bMadeUnhidden) UrlUtil.HideFile(m_iocTemp.Path, true); // Hide again
}
}
private void CommitWriteTransaction()
{
bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path);
#if !KeePassLibSD
FileSecurity bkSecurity = null;
bool bEfsEncrypted = false;
#endif
if(IOConnection.FileExists(m_iocBase))
{
#if !KeePassLibSD
if(m_iocBase.IsLocalFile())
{
try
{
FileAttributes faBase = File.GetAttributes(m_iocBase.Path);
bEfsEncrypted = ((long)(faBase & FileAttributes.Encrypted) != 0);
DateTime tCreation = File.GetCreationTime(m_iocBase.Path);
bkSecurity = File.GetAccessControl(m_iocBase.Path);
File.SetCreationTime(m_iocTemp.Path, tCreation);
}
catch(Exception) { Debug.Assert(false); }
}
#endif
IOConnection.DeleteFile(m_iocBase);
}
IOConnection.RenameFile(m_iocTemp, m_iocBase);
#if !KeePassLibSD
if(m_iocBase.IsLocalFile())
{
try
{
if(bEfsEncrypted)
{
try { File.Encrypt(m_iocBase.Path); }
catch(Exception) { Debug.Assert(false); }
}
if(bkSecurity != null)
File.SetAccessControl(m_iocBase.Path, bkSecurity);
}
catch(Exception) { Debug.Assert(false); }
}
#endif
if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); // Hide again
}
}
}

View File

@ -0,0 +1,316 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.IO;
using System.Security.Cryptography;
using System.Diagnostics;
using System.Text;
using KeePassLib.Native;
using KeePassLib.Utility;
#if KeePassLibSD
using KeePassLibSD;
#endif
namespace KeePassLib.Serialization
{
public sealed class HashedBlockStream : Stream
{
private const int m_nDefaultBufferSize = 1024 * 1024; // 1 MB
private Stream m_sBaseStream;
private bool m_bWriting;
private bool m_bVerify;
private bool m_bEos = false;
private BinaryReader m_brInput;
private BinaryWriter m_bwOutput;
private byte[] m_pbBuffer;
private int m_nBufferPos = 0;
private uint m_uBufferIndex = 0;
public override bool CanRead
{
get { return !m_bWriting; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return m_bWriting; }
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public HashedBlockStream(Stream sBaseStream, bool bWriting)
{
Initialize(sBaseStream, bWriting, 0, true);
}
public HashedBlockStream(Stream sBaseStream, bool bWriting, int nBufferSize)
{
Initialize(sBaseStream, bWriting, nBufferSize, true);
}
public HashedBlockStream(Stream sBaseStream, bool bWriting, int nBufferSize,
bool bVerify)
{
Initialize(sBaseStream, bWriting, nBufferSize, bVerify);
}
private void Initialize(Stream sBaseStream, bool bWriting, int nBufferSize,
bool bVerify)
{
if(sBaseStream == null) throw new ArgumentNullException("sBaseStream");
if(nBufferSize < 0) throw new ArgumentOutOfRangeException("nBufferSize");
if(nBufferSize == 0) nBufferSize = m_nDefaultBufferSize;
m_sBaseStream = sBaseStream;
m_bWriting = bWriting;
m_bVerify = bVerify;
UTF8Encoding utf8 = StrUtil.Utf8;
if(m_bWriting == false) // Reading mode
{
if(m_sBaseStream.CanRead == false)
throw new InvalidOperationException();
m_brInput = new BinaryReader(sBaseStream, utf8);
m_pbBuffer = new byte[0];
}
else // Writing mode
{
if(m_sBaseStream.CanWrite == false)
throw new InvalidOperationException();
m_bwOutput = new BinaryWriter(sBaseStream, utf8);
m_pbBuffer = new byte[nBufferSize];
}
}
public override void Flush()
{
if(m_bWriting) m_bwOutput.Flush();
}
public override void Close()
{
if(m_sBaseStream != null)
{
if(m_bWriting == false) // Reading mode
{
m_brInput.Close();
m_brInput = null;
}
else // Writing mode
{
if(m_nBufferPos == 0) // No data left in buffer
WriteHashedBlock(); // Write terminating block
else
{
WriteHashedBlock(); // Write remaining buffered data
WriteHashedBlock(); // Write terminating block
}
Flush();
m_bwOutput.Close();
m_bwOutput = null;
}
m_sBaseStream.Close();
m_sBaseStream = null;
}
}
public override long Seek(long lOffset, SeekOrigin soOrigin)
{
throw new NotSupportedException();
}
public override void SetLength(long lValue)
{
throw new NotSupportedException();
}
public override int Read(byte[] pbBuffer, int nOffset, int nCount)
{
if(m_bWriting) throw new InvalidOperationException();
int nRemaining = nCount;
while(nRemaining > 0)
{
if(m_nBufferPos == m_pbBuffer.Length)
{
if(ReadHashedBlock() == false)
return nCount - nRemaining; // Bytes actually read
}
int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nRemaining);
Array.Copy(m_pbBuffer, m_nBufferPos, pbBuffer, nOffset, nCopy);
nOffset += nCopy;
m_nBufferPos += nCopy;
nRemaining -= nCopy;
}
return nCount;
}
private bool ReadHashedBlock()
{
if(m_bEos) return false; // End of stream reached already
m_nBufferPos = 0;
if(m_brInput.ReadUInt32() != m_uBufferIndex)
throw new InvalidDataException();
++m_uBufferIndex;
byte[] pbStoredHash = m_brInput.ReadBytes(32);
if((pbStoredHash == null) || (pbStoredHash.Length != 32))
throw new InvalidDataException();
int nBufferSize = 0;
try { nBufferSize = m_brInput.ReadInt32(); }
catch(NullReferenceException) // Mono bug workaround (LaunchPad 783268)
{
if(!NativeLib.IsUnix()) throw;
}
if(nBufferSize < 0)
throw new InvalidDataException();
if(nBufferSize == 0)
{
for(int iHash = 0; iHash < 32; ++iHash)
{
if(pbStoredHash[iHash] != 0)
throw new InvalidDataException();
}
m_bEos = true;
m_pbBuffer = new byte[0];
return false;
}
m_pbBuffer = m_brInput.ReadBytes(nBufferSize);
if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBufferSize) && m_bVerify))
throw new InvalidDataException();
if(m_bVerify)
{
SHA256Managed sha256 = new SHA256Managed();
byte[] pbComputedHash = sha256.ComputeHash(m_pbBuffer);
if((pbComputedHash == null) || (pbComputedHash.Length != 32))
throw new InvalidOperationException();
for(int iHashPos = 0; iHashPos < 32; ++iHashPos)
{
if(pbStoredHash[iHashPos] != pbComputedHash[iHashPos])
throw new InvalidDataException();
}
}
return true;
}
public override void Write(byte[] pbBuffer, int nOffset, int nCount)
{
if(!m_bWriting) throw new InvalidOperationException();
while(nCount > 0)
{
if(m_nBufferPos == m_pbBuffer.Length)
WriteHashedBlock();
int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nCount);
Array.Copy(pbBuffer, nOffset, m_pbBuffer, m_nBufferPos, nCopy);
nOffset += nCopy;
m_nBufferPos += nCopy;
nCount -= nCopy;
}
}
private void WriteHashedBlock()
{
m_bwOutput.Write(m_uBufferIndex);
++m_uBufferIndex;
if(m_nBufferPos > 0)
{
SHA256Managed sha256 = new SHA256Managed();
#if !KeePassLibSD
byte[] pbHash = sha256.ComputeHash(m_pbBuffer, 0, m_nBufferPos);
#else
byte[] pbHash;
if(m_nBufferPos == m_pbBuffer.Length)
pbHash = sha256.ComputeHash(m_pbBuffer);
else
{
byte[] pbData = new byte[m_nBufferPos];
Array.Copy(m_pbBuffer, 0, pbData, 0, m_nBufferPos);
pbHash = sha256.ComputeHash(pbData);
}
#endif
m_bwOutput.Write(pbHash);
}
else
{
m_bwOutput.Write((ulong)0); // Zero hash
m_bwOutput.Write((ulong)0);
m_bwOutput.Write((ulong)0);
m_bwOutput.Write((ulong)0);
}
m_bwOutput.Write(m_nBufferPos);
if(m_nBufferPos > 0)
m_bwOutput.Write(m_pbBuffer, 0, m_nBufferPos);
m_nBufferPos = 0;
}
}
}

View File

@ -0,0 +1,453 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
#if !KeePassLibSD
using System.Net.Cache;
using System.Net.Security;
#endif
using KeePassLib.Native;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
#if !KeePassLibSD
public sealed class IOWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
IOConnection.ConfigureWebRequest(request);
return request;
}
}
#endif
public static class IOConnection
{
#if !KeePassLibSD
private static ProxyServerType m_pstProxyType = ProxyServerType.System;
private static string m_strProxyAddr = string.Empty;
private static string m_strProxyPort = string.Empty;
private static string m_strProxyUserName = string.Empty;
private static string m_strProxyPassword = string.Empty;
#endif
// Web request methods
public const string WrmDeleteFile = "DELETEFILE";
public const string WrmMoveFile = "MOVEFILE";
// Web request headers
public const string WrhMoveFileTo = "MoveFileTo";
#if !KeePassLibSD
// Allow self-signed certificates, expired certificates, etc.
private static bool ValidateServerCertificate(object sender,
X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
return true;
}
public static void SetProxy(ProxyServerType pst, string strAddr,
string strPort, string strUserName, string strPassword)
{
m_pstProxyType = pst;
m_strProxyAddr = (strAddr ?? string.Empty);
m_strProxyPort = (strPort ?? string.Empty);
m_strProxyUserName = (strUserName ?? string.Empty);
m_strProxyPassword = (strPassword ?? string.Empty);
}
internal static void ConfigureWebRequest(WebRequest request)
{
if(request == null) { Debug.Assert(false); return; } // No throw
// WebDAV support
if(request is HttpWebRequest)
{
request.PreAuthenticate = true; // Also auth GET
if(request.Method == WebRequestMethods.Http.Post)
request.Method = WebRequestMethods.Http.Put;
}
// else if(request is FtpWebRequest)
// {
// Debug.Assert(((FtpWebRequest)request).UsePassive);
// }
// Not implemented and ignored in Mono < 2.10
try
{
request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
}
catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); }
try
{
IWebProxy prx;
if(GetWebProxy(out prx)) request.Proxy = prx;
}
catch(Exception) { Debug.Assert(false); }
}
internal static void ConfigureWebClient(WebClient wc)
{
// Not implemented and ignored in Mono < 2.10
try
{
wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore);
}
catch(NotImplementedException) { }
catch(Exception) { Debug.Assert(false); }
try
{
IWebProxy prx;
if(GetWebProxy(out prx)) wc.Proxy = prx;
}
catch(Exception) { Debug.Assert(false); }
}
private static bool GetWebProxy(out IWebProxy prx)
{
prx = null;
if(m_pstProxyType == ProxyServerType.None)
return true; // Use null proxy
if(m_pstProxyType == ProxyServerType.Manual)
{
try
{
if(m_strProxyPort.Length > 0)
prx = new WebProxy(m_strProxyAddr, int.Parse(m_strProxyPort));
else prx = new WebProxy(m_strProxyAddr);
if((m_strProxyUserName.Length > 0) || (m_strProxyPassword.Length > 0))
prx.Credentials = new NetworkCredential(m_strProxyUserName,
m_strProxyPassword);
return true; // Use manual proxy
}
catch(Exception exProxy)
{
string strInfo = m_strProxyAddr;
if(m_strProxyPort.Length > 0) strInfo += ":" + m_strProxyPort;
MessageService.ShowWarning(strInfo, exProxy.Message);
}
return false; // Use default
}
if((m_strProxyUserName.Length == 0) && (m_strProxyPassword.Length == 0))
return false; // Use default proxy, no auth
try
{
prx = WebRequest.DefaultWebProxy;
if(prx == null) prx = WebRequest.GetSystemWebProxy();
if(prx == null) throw new InvalidOperationException();
prx.Credentials = new NetworkCredential(m_strProxyUserName,
m_strProxyPassword);
return true;
}
catch(Exception) { Debug.Assert(false); }
return false;
}
private static void PrepareWebAccess()
{
ServicePointManager.ServerCertificateValidationCallback =
ValidateServerCertificate;
}
private static IOWebClient CreateWebClient(IOConnectionInfo ioc)
{
PrepareWebAccess();
IOWebClient wc = new IOWebClient();
ConfigureWebClient(wc);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
wc.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
else if(NativeLib.IsUnix()) // Mono requires credentials
wc.Credentials = new NetworkCredential("anonymous", string.Empty);
return wc;
}
private static WebRequest CreateWebRequest(IOConnectionInfo ioc)
{
PrepareWebAccess();
WebRequest req = WebRequest.Create(ioc.Path);
ConfigureWebRequest(req);
if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0))
req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password);
else if(NativeLib.IsUnix()) // Mono requires credentials
req.Credentials = new NetworkCredential("anonymous", string.Empty);
return req;
}
public static Stream OpenRead(IOConnectionInfo ioc)
{
if(StrUtil.IsDataUri(ioc.Path))
{
byte[] pbData = StrUtil.DataUriToData(ioc.Path);
if(pbData != null) return new MemoryStream(pbData, false);
}
if(ioc.IsLocalFile()) return OpenReadLocal(ioc);
return CreateWebClient(ioc).OpenRead(new Uri(ioc.Path));
}
#else
public static Stream OpenRead(IOConnectionInfo ioc)
{
return OpenReadLocal(ioc);
}
#endif
private static Stream OpenReadLocal(IOConnectionInfo ioc)
{
return new FileStream(ioc.Path, FileMode.Open, FileAccess.Read,
FileShare.Read);
}
#if !KeePassLibSD
public static Stream OpenWrite(IOConnectionInfo ioc)
{
if(ioc == null) { Debug.Assert(false); return null; }
if(ioc.IsLocalFile()) return OpenWriteLocal(ioc);
Uri uri = new Uri(ioc.Path);
// Mono does not set HttpWebRequest.Method to POST for writes,
// so one needs to set the method to PUT explicitly
if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp,
StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps,
StrUtil.CaseIgnoreCmp)))
return CreateWebClient(ioc).OpenWrite(uri, WebRequestMethods.Http.Put);
return CreateWebClient(ioc).OpenWrite(uri);
}
#else
public static Stream OpenWrite(IOConnectionInfo ioc)
{
return OpenWriteLocal(ioc);
}
#endif
private static Stream OpenWriteLocal(IOConnectionInfo ioc)
{
return new FileStream(ioc.Path, FileMode.Create, FileAccess.Write,
FileShare.None);
}
public static bool FileExists(IOConnectionInfo ioc)
{
return FileExists(ioc, false);
}
public static bool FileExists(IOConnectionInfo ioc, bool bThrowErrors)
{
if(ioc == null) { Debug.Assert(false); return false; }
if(ioc.IsLocalFile()) return File.Exists(ioc.Path);
#if !KeePassLibSD
if(ioc.Path.StartsWith("ftp://", StrUtil.CaseIgnoreCmp))
{
bool b = SendCommand(ioc, WebRequestMethods.Ftp.GetDateTimestamp);
if(!b && bThrowErrors) throw new InvalidOperationException();
return b;
}
#endif
try
{
Stream s = OpenRead(ioc);
if(s == null) throw new FileNotFoundException();
try { s.ReadByte(); }
catch(Exception) { }
// We didn't download the file completely; close may throw
// an exception -- that's okay
try { s.Close(); }
catch(Exception) { }
}
catch(Exception)
{
if(bThrowErrors) throw;
return false;
}
return true;
}
public static void DeleteFile(IOConnectionInfo ioc)
{
if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; }
#if !KeePassLibSD
WebRequest req = CreateWebRequest(ioc);
if(req != null)
{
if(req is HttpWebRequest) req.Method = "DELETE";
else if(req is FtpWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile;
else if(req is FileWebRequest)
{
File.Delete(UrlUtil.FileUrlToPath(ioc.Path));
return;
}
else req.Method = WrmDeleteFile;
DisposeResponse(req.GetResponse(), true);
}
#endif
}
/// <summary>
/// Rename/move a file. For local file system and WebDAV, the
/// specified file is moved, i.e. the file destination can be
/// in a different directory/path. In contrast, for FTP the
/// file is renamed, i.e. its destination must be in the same
/// directory/path.
/// </summary>
/// <param name="iocFrom">Source file path.</param>
/// <param name="iocTo">Target file path.</param>
public static void RenameFile(IOConnectionInfo iocFrom, IOConnectionInfo iocTo)
{
if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; }
#if !KeePassLibSD
WebRequest req = CreateWebRequest(iocFrom);
if(req != null)
{
if(req is HttpWebRequest)
{
req.Method = "MOVE";
req.Headers.Set("Destination", iocTo.Path); // Full URL supported
}
else if(req is FtpWebRequest)
{
req.Method = WebRequestMethods.Ftp.Rename;
((FtpWebRequest)req).RenameTo = UrlUtil.GetFileName(iocTo.Path);
}
else if(req is FileWebRequest)
{
File.Move(UrlUtil.FileUrlToPath(iocFrom.Path),
UrlUtil.FileUrlToPath(iocTo.Path));
return;
}
else
{
req.Method = WrmMoveFile;
req.Headers.Set(WrhMoveFileTo, iocTo.Path);
}
DisposeResponse(req.GetResponse(), true);
}
#endif
// using(Stream sIn = IOConnection.OpenRead(iocFrom))
// {
// using(Stream sOut = IOConnection.OpenWrite(iocTo))
// {
// MemUtil.CopyStream(sIn, sOut);
// sOut.Close();
// }
//
// sIn.Close();
// }
// DeleteFile(iocFrom);
}
#if !KeePassLibSD
private static bool SendCommand(IOConnectionInfo ioc, string strMethod)
{
try
{
WebRequest req = CreateWebRequest(ioc);
req.Method = strMethod;
DisposeResponse(req.GetResponse(), true);
}
catch(Exception) { return false; }
return true;
}
#endif
private static void DisposeResponse(WebResponse wr, bool bGetStream)
{
if(wr == null) return;
try
{
if(bGetStream)
{
Stream s = wr.GetResponseStream();
if(s != null) s.Close();
}
}
catch(Exception) { Debug.Assert(false); }
try { wr.Close(); }
catch(Exception) { Debug.Assert(false); }
}
public static byte[] ReadFile(IOConnectionInfo ioc)
{
Stream sIn = null;
MemoryStream ms = null;
try
{
sIn = IOConnection.OpenRead(ioc);
if(sIn == null) return null;
ms = new MemoryStream();
MemUtil.CopyStream(sIn, ms);
return ms.ToArray();
}
catch(Exception) { }
finally
{
if(sIn != null) sIn.Close();
if(ms != null) ms.Close();
}
return null;
}
}
}

View File

@ -0,0 +1,342 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Net;
using System.ComponentModel;
using System.Diagnostics;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public enum IOCredSaveMode
{
/// <summary>
/// Do not remember user name or password.
/// </summary>
NoSave = 0,
/// <summary>
/// Remember the user name only, not the password.
/// </summary>
UserNameOnly,
/// <summary>
/// Save both user name and password.
/// </summary>
SaveCred
}
public enum IOCredProtMode
{
None = 0,
Obf
}
/* public enum IOFileFormatHint
{
None = 0,
Deprecated
} */
public sealed class IOConnectionInfo : IDeepCloneable<IOConnectionInfo>
{
// private IOFileFormatHint m_ioHint = IOFileFormatHint.None;
private string m_strUrl = string.Empty;
public string Path
{
get { return m_strUrl; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strUrl = value;
}
}
private string m_strUser = string.Empty;
[DefaultValue("")]
public string UserName
{
get { return m_strUser; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strUser = value;
}
}
private string m_strPassword = string.Empty;
[DefaultValue("")]
public string Password
{
get { return m_strPassword; }
set
{
Debug.Assert(value != null);
if(value == null) throw new ArgumentNullException("value");
m_strPassword = value;
}
}
private IOCredProtMode m_ioCredProtMode = IOCredProtMode.None;
public IOCredProtMode CredProtMode
{
get { return m_ioCredProtMode; }
set { m_ioCredProtMode = value; }
}
private IOCredSaveMode m_ioCredSaveMode = IOCredSaveMode.NoSave;
public IOCredSaveMode CredSaveMode
{
get { return m_ioCredSaveMode; }
set { m_ioCredSaveMode = value; }
}
/* public IOFileFormatHint FileFormatHint
{
get { return m_ioHint; }
set { m_ioHint = value; }
} */
public IOConnectionInfo CloneDeep()
{
return (IOConnectionInfo)this.MemberwiseClone();
}
/*
/// <summary>
/// Serialize the current connection info to a string. Credentials
/// are only serialized if the <c>SaveCredentials</c> property
/// is <c>true</c>.
/// </summary>
/// <param name="iocToCompile">Input object to be serialized.</param>
/// <returns>Serialized object as string.</returns>
public static string SerializeToString(IOConnectionInfo iocToCompile)
{
Debug.Assert(iocToCompile != null);
if(iocToCompile == null) throw new ArgumentNullException("iocToCompile");
string strUrl = iocToCompile.Path;
string strUser = TransformUnreadable(iocToCompile.UserName, true);
string strPassword = TransformUnreadable(iocToCompile.Password, true);
string strAll = strUrl + strUser + strPassword;
char chSep = char.MinValue;
char[] vPrefSeps = new char[]{ '@', '#', '!', '$', '*' };
foreach(char ch in vPrefSeps)
{
if(strAll.IndexOf(ch) < 0)
{
chSep = ch;
break;
}
}
if(chSep == char.MinValue)
{
for(char chEnum = '!'; chEnum < char.MaxValue; ++chEnum)
{
if(strAll.IndexOf(chEnum) < 0)
{
chSep = chEnum;
break;
}
}
}
if(chSep == char.MinValue) throw new FormatException();
StringBuilder sb = new StringBuilder();
sb.Append(chSep);
sb.Append(strUrl);
sb.Append(chSep);
if(iocToCompile.CredSaveMode == IOCredSaveMode.SaveCred)
{
sb.Append('C');
sb.Append(chSep);
sb.Append(strUser);
sb.Append(chSep);
sb.Append(strPassword);
}
else if(iocToCompile.CredSaveMode == IOCredSaveMode.UserNameOnly)
{
sb.Append('U');
sb.Append(chSep);
sb.Append(strUser);
sb.Append(chSep);
}
else // Don't remember credentials
{
sb.Append('N');
sb.Append(chSep);
sb.Append(chSep);
}
return sb.ToString();
}
public static IOConnectionInfo UnserializeFromString(string strToDecompile)
{
Debug.Assert(strToDecompile != null);
if(strToDecompile == null) throw new ArgumentNullException("strToDecompile");
if(strToDecompile.Length <= 1) throw new ArgumentException();
char chSep = strToDecompile[0];
string[] vParts = strToDecompile.Substring(1, strToDecompile.Length -
1).Split(new char[]{ chSep });
if(vParts.Length < 4) throw new ArgumentException();
IOConnectionInfo s = new IOConnectionInfo();
s.Path = vParts[0];
if(vParts[1] == "C")
s.CredSaveMode = IOCredSaveMode.SaveCred;
else if(vParts[1] == "U")
s.CredSaveMode = IOCredSaveMode.UserNameOnly;
else
s.CredSaveMode = IOCredSaveMode.NoSave;
s.UserName = TransformUnreadable(vParts[2], false);
s.Password = TransformUnreadable(vParts[3], false);
return s;
}
*/
/*
/// <summary>
/// Very simple string protection. Doesn't really encrypt the input
/// string, only encodes it that it's not readable on the first glance.
/// </summary>
/// <param name="strToEncode">The string to encode/decode.</param>
/// <param name="bEncode">If <c>true</c>, the string will be encoded,
/// otherwise it'll be decoded.</param>
/// <returns>Encoded/decoded string.</returns>
private static string TransformUnreadable(string strToEncode, bool bEncode)
{
Debug.Assert(strToEncode != null);
if(strToEncode == null) throw new ArgumentNullException("strToEncode");
if(bEncode)
{
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(strToEncode);
unchecked
{
for(int iPos = 0; iPos < pbUtf8.Length; ++iPos)
pbUtf8[iPos] += (byte)(iPos * 11);
}
return Convert.ToBase64String(pbUtf8);
}
else // Decode
{
byte[] pbBase = Convert.FromBase64String(strToEncode);
unchecked
{
for(int iPos = 0; iPos < pbBase.Length; ++iPos)
pbBase[iPos] -= (byte)(iPos * 11);
}
return StrUtil.Utf8.GetString(pbBase, 0, pbBase.Length);
}
}
*/
public string GetDisplayName()
{
string str = m_strUrl;
if(m_strUser.Length > 0)
str += " (" + m_strUser + ")";
return str;
}
public bool IsEmpty()
{
return (m_strUrl.Length > 0);
}
public static IOConnectionInfo FromPath(string strPath)
{
IOConnectionInfo ioc = new IOConnectionInfo();
ioc.Path = strPath;
ioc.CredSaveMode = IOCredSaveMode.NoSave;
return ioc;
}
public bool CanProbablyAccess()
{
if(IsLocalFile()) return File.Exists(m_strUrl);
return true;
}
public bool IsLocalFile()
{
// Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs
return (m_strUrl.IndexOf(@"://") < 0);
}
public void ClearCredentials(bool bDependingOnRememberMode)
{
if((bDependingOnRememberMode == false) ||
(m_ioCredSaveMode == IOCredSaveMode.NoSave))
{
m_strUser = string.Empty;
}
if((bDependingOnRememberMode == false) ||
(m_ioCredSaveMode == IOCredSaveMode.NoSave) ||
(m_ioCredSaveMode == IOCredSaveMode.UserNameOnly))
{
m_strPassword = string.Empty;
}
}
public void Obfuscate(bool bObf)
{
if(bObf && (m_ioCredProtMode == IOCredProtMode.None))
{
m_strPassword = StrUtil.Obfuscate(m_strPassword);
m_ioCredProtMode = IOCredProtMode.Obf;
}
else if(!bObf && (m_ioCredProtMode == IOCredProtMode.Obf))
{
m_strPassword = StrUtil.Deobfuscate(m_strPassword);
m_ioCredProtMode = IOCredProtMode.None;
}
}
}
}

View File

@ -0,0 +1,877 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Xml;
using System.IO;
using System.Diagnostics;
using KeePassLib;
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Interfaces;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
/// <summary>
/// Serialization to KeePass KDBX files.
/// </summary>
public sealed partial class KdbxFile
{
private enum KdbContext
{
Null,
KeePassFile,
Meta,
Root,
MemoryProtection,
CustomIcons,
CustomIcon,
Binaries,
CustomData,
CustomDataItem,
RootDeletedObjects,
DeletedObject,
Group,
GroupTimes,
Entry,
EntryTimes,
EntryString,
EntryBinary,
EntryAutoType,
EntryAutoTypeItem,
EntryHistory
}
private bool m_bReadNextNode = true;
private Stack<PwGroup> m_ctxGroups = new Stack<PwGroup>();
private PwGroup m_ctxGroup = null;
private PwEntry m_ctxEntry = null;
private string m_ctxStringName = null;
private ProtectedString m_ctxStringValue = null;
private string m_ctxBinaryName = null;
private ProtectedBinary m_ctxBinaryValue = null;
private string m_ctxATName = null;
private string m_ctxATSeq = null;
private bool m_bEntryInHistory = false;
private PwEntry m_ctxHistoryBase = null;
private PwDeletedObject m_ctxDeletedObject = null;
private PwUuid m_uuidCustomIconID = PwUuid.Zero;
private byte[] m_pbCustomIconData = null;
private string m_strCustomDataKey = null;
private string m_strCustomDataValue = null;
private void ReadXmlStreamed(Stream readerStream, Stream sParentStream)
{
ReadDocumentStreamed(CreateXmlReader(readerStream), sParentStream);
}
internal static XmlReaderSettings CreateStdXmlReaderSettings()
{
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.CloseInput = true;
xrs.IgnoreComments = true;
xrs.IgnoreProcessingInstructions = true;
xrs.IgnoreWhitespace = true;
#if !KeePassLibSD
xrs.ProhibitDtd = true;
#endif
xrs.ValidationType = ValidationType.None;
return xrs;
}
private static XmlReader CreateXmlReader(Stream readerStream)
{
XmlReaderSettings xrs = CreateStdXmlReaderSettings();
return XmlReader.Create(readerStream, xrs);
}
private void ReadDocumentStreamed(XmlReader xr, Stream sParentStream)
{
Debug.Assert(xr != null);
if(xr == null) throw new ArgumentNullException("xr");
m_ctxGroups.Clear();
m_dictBinPool = new Dictionary<string, ProtectedBinary>();
KdbContext ctx = KdbContext.Null;
uint uTagCounter = 0;
bool bSupportsStatus = (m_slLogger != null);
long lStreamLength = 1;
try
{
sParentStream.Position.ToString(); // Test Position support
lStreamLength = sParentStream.Length;
}
catch(Exception) { bSupportsStatus = false; }
if(lStreamLength <= 0) { Debug.Assert(false); lStreamLength = 1; }
m_bReadNextNode = true;
while(true)
{
if(m_bReadNextNode)
{
if(!xr.Read()) break;
}
else m_bReadNextNode = true;
switch(xr.NodeType)
{
case XmlNodeType.Element:
ctx = ReadXmlElement(ctx, xr);
break;
case XmlNodeType.EndElement:
ctx = EndXmlElement(ctx, xr);
break;
case XmlNodeType.XmlDeclaration:
break; // Ignore
default:
Debug.Assert(false);
break;
}
++uTagCounter;
if(((uTagCounter % 256) == 0) && bSupportsStatus)
{
Debug.Assert(lStreamLength == sParentStream.Length);
uint uPct = (uint)((sParentStream.Position * 100) /
lStreamLength);
// Clip percent value in case the stream reports incorrect
// position/length values (M120413)
if(uPct > 100) { Debug.Assert(false); uPct = 100; }
m_slLogger.SetProgress(uPct);
}
}
Debug.Assert(ctx == KdbContext.Null);
if(ctx != KdbContext.Null) throw new FormatException();
Debug.Assert(m_ctxGroups.Count == 0);
if(m_ctxGroups.Count != 0) throw new FormatException();
}
private KdbContext ReadXmlElement(KdbContext ctx, XmlReader xr)
{
Debug.Assert(xr.NodeType == XmlNodeType.Element);
switch(ctx)
{
case KdbContext.Null:
if(xr.Name == ElemDocNode)
return SwitchContext(ctx, KdbContext.KeePassFile, xr);
else ReadUnknown(xr);
break;
case KdbContext.KeePassFile:
if(xr.Name == ElemMeta)
return SwitchContext(ctx, KdbContext.Meta, xr);
else if(xr.Name == ElemRoot)
return SwitchContext(ctx, KdbContext.Root, xr);
else ReadUnknown(xr);
break;
case KdbContext.Meta:
if(xr.Name == ElemGenerator)
ReadString(xr); // Ignore
else if(xr.Name == ElemHeaderHash)
{
string strHash = ReadString(xr);
if(!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) &&
!m_bRepairMode)
{
byte[] pbHash = Convert.FromBase64String(strHash);
if(!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader))
throw new IOException(KLRes.FileCorrupted);
}
}
else if(xr.Name == ElemDbName)
m_pwDatabase.Name = ReadString(xr);
else if(xr.Name == ElemDbNameChanged)
m_pwDatabase.NameChanged = ReadTime(xr);
else if(xr.Name == ElemDbDesc)
m_pwDatabase.Description = ReadString(xr);
else if(xr.Name == ElemDbDescChanged)
m_pwDatabase.DescriptionChanged = ReadTime(xr);
else if(xr.Name == ElemDbDefaultUser)
m_pwDatabase.DefaultUserName = ReadString(xr);
else if(xr.Name == ElemDbDefaultUserChanged)
m_pwDatabase.DefaultUserNameChanged = ReadTime(xr);
else if(xr.Name == ElemDbMntncHistoryDays)
m_pwDatabase.MaintenanceHistoryDays = ReadUInt(xr, 365);
else if(xr.Name == ElemDbColor)
{
string strColor = ReadString(xr);
if(!string.IsNullOrEmpty(strColor))
m_pwDatabase.Color = ColorTranslator.FromHtml(strColor);
}
else if(xr.Name == ElemDbKeyChanged)
m_pwDatabase.MasterKeyChanged = ReadTime(xr);
else if(xr.Name == ElemDbKeyChangeRec)
m_pwDatabase.MasterKeyChangeRec = ReadLong(xr, -1);
else if(xr.Name == ElemDbKeyChangeForce)
m_pwDatabase.MasterKeyChangeForce = ReadLong(xr, -1);
else if(xr.Name == ElemMemoryProt)
return SwitchContext(ctx, KdbContext.MemoryProtection, xr);
else if(xr.Name == ElemCustomIcons)
return SwitchContext(ctx, KdbContext.CustomIcons, xr);
else if(xr.Name == ElemRecycleBinEnabled)
m_pwDatabase.RecycleBinEnabled = ReadBool(xr, true);
else if(xr.Name == ElemRecycleBinUuid)
m_pwDatabase.RecycleBinUuid = ReadUuid(xr);
else if(xr.Name == ElemRecycleBinChanged)
m_pwDatabase.RecycleBinChanged = ReadTime(xr);
else if(xr.Name == ElemEntryTemplatesGroup)
m_pwDatabase.EntryTemplatesGroup = ReadUuid(xr);
else if(xr.Name == ElemEntryTemplatesGroupChanged)
m_pwDatabase.EntryTemplatesGroupChanged = ReadTime(xr);
else if(xr.Name == ElemHistoryMaxItems)
m_pwDatabase.HistoryMaxItems = ReadInt(xr, -1);
else if(xr.Name == ElemHistoryMaxSize)
m_pwDatabase.HistoryMaxSize = ReadLong(xr, -1);
else if(xr.Name == ElemLastSelectedGroup)
m_pwDatabase.LastSelectedGroup = ReadUuid(xr);
else if(xr.Name == ElemLastTopVisibleGroup)
m_pwDatabase.LastTopVisibleGroup = ReadUuid(xr);
else if(xr.Name == ElemBinaries)
return SwitchContext(ctx, KdbContext.Binaries, xr);
else if(xr.Name == ElemCustomData)
return SwitchContext(ctx, KdbContext.CustomData, xr);
else ReadUnknown(xr);
break;
case KdbContext.MemoryProtection:
if(xr.Name == ElemProtTitle)
m_pwDatabase.MemoryProtection.ProtectTitle = ReadBool(xr, false);
else if(xr.Name == ElemProtUserName)
m_pwDatabase.MemoryProtection.ProtectUserName = ReadBool(xr, false);
else if(xr.Name == ElemProtPassword)
m_pwDatabase.MemoryProtection.ProtectPassword = ReadBool(xr, true);
else if(xr.Name == ElemProtUrl)
m_pwDatabase.MemoryProtection.ProtectUrl = ReadBool(xr, false);
else if(xr.Name == ElemProtNotes)
m_pwDatabase.MemoryProtection.ProtectNotes = ReadBool(xr, false);
// else if(xr.Name == ElemProtAutoHide)
// m_pwDatabase.MemoryProtection.AutoEnableVisualHiding = ReadBool(xr, true);
else ReadUnknown(xr);
break;
case KdbContext.CustomIcons:
if(xr.Name == ElemCustomIconItem)
return SwitchContext(ctx, KdbContext.CustomIcon, xr);
else ReadUnknown(xr);
break;
case KdbContext.CustomIcon:
if(xr.Name == ElemCustomIconItemID)
m_uuidCustomIconID = ReadUuid(xr);
else if(xr.Name == ElemCustomIconItemData)
{
string strData = ReadString(xr);
if(!string.IsNullOrEmpty(strData))
m_pbCustomIconData = Convert.FromBase64String(strData);
else { Debug.Assert(false); }
}
else ReadUnknown(xr);
break;
case KdbContext.Binaries:
if(xr.Name == ElemBinary)
{
if(xr.MoveToAttribute(AttrId))
{
string strKey = xr.Value;
ProtectedBinary pbData = ReadProtectedBinary(xr);
m_dictBinPool[strKey ?? string.Empty] = pbData;
}
else ReadUnknown(xr);
}
else ReadUnknown(xr);
break;
case KdbContext.CustomData:
if(xr.Name == ElemStringDictExItem)
return SwitchContext(ctx, KdbContext.CustomDataItem, xr);
else ReadUnknown(xr);
break;
case KdbContext.CustomDataItem:
if(xr.Name == ElemKey)
m_strCustomDataKey = ReadString(xr);
else if(xr.Name == ElemValue)
m_strCustomDataValue = ReadString(xr);
else ReadUnknown(xr);
break;
case KdbContext.Root:
if(xr.Name == ElemGroup)
{
Debug.Assert(m_ctxGroups.Count == 0);
if(m_ctxGroups.Count != 0) throw new FormatException();
m_pwDatabase.RootGroup = new PwGroup(false, false);
m_ctxGroups.Push(m_pwDatabase.RootGroup);
m_ctxGroup = m_ctxGroups.Peek();
return SwitchContext(ctx, KdbContext.Group, xr);
}
else if(xr.Name == ElemDeletedObjects)
return SwitchContext(ctx, KdbContext.RootDeletedObjects, xr);
else ReadUnknown(xr);
break;
case KdbContext.Group:
if(xr.Name == ElemUuid)
m_ctxGroup.Uuid = ReadUuid(xr);
else if(xr.Name == ElemName)
m_ctxGroup.Name = ReadString(xr);
else if(xr.Name == ElemNotes)
m_ctxGroup.Notes = ReadString(xr);
else if(xr.Name == ElemIcon)
m_ctxGroup.IconId = (PwIcon)ReadInt(xr, (int)PwIcon.Folder);
else if(xr.Name == ElemCustomIconID)
m_ctxGroup.CustomIconUuid = ReadUuid(xr);
else if(xr.Name == ElemTimes)
return SwitchContext(ctx, KdbContext.GroupTimes, xr);
else if(xr.Name == ElemIsExpanded)
m_ctxGroup.IsExpanded = ReadBool(xr, true);
else if(xr.Name == ElemGroupDefaultAutoTypeSeq)
m_ctxGroup.DefaultAutoTypeSequence = ReadString(xr);
else if(xr.Name == ElemEnableAutoType)
m_ctxGroup.EnableAutoType = StrUtil.StringToBoolEx(ReadString(xr));
else if(xr.Name == ElemEnableSearching)
m_ctxGroup.EnableSearching = StrUtil.StringToBoolEx(ReadString(xr));
else if(xr.Name == ElemLastTopVisibleEntry)
m_ctxGroup.LastTopVisibleEntry = ReadUuid(xr);
else if(xr.Name == ElemGroup)
{
m_ctxGroup = new PwGroup(false, false);
m_ctxGroups.Peek().AddGroup(m_ctxGroup, true);
m_ctxGroups.Push(m_ctxGroup);
return SwitchContext(ctx, KdbContext.Group, xr);
}
else if(xr.Name == ElemEntry)
{
m_ctxEntry = new PwEntry(false, false);
m_ctxGroup.AddEntry(m_ctxEntry, true);
m_bEntryInHistory = false;
return SwitchContext(ctx, KdbContext.Entry, xr);
}
else ReadUnknown(xr);
break;
case KdbContext.Entry:
if(xr.Name == ElemUuid)
m_ctxEntry.Uuid = ReadUuid(xr);
else if(xr.Name == ElemIcon)
m_ctxEntry.IconId = (PwIcon)ReadInt(xr, (int)PwIcon.Key);
else if(xr.Name == ElemCustomIconID)
m_ctxEntry.CustomIconUuid = ReadUuid(xr);
else if(xr.Name == ElemFgColor)
{
string strColor = ReadString(xr);
if(!string.IsNullOrEmpty(strColor))
m_ctxEntry.ForegroundColor = ColorTranslator.FromHtml(strColor);
}
else if(xr.Name == ElemBgColor)
{
string strColor = ReadString(xr);
if(!string.IsNullOrEmpty(strColor))
m_ctxEntry.BackgroundColor = ColorTranslator.FromHtml(strColor);
}
else if(xr.Name == ElemOverrideUrl)
m_ctxEntry.OverrideUrl = ReadString(xr);
else if(xr.Name == ElemTags)
m_ctxEntry.Tags = StrUtil.StringToTags(ReadString(xr));
else if(xr.Name == ElemTimes)
return SwitchContext(ctx, KdbContext.EntryTimes, xr);
else if(xr.Name == ElemString)
return SwitchContext(ctx, KdbContext.EntryString, xr);
else if(xr.Name == ElemBinary)
return SwitchContext(ctx, KdbContext.EntryBinary, xr);
else if(xr.Name == ElemAutoType)
return SwitchContext(ctx, KdbContext.EntryAutoType, xr);
else if(xr.Name == ElemHistory)
{
Debug.Assert(m_bEntryInHistory == false);
if(m_bEntryInHistory == false)
{
m_ctxHistoryBase = m_ctxEntry;
return SwitchContext(ctx, KdbContext.EntryHistory, xr);
}
else ReadUnknown(xr);
}
else ReadUnknown(xr);
break;
case KdbContext.GroupTimes:
case KdbContext.EntryTimes:
ITimeLogger tl = ((ctx == KdbContext.GroupTimes) ?
(ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry);
Debug.Assert(tl != null);
if(xr.Name == ElemLastModTime)
tl.LastModificationTime = ReadTime(xr);
else if(xr.Name == ElemCreationTime)
tl.CreationTime = ReadTime(xr);
else if(xr.Name == ElemLastAccessTime)
tl.LastAccessTime = ReadTime(xr);
else if(xr.Name == ElemExpiryTime)
tl.ExpiryTime = ReadTime(xr);
else if(xr.Name == ElemExpires)
tl.Expires = ReadBool(xr, false);
else if(xr.Name == ElemUsageCount)
tl.UsageCount = ReadULong(xr, 0);
else if(xr.Name == ElemLocationChanged)
tl.LocationChanged = ReadTime(xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryString:
if(xr.Name == ElemKey)
m_ctxStringName = ReadString(xr);
else if(xr.Name == ElemValue)
m_ctxStringValue = ReadProtectedString(xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryBinary:
if(xr.Name == ElemKey)
m_ctxBinaryName = ReadString(xr);
else if(xr.Name == ElemValue)
m_ctxBinaryValue = ReadProtectedBinary(xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryAutoType:
if(xr.Name == ElemAutoTypeEnabled)
m_ctxEntry.AutoType.Enabled = ReadBool(xr, true);
else if(xr.Name == ElemAutoTypeObfuscation)
m_ctxEntry.AutoType.ObfuscationOptions =
(AutoTypeObfuscationOptions)ReadInt(xr, 0);
else if(xr.Name == ElemAutoTypeDefaultSeq)
m_ctxEntry.AutoType.DefaultSequence = ReadString(xr);
else if(xr.Name == ElemAutoTypeItem)
return SwitchContext(ctx, KdbContext.EntryAutoTypeItem, xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryAutoTypeItem:
if(xr.Name == ElemWindow)
m_ctxATName = ReadString(xr);
else if(xr.Name == ElemKeystrokeSequence)
m_ctxATSeq = ReadString(xr);
else ReadUnknown(xr);
break;
case KdbContext.EntryHistory:
if(xr.Name == ElemEntry)
{
m_ctxEntry = new PwEntry(false, false);
m_ctxHistoryBase.History.Add(m_ctxEntry);
m_bEntryInHistory = true;
return SwitchContext(ctx, KdbContext.Entry, xr);
}
else ReadUnknown(xr);
break;
case KdbContext.RootDeletedObjects:
if(xr.Name == ElemDeletedObject)
{
m_ctxDeletedObject = new PwDeletedObject();
m_pwDatabase.DeletedObjects.Add(m_ctxDeletedObject);
return SwitchContext(ctx, KdbContext.DeletedObject, xr);
}
else ReadUnknown(xr);
break;
case KdbContext.DeletedObject:
if(xr.Name == ElemUuid)
m_ctxDeletedObject.Uuid = ReadUuid(xr);
else if(xr.Name == ElemDeletionTime)
m_ctxDeletedObject.DeletionTime = ReadTime(xr);
else ReadUnknown(xr);
break;
default:
ReadUnknown(xr);
break;
}
return ctx;
}
private KdbContext EndXmlElement(KdbContext ctx, XmlReader xr)
{
Debug.Assert(xr.NodeType == XmlNodeType.EndElement);
if((ctx == KdbContext.KeePassFile) && (xr.Name == ElemDocNode))
return KdbContext.Null;
else if((ctx == KdbContext.Meta) && (xr.Name == ElemMeta))
return KdbContext.KeePassFile;
else if((ctx == KdbContext.Root) && (xr.Name == ElemRoot))
return KdbContext.KeePassFile;
else if((ctx == KdbContext.MemoryProtection) && (xr.Name == ElemMemoryProt))
return KdbContext.Meta;
else if((ctx == KdbContext.CustomIcons) && (xr.Name == ElemCustomIcons))
return KdbContext.Meta;
else if((ctx == KdbContext.CustomIcon) && (xr.Name == ElemCustomIconItem))
{
if((m_uuidCustomIconID != PwUuid.Zero) && (m_pbCustomIconData != null))
m_pwDatabase.CustomIcons.Add(new PwCustomIcon(
m_uuidCustomIconID, m_pbCustomIconData));
else { Debug.Assert(false); }
m_uuidCustomIconID = PwUuid.Zero;
m_pbCustomIconData = null;
return KdbContext.CustomIcons;
}
else if((ctx == KdbContext.Binaries) && (xr.Name == ElemBinaries))
return KdbContext.Meta;
else if((ctx == KdbContext.CustomData) && (xr.Name == ElemCustomData))
return KdbContext.Meta;
else if((ctx == KdbContext.CustomDataItem) && (xr.Name == ElemStringDictExItem))
{
if((m_strCustomDataKey != null) && (m_strCustomDataValue != null))
m_pwDatabase.CustomData.Set(m_strCustomDataKey, m_strCustomDataValue);
else { Debug.Assert(false); }
m_strCustomDataKey = null;
m_strCustomDataValue = null;
return KdbContext.CustomData;
}
else if((ctx == KdbContext.Group) && (xr.Name == ElemGroup))
{
if(PwUuid.Zero.EqualsValue(m_ctxGroup.Uuid))
m_ctxGroup.Uuid = new PwUuid(true); // No assert (import)
m_ctxGroups.Pop();
if(m_ctxGroups.Count == 0)
{
m_ctxGroup = null;
return KdbContext.Root;
}
else
{
m_ctxGroup = m_ctxGroups.Peek();
return KdbContext.Group;
}
}
else if((ctx == KdbContext.GroupTimes) && (xr.Name == ElemTimes))
return KdbContext.Group;
else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry))
{
// Create new UUID if absent
if(PwUuid.Zero.EqualsValue(m_ctxEntry.Uuid))
m_ctxEntry.Uuid = new PwUuid(true); // No assert (import)
if(m_bEntryInHistory)
{
m_ctxEntry = m_ctxHistoryBase;
return KdbContext.EntryHistory;
}
return KdbContext.Group;
}
else if((ctx == KdbContext.EntryTimes) && (xr.Name == ElemTimes))
return KdbContext.Entry;
else if((ctx == KdbContext.EntryString) && (xr.Name == ElemString))
{
m_ctxEntry.Strings.Set(m_ctxStringName, m_ctxStringValue);
m_ctxStringName = null;
m_ctxStringValue = null;
return KdbContext.Entry;
}
else if((ctx == KdbContext.EntryBinary) && (xr.Name == ElemBinary))
{
if(string.IsNullOrEmpty(m_strDetachBins))
m_ctxEntry.Binaries.Set(m_ctxBinaryName, m_ctxBinaryValue);
else
{
SaveBinary(m_ctxBinaryName, m_ctxBinaryValue, m_strDetachBins);
m_ctxBinaryValue = null;
GC.Collect();
}
m_ctxBinaryName = null;
m_ctxBinaryValue = null;
return KdbContext.Entry;
}
else if((ctx == KdbContext.EntryAutoType) && (xr.Name == ElemAutoType))
return KdbContext.Entry;
else if((ctx == KdbContext.EntryAutoTypeItem) && (xr.Name == ElemAutoTypeItem))
{
AutoTypeAssociation atAssoc = new AutoTypeAssociation(m_ctxATName,
m_ctxATSeq);
m_ctxEntry.AutoType.Add(atAssoc);
m_ctxATName = null;
m_ctxATSeq = null;
return KdbContext.EntryAutoType;
}
else if((ctx == KdbContext.EntryHistory) && (xr.Name == ElemHistory))
{
m_bEntryInHistory = false;
return KdbContext.Entry;
}
else if((ctx == KdbContext.RootDeletedObjects) && (xr.Name == ElemDeletedObjects))
return KdbContext.Root;
else if((ctx == KdbContext.DeletedObject) && (xr.Name == ElemDeletedObject))
{
m_ctxDeletedObject = null;
return KdbContext.RootDeletedObjects;
}
else
{
Debug.Assert(false);
throw new FormatException();
}
}
private string ReadString(XmlReader xr)
{
XorredBuffer xb = ProcessNode(xr);
if(xb != null)
{
byte[] pb = xb.ReadPlainText();
if(pb.Length == 0) return string.Empty;
return StrUtil.Utf8.GetString(pb, 0, pb.Length);
}
m_bReadNextNode = false; // ReadElementString skips end tag
return xr.ReadElementString();
}
private string ReadStringRaw(XmlReader xr)
{
m_bReadNextNode = false; // ReadElementString skips end tag
return xr.ReadElementString();
}
private bool ReadBool(XmlReader xr, bool bDefault)
{
string str = ReadString(xr);
if(str == ValTrue) return true;
else if(str == ValFalse) return false;
Debug.Assert(false);
return bDefault;
}
private PwUuid ReadUuid(XmlReader xr)
{
string str = ReadString(xr);
if(string.IsNullOrEmpty(str)) return PwUuid.Zero;
return new PwUuid(Convert.FromBase64String(str));
}
private int ReadInt(XmlReader xr, int nDefault)
{
string str = ReadString(xr);
int n;
if(StrUtil.TryParseInt(str, out n)) return n;
Debug.Assert(false);
return nDefault;
}
private uint ReadUInt(XmlReader xr, uint uDefault)
{
string str = ReadString(xr);
uint u;
if(StrUtil.TryParseUInt(str, out u)) return u;
Debug.Assert(false);
return uDefault;
}
private long ReadLong(XmlReader xr, long lDefault)
{
string str = ReadString(xr);
long l;
if(StrUtil.TryParseLong(str, out l)) return l;
Debug.Assert(false);
return lDefault;
}
private ulong ReadULong(XmlReader xr, ulong uDefault)
{
string str = ReadString(xr);
ulong u;
if(StrUtil.TryParseULong(str, out u)) return u;
Debug.Assert(false);
return uDefault;
}
private DateTime ReadTime(XmlReader xr)
{
string str = ReadString(xr);
DateTime dt;
if(TimeUtil.TryDeserializeUtc(str, out dt)) return dt;
Debug.Assert(false);
return m_dtNow;
}
private ProtectedString ReadProtectedString(XmlReader xr)
{
XorredBuffer xb = ProcessNode(xr);
if(xb != null) return new ProtectedString(true, xb);
bool bProtect = false;
if(m_format == KdbxFormat.PlainXml)
{
if(xr.MoveToAttribute(AttrProtectedInMemPlainXml))
{
string strProtect = xr.Value;
bProtect = ((strProtect != null) && (strProtect == ValTrue));
}
}
ProtectedString ps = new ProtectedString(bProtect, ReadString(xr));
return ps;
}
private ProtectedBinary ReadProtectedBinary(XmlReader xr)
{
if(xr.MoveToAttribute(AttrRef))
{
string strRef = xr.Value;
if(strRef != null)
{
ProtectedBinary pb = BinPoolGet(strRef);
if(pb != null) return pb;
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }
}
bool bCompressed = false;
if(xr.MoveToAttribute(AttrCompressed))
bCompressed = (xr.Value == ValTrue);
XorredBuffer xb = ProcessNode(xr);
if(xb != null)
{
Debug.Assert(!bCompressed); // See SubWriteValue(ProtectedBinary value)
return new ProtectedBinary(true, xb);
}
string strValue = ReadString(xr);
if(strValue.Length == 0) return new ProtectedBinary();
byte[] pbData = Convert.FromBase64String(strValue);
if(bCompressed) pbData = MemUtil.Decompress(pbData);
return new ProtectedBinary(false, pbData);
}
private void ReadUnknown(XmlReader xr)
{
Debug.Assert(false); // Unknown node!
if(xr.IsEmptyElement) return;
string strUnknownName = xr.Name;
ProcessNode(xr);
while(xr.Read())
{
if(xr.NodeType == XmlNodeType.EndElement) break;
if(xr.NodeType != XmlNodeType.Element) continue;
ReadUnknown(xr);
}
Debug.Assert(xr.Name == strUnknownName);
}
private XorredBuffer ProcessNode(XmlReader xr)
{
// Debug.Assert(xr.NodeType == XmlNodeType.Element);
XorredBuffer xb = null;
if(xr.HasAttributes)
{
if(xr.MoveToAttribute(AttrProtected))
{
if(xr.Value == ValTrue)
{
xr.MoveToElement();
string strEncrypted = ReadStringRaw(xr);
byte[] pbEncrypted;
if(strEncrypted.Length > 0)
pbEncrypted = Convert.FromBase64String(strEncrypted);
else pbEncrypted = new byte[0];
byte[] pbPad = m_randomStream.GetRandomBytes((uint)pbEncrypted.Length);
xb = new XorredBuffer(pbEncrypted, pbPad);
}
}
}
return xb;
}
private static KdbContext SwitchContext(KdbContext ctxCurrent,
KdbContext ctxNew, XmlReader xr)
{
if(xr.IsEmptyElement) return ctxCurrent;
return ctxNew;
}
}
}

View File

@ -0,0 +1,391 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
using System.Xml;
#if !KeePassLibSD
using System.IO.Compression;
#else
using KeePassLibSD;
#endif
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Interfaces;
using KeePassLib.Keys;
using KeePassLib.Resources;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
/// <summary>
/// Serialization to KeePass KDBX files.
/// </summary>
public sealed partial class KdbxFile
{
/// <summary>
/// Load a KDB file from a file.
/// </summary>
/// <param name="strFilePath">File to load.</param>
/// <param name="kdbFormat">Format specifier.</param>
/// <param name="slLogger">Status logger (optional).</param>
public void Load(string strFilePath, KdbxFormat kdbFormat, IStatusLogger slLogger)
{
IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath);
Load(IOConnection.OpenRead(ioc), kdbFormat, slLogger);
}
/// <summary>
/// Load a KDB file from a stream.
/// </summary>
/// <param name="sSource">Stream to read the data from. Must contain
/// a KDBX stream.</param>
/// <param name="kdbFormat">Format specifier.</param>
/// <param name="slLogger">Status logger (optional).</param>
public void Load(Stream sSource, KdbxFormat kdbFormat, IStatusLogger slLogger)
{
Debug.Assert(sSource != null);
if(sSource == null) throw new ArgumentNullException("sSource");
m_format = kdbFormat;
m_slLogger = slLogger;
HashingStreamEx hashedStream = new HashingStreamEx(sSource, false, null);
UTF8Encoding encNoBom = StrUtil.Utf8;
try
{
BinaryReaderEx br = null;
BinaryReaderEx brDecrypted = null;
Stream readerStream = null;
if(kdbFormat == KdbxFormat.Default)
{
br = new BinaryReaderEx(hashedStream, encNoBom, KLRes.FileCorrupted);
ReadHeader(br);
Stream sDecrypted = AttachStreamDecryptor(hashedStream);
if((sDecrypted == null) || (sDecrypted == hashedStream))
throw new SecurityException(KLRes.CryptoStreamFailed);
brDecrypted = new BinaryReaderEx(sDecrypted, encNoBom, KLRes.FileCorrupted);
byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32);
if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32))
throw new InvalidDataException();
for(int iStart = 0; iStart < 32; ++iStart)
{
if(pbStoredStartBytes[iStart] != m_pbStreamStartBytes[iStart])
throw new InvalidCompositeKeyException();
}
Stream sHashed = new HashedBlockStream(sDecrypted, false, 0,
!m_bRepairMode);
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
readerStream = new GZipStream(sHashed, CompressionMode.Decompress);
else readerStream = sHashed;
}
else if(kdbFormat == KdbxFormat.PlainXml)
readerStream = hashedStream;
else { Debug.Assert(false); throw new FormatException("KdbFormat"); }
if(kdbFormat != KdbxFormat.PlainXml) // Is an encrypted format
{
if(m_pbProtectedStreamKey == null)
{
Debug.Assert(false);
throw new SecurityException("Invalid protected stream key!");
}
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbProtectedStreamKey);
}
else m_randomStream = null; // No random stream for plain-text files
ReadXmlStreamed(readerStream, hashedStream);
// ReadXmlDom(readerStream);
readerStream.Close();
// GC.KeepAlive(br);
// GC.KeepAlive(brDecrypted);
}
catch(CryptographicException) // Thrown on invalid padding
{
throw new CryptographicException(KLRes.FileCorrupted);
}
finally { CommonCleanUpRead(sSource, hashedStream); }
}
private void CommonCleanUpRead(Stream sSource, HashingStreamEx hashedStream)
{
hashedStream.Close();
m_pbHashOfFileOnDisk = hashedStream.Hash;
sSource.Close();
// Reset memory protection settings (to always use reasonable
// defaults)
m_pwDatabase.MemoryProtection = new MemoryProtectionConfig();
// Remove old backups (this call is required here in order to apply
// the default history maintenance settings for people upgrading from
// KeePass <= 2.14 to >= 2.15; also it ensures history integrity in
// case a different application has created the KDBX file and ignored
// the history maintenance settings)
m_pwDatabase.MaintainBackups(); // Don't mark database as modified
m_pbHashOfHeader = null;
}
private void ReadHeader(BinaryReaderEx br)
{
MemoryStream msHeader = new MemoryStream();
Debug.Assert(br.CopyDataTo == null);
br.CopyDataTo = msHeader;
byte[] pbSig1 = br.ReadBytes(4);
uint uSig1 = MemUtil.BytesToUInt32(pbSig1);
byte[] pbSig2 = br.ReadBytes(4);
uint uSig2 = MemUtil.BytesToUInt32(pbSig2);
if((uSig1 == FileSignatureOld1) && (uSig2 == FileSignatureOld2))
throw new OldFormatException(PwDefs.ShortProductName + @" 1.x",
OldFormatException.OldFormatType.KeePass1x);
if((uSig1 == FileSignature1) && (uSig2 == FileSignature2)) { }
else if((uSig1 == FileSignaturePreRelease1) && (uSig2 ==
FileSignaturePreRelease2)) { }
else throw new FormatException(KLRes.FileSigInvalid);
byte[] pb = br.ReadBytes(4);
uint uVersion = MemUtil.BytesToUInt32(pb);
if((uVersion & FileVersionCriticalMask) > (FileVersion32 & FileVersionCriticalMask))
throw new FormatException(KLRes.FileVersionUnsupported +
MessageService.NewParagraph + KLRes.FileNewVerReq);
while(true)
{
if(ReadHeaderField(br) == false)
break;
}
br.CopyDataTo = null;
byte[] pbHeader = msHeader.ToArray();
msHeader.Close();
SHA256Managed sha256 = new SHA256Managed();
m_pbHashOfHeader = sha256.ComputeHash(pbHeader);
}
private bool ReadHeaderField(BinaryReaderEx brSource)
{
Debug.Assert(brSource != null);
if(brSource == null) throw new ArgumentNullException("brSource");
byte btFieldID = brSource.ReadByte();
ushort uSize = MemUtil.BytesToUInt16(brSource.ReadBytes(2));
byte[] pbData = null;
if(uSize > 0)
{
string strPrevExcpText = brSource.ReadExceptionText;
brSource.ReadExceptionText = KLRes.FileHeaderEndEarly;
pbData = brSource.ReadBytes(uSize);
brSource.ReadExceptionText = strPrevExcpText;
}
bool bResult = true;
KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID;
switch(kdbID)
{
case KdbxHeaderFieldID.EndOfHeader:
bResult = false; // Returning false indicates end of header
break;
case KdbxHeaderFieldID.CipherID:
SetCipher(pbData);
break;
case KdbxHeaderFieldID.CompressionFlags:
SetCompressionFlags(pbData);
break;
case KdbxHeaderFieldID.MasterSeed:
m_pbMasterSeed = pbData;
CryptoRandom.Instance.AddEntropy(pbData);
break;
case KdbxHeaderFieldID.TransformSeed:
m_pbTransformSeed = pbData;
CryptoRandom.Instance.AddEntropy(pbData);
break;
case KdbxHeaderFieldID.TransformRounds:
m_pwDatabase.KeyEncryptionRounds = MemUtil.BytesToUInt64(pbData);
break;
case KdbxHeaderFieldID.EncryptionIV:
m_pbEncryptionIV = pbData;
break;
case KdbxHeaderFieldID.ProtectedStreamKey:
m_pbProtectedStreamKey = pbData;
CryptoRandom.Instance.AddEntropy(pbData);
break;
case KdbxHeaderFieldID.StreamStartBytes:
m_pbStreamStartBytes = pbData;
break;
case KdbxHeaderFieldID.InnerRandomStreamID:
SetInnerRandomStreamID(pbData);
break;
default:
Debug.Assert(false);
if(m_slLogger != null)
m_slLogger.SetText(KLRes.UnknownHeaderId + @": " +
kdbID.ToString() + "!", LogStatusType.Warning);
break;
}
return bResult;
}
private void SetCipher(byte[] pbID)
{
if((pbID == null) || (pbID.Length != 16))
throw new FormatException(KLRes.FileUnknownCipher);
m_pwDatabase.DataCipherUuid = new PwUuid(pbID);
}
private void SetCompressionFlags(byte[] pbFlags)
{
int nID = (int)MemUtil.BytesToUInt32(pbFlags);
if((nID < 0) || (nID >= (int)PwCompressionAlgorithm.Count))
throw new FormatException(KLRes.FileUnknownCompression);
m_pwDatabase.Compression = (PwCompressionAlgorithm)nID;
}
private void SetInnerRandomStreamID(byte[] pbID)
{
uint uID = MemUtil.BytesToUInt32(pbID);
if(uID >= (uint)CrsAlgorithm.Count)
throw new FormatException(KLRes.FileUnknownCipher);
m_craInnerRandomStream = (CrsAlgorithm)uID;
}
private Stream AttachStreamDecryptor(Stream s)
{
MemoryStream ms = new MemoryStream();
Debug.Assert(m_pbMasterSeed.Length == 32);
if(m_pbMasterSeed.Length != 32)
throw new FormatException(KLRes.MasterSeedLengthInvalid);
ms.Write(m_pbMasterSeed, 0, 32);
byte[] pKey32 = m_pwDatabase.MasterKey.GenerateKey32(m_pbTransformSeed,
m_pwDatabase.KeyEncryptionRounds).ReadData();
if((pKey32 == null) || (pKey32.Length != 32))
throw new SecurityException(KLRes.InvalidCompositeKey);
ms.Write(pKey32, 0, 32);
SHA256Managed sha256 = new SHA256Managed();
byte[] aesKey = sha256.ComputeHash(ms.ToArray());
ms.Close();
Array.Clear(pKey32, 0, 32);
if((aesKey == null) || (aesKey.Length != 32))
throw new SecurityException(KLRes.FinalKeyCreationFailed);
ICipherEngine iEngine = CipherPool.GlobalPool.GetCipher(m_pwDatabase.DataCipherUuid);
if(iEngine == null) throw new SecurityException(KLRes.FileUnknownCipher);
return iEngine.DecryptStream(s, aesKey, m_pbEncryptionIV);
}
[Obsolete]
public static List<PwEntry> ReadEntries(PwDatabase pwDatabase, Stream msData)
{
return ReadEntries(msData);
}
/// <summary>
/// Read entries from a stream.
/// </summary>
/// <param name="msData">Input stream to read the entries from.</param>
/// <returns>Extracted entries.</returns>
public static List<PwEntry> ReadEntries(Stream msData)
{
/* KdbxFile f = new KdbxFile(pwDatabase);
f.m_format = KdbxFormat.PlainXml;
XmlDocument doc = new XmlDocument();
doc.Load(msData);
XmlElement el = doc.DocumentElement;
if(el.Name != ElemRoot) throw new FormatException();
List<PwEntry> vEntries = new List<PwEntry>();
foreach(XmlNode xmlChild in el.ChildNodes)
{
if(xmlChild.Name == ElemEntry)
{
PwEntry pe = f.ReadEntry(xmlChild);
pe.Uuid = new PwUuid(true);
foreach(PwEntry peHistory in pe.History)
peHistory.Uuid = pe.Uuid;
vEntries.Add(pe);
}
else { Debug.Assert(false); }
}
return vEntries; */
PwDatabase pd = new PwDatabase();
KdbxFile f = new KdbxFile(pd);
f.Load(msData, KdbxFormat.PlainXml, null);
List<PwEntry> vEntries = new List<PwEntry>();
foreach(PwEntry pe in pd.RootGroup.Entries)
{
pe.SetUuid(new PwUuid(true), true);
vEntries.Add(pe);
}
return vEntries;
}
}
}

View File

@ -0,0 +1,851 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Xml;
using System.Diagnostics;
using System.Security;
using System.Security.Cryptography;
using System.Drawing;
using System.Globalization;
using System.Drawing.Imaging;
#if !KeePassLibSD
using System.IO.Compression;
#else
using KeePassLibSD;
#endif
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Cryptography.Cipher;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Keys;
using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
/// <summary>
/// Serialization to KeePass KDBX files.
/// </summary>
public sealed partial class KdbxFile
{
// public void Save(string strFile, PwGroup pgDataSource, KdbxFormat format,
// IStatusLogger slLogger)
// {
// bool bMadeUnhidden = UrlUtil.UnhideFile(strFile);
//
// IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile);
// this.Save(IOConnection.OpenWrite(ioc), pgDataSource, format, slLogger);
//
// if(bMadeUnhidden) UrlUtil.HideFile(strFile, true); // Hide again
// }
/// <summary>
/// Save the contents of the current <c>PwDatabase</c> to a KDBX file.
/// </summary>
/// <param name="sSaveTo">Stream to write the KDBX file into.</param>
/// <param name="pgDataSource">Group containing all groups and
/// entries to write. If <c>null</c>, the complete database will
/// be written.</param>
/// <param name="format">Format of the file to create.</param>
/// <param name="slLogger">Logger that recieves status information.</param>
public void Save(Stream sSaveTo, PwGroup pgDataSource, KdbxFormat format,
IStatusLogger slLogger)
{
Debug.Assert(sSaveTo != null);
if(sSaveTo == null) throw new ArgumentNullException("sSaveTo");
m_format = format;
m_slLogger = slLogger;
HashingStreamEx hashedStream = new HashingStreamEx(sSaveTo, true, null);
UTF8Encoding encNoBom = StrUtil.Utf8;
CryptoRandom cr = CryptoRandom.Instance;
try
{
m_pbMasterSeed = cr.GetRandomBytes(32);
m_pbTransformSeed = cr.GetRandomBytes(32);
m_pbEncryptionIV = cr.GetRandomBytes(16);
m_pbProtectedStreamKey = cr.GetRandomBytes(32);
m_craInnerRandomStream = CrsAlgorithm.Salsa20;
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbProtectedStreamKey);
m_pbStreamStartBytes = cr.GetRandomBytes(32);
Stream writerStream;
if(m_format == KdbxFormat.Default)
{
WriteHeader(hashedStream); // Also flushes the stream
Stream sEncrypted = AttachStreamEncryptor(hashedStream);
if((sEncrypted == null) || (sEncrypted == hashedStream))
throw new SecurityException(KLRes.CryptoStreamFailed);
sEncrypted.Write(m_pbStreamStartBytes, 0, m_pbStreamStartBytes.Length);
Stream sHashed = new HashedBlockStream(sEncrypted, true);
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
writerStream = new GZipStream(sHashed, CompressionMode.Compress);
else
writerStream = sHashed;
}
else if(m_format == KdbxFormat.PlainXml)
writerStream = hashedStream;
else { Debug.Assert(false); throw new FormatException("KdbFormat"); }
m_xmlWriter = new XmlTextWriter(writerStream, encNoBom);
WriteDocument(pgDataSource);
m_xmlWriter.Flush();
m_xmlWriter.Close();
writerStream.Close();
}
finally { CommonCleanUpWrite(sSaveTo, hashedStream); }
}
private void CommonCleanUpWrite(Stream sSaveTo, HashingStreamEx hashedStream)
{
hashedStream.Close();
m_pbHashOfFileOnDisk = hashedStream.Hash;
sSaveTo.Close();
m_xmlWriter = null;
m_pbHashOfHeader = null;
}
private void WriteHeader(Stream s)
{
MemoryStream ms = new MemoryStream();
MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature1));
MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature2));
MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileVersion32));
WriteHeaderField(ms, KdbxHeaderFieldID.CipherID,
m_pwDatabase.DataCipherUuid.UuidBytes);
int nCprID = (int)m_pwDatabase.Compression;
WriteHeaderField(ms, KdbxHeaderFieldID.CompressionFlags,
MemUtil.UInt32ToBytes((uint)nCprID));
WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed);
WriteHeaderField(ms, KdbxHeaderFieldID.TransformSeed, m_pbTransformSeed);
WriteHeaderField(ms, KdbxHeaderFieldID.TransformRounds,
MemUtil.UInt64ToBytes(m_pwDatabase.KeyEncryptionRounds));
WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV);
WriteHeaderField(ms, KdbxHeaderFieldID.ProtectedStreamKey, m_pbProtectedStreamKey);
WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes, m_pbStreamStartBytes);
int nIrsID = (int)m_craInnerRandomStream;
WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID,
MemUtil.UInt32ToBytes((uint)nIrsID));
WriteHeaderField(ms, KdbxHeaderFieldID.EndOfHeader, new byte[]{
(byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' });
byte[] pbHeader = ms.ToArray();
ms.Close();
SHA256Managed sha256 = new SHA256Managed();
m_pbHashOfHeader = sha256.ComputeHash(pbHeader);
s.Write(pbHeader, 0, pbHeader.Length);
s.Flush();
}
private static void WriteHeaderField(Stream s, KdbxHeaderFieldID kdbID,
byte[] pbData)
{
s.WriteByte((byte)kdbID);
if(pbData != null)
{
ushort uLength = (ushort)pbData.Length;
MemUtil.Write(s, MemUtil.UInt16ToBytes(uLength));
if(uLength > 0) s.Write(pbData, 0, pbData.Length);
}
else MemUtil.Write(s, MemUtil.UInt16ToBytes((ushort)0));
}
private Stream AttachStreamEncryptor(Stream s)
{
MemoryStream ms = new MemoryStream();
Debug.Assert(m_pbMasterSeed != null);
Debug.Assert(m_pbMasterSeed.Length == 32);
ms.Write(m_pbMasterSeed, 0, 32);
Debug.Assert(m_pwDatabase != null);
Debug.Assert(m_pwDatabase.MasterKey != null);
ProtectedBinary pbinKey = m_pwDatabase.MasterKey.GenerateKey32(
m_pbTransformSeed, m_pwDatabase.KeyEncryptionRounds);
Debug.Assert(pbinKey != null);
if(pbinKey == null)
throw new SecurityException(KLRes.InvalidCompositeKey);
byte[] pKey32 = pbinKey.ReadData();
if((pKey32 == null) || (pKey32.Length != 32))
throw new SecurityException(KLRes.InvalidCompositeKey);
ms.Write(pKey32, 0, 32);
SHA256Managed sha256 = new SHA256Managed();
byte[] aesKey = sha256.ComputeHash(ms.ToArray());
ms.Close();
Array.Clear(pKey32, 0, 32);
Debug.Assert(CipherPool.GlobalPool != null);
ICipherEngine iEngine = CipherPool.GlobalPool.GetCipher(m_pwDatabase.DataCipherUuid);
if(iEngine == null) throw new SecurityException(KLRes.FileUnknownCipher);
return iEngine.EncryptStream(s, aesKey, m_pbEncryptionIV);
}
private void WriteDocument(PwGroup pgDataSource)
{
Debug.Assert(m_xmlWriter != null);
if(m_xmlWriter == null) throw new InvalidOperationException();
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
uint uNumGroups, uNumEntries, uCurEntry = 0;
pgRoot.GetCounts(true, out uNumGroups, out uNumEntries);
BinPoolBuild(pgRoot);
m_xmlWriter.Formatting = Formatting.Indented;
m_xmlWriter.IndentChar = '\t';
m_xmlWriter.Indentation = 1;
m_xmlWriter.WriteStartDocument(true);
m_xmlWriter.WriteStartElement(ElemDocNode);
WriteMeta();
m_xmlWriter.WriteStartElement(ElemRoot);
StartGroup(pgRoot);
Stack<PwGroup> groupStack = new Stack<PwGroup>();
groupStack.Push(pgRoot);
GroupHandler gh = delegate(PwGroup pg)
{
Debug.Assert(pg != null);
if(pg == null) throw new ArgumentNullException("pg");
while(true)
{
if(pg.ParentGroup == groupStack.Peek())
{
groupStack.Push(pg);
StartGroup(pg);
break;
}
else
{
groupStack.Pop();
if(groupStack.Count <= 0) return false;
EndGroup();
}
}
return true;
};
EntryHandler eh = delegate(PwEntry pe)
{
Debug.Assert(pe != null);
WriteEntry(pe, false);
++uCurEntry;
if(m_slLogger != null)
if(!m_slLogger.SetProgress((100 * uCurEntry) / uNumEntries))
return false;
return true;
};
if(!pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh))
throw new InvalidOperationException();
while(groupStack.Count > 1)
{
m_xmlWriter.WriteEndElement();
groupStack.Pop();
}
EndGroup();
WriteList(ElemDeletedObjects, m_pwDatabase.DeletedObjects);
m_xmlWriter.WriteEndElement(); // Root
m_xmlWriter.WriteEndElement(); // ElemDocNode
m_xmlWriter.WriteEndDocument();
}
private void WriteMeta()
{
m_xmlWriter.WriteStartElement(ElemMeta);
WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false); // Generator name
if(m_pbHashOfHeader != null)
WriteObject(ElemHeaderHash, Convert.ToBase64String(
m_pbHashOfHeader), false);
WriteObject(ElemDbName, m_pwDatabase.Name, true);
WriteObject(ElemDbNameChanged, m_pwDatabase.NameChanged);
WriteObject(ElemDbDesc, m_pwDatabase.Description, true);
WriteObject(ElemDbDescChanged, m_pwDatabase.DescriptionChanged);
WriteObject(ElemDbDefaultUser, m_pwDatabase.DefaultUserName, true);
WriteObject(ElemDbDefaultUserChanged, m_pwDatabase.DefaultUserNameChanged);
WriteObject(ElemDbMntncHistoryDays, m_pwDatabase.MaintenanceHistoryDays);
WriteObject(ElemDbColor, StrUtil.ColorToUnnamedHtml(m_pwDatabase.Color, true), false);
WriteObject(ElemDbKeyChanged, m_pwDatabase.MasterKeyChanged);
WriteObject(ElemDbKeyChangeRec, m_pwDatabase.MasterKeyChangeRec);
WriteObject(ElemDbKeyChangeForce, m_pwDatabase.MasterKeyChangeForce);
WriteList(ElemMemoryProt, m_pwDatabase.MemoryProtection);
WriteCustomIconList();
WriteObject(ElemRecycleBinEnabled, m_pwDatabase.RecycleBinEnabled);
WriteObject(ElemRecycleBinUuid, m_pwDatabase.RecycleBinUuid);
WriteObject(ElemRecycleBinChanged, m_pwDatabase.RecycleBinChanged);
WriteObject(ElemEntryTemplatesGroup, m_pwDatabase.EntryTemplatesGroup);
WriteObject(ElemEntryTemplatesGroupChanged, m_pwDatabase.EntryTemplatesGroupChanged);
WriteObject(ElemHistoryMaxItems, m_pwDatabase.HistoryMaxItems);
WriteObject(ElemHistoryMaxSize, m_pwDatabase.HistoryMaxSize);
WriteObject(ElemLastSelectedGroup, m_pwDatabase.LastSelectedGroup);
WriteObject(ElemLastTopVisibleGroup, m_pwDatabase.LastTopVisibleGroup);
WriteBinPool();
WriteList(ElemCustomData, m_pwDatabase.CustomData);
m_xmlWriter.WriteEndElement();
}
private void StartGroup(PwGroup pg)
{
m_xmlWriter.WriteStartElement(ElemGroup);
WriteObject(ElemUuid, pg.Uuid);
WriteObject(ElemName, pg.Name, true);
WriteObject(ElemNotes, pg.Notes, true);
WriteObject(ElemIcon, (int)pg.IconId);
if(pg.CustomIconUuid != PwUuid.Zero)
WriteObject(ElemCustomIconID, pg.CustomIconUuid);
WriteList(ElemTimes, pg);
WriteObject(ElemIsExpanded, pg.IsExpanded);
WriteObject(ElemGroupDefaultAutoTypeSeq, pg.DefaultAutoTypeSequence, true);
WriteObject(ElemEnableAutoType, StrUtil.BoolToStringEx(pg.EnableAutoType), false);
WriteObject(ElemEnableSearching, StrUtil.BoolToStringEx(pg.EnableSearching), false);
WriteObject(ElemLastTopVisibleEntry, pg.LastTopVisibleEntry);
}
private void EndGroup()
{
m_xmlWriter.WriteEndElement(); // Close group element
}
private void WriteEntry(PwEntry pe, bool bIsHistory)
{
Debug.Assert(pe != null); if(pe == null) throw new ArgumentNullException("pe");
m_xmlWriter.WriteStartElement(ElemEntry);
WriteObject(ElemUuid, pe.Uuid);
WriteObject(ElemIcon, (int)pe.IconId);
if(pe.CustomIconUuid != PwUuid.Zero)
WriteObject(ElemCustomIconID, pe.CustomIconUuid);
WriteObject(ElemFgColor, StrUtil.ColorToUnnamedHtml(pe.ForegroundColor, true), false);
WriteObject(ElemBgColor, StrUtil.ColorToUnnamedHtml(pe.BackgroundColor, true), false);
WriteObject(ElemOverrideUrl, pe.OverrideUrl, true);
WriteObject(ElemTags, StrUtil.TagsToString(pe.Tags, false), true);
WriteList(ElemTimes, pe);
WriteList(pe.Strings, true);
WriteList(pe.Binaries);
WriteList(ElemAutoType, pe.AutoType);
if(!bIsHistory) WriteList(ElemHistory, pe.History, true);
else { Debug.Assert(pe.History.UCount == 0); }
m_xmlWriter.WriteEndElement();
}
private void WriteList(ProtectedStringDictionary dictStrings, bool bEntryStrings)
{
Debug.Assert(dictStrings != null);
if(dictStrings == null) throw new ArgumentNullException("dictStrings");
foreach(KeyValuePair<string, ProtectedString> kvp in dictStrings)
WriteObject(kvp.Key, kvp.Value, bEntryStrings);
}
private void WriteList(ProtectedBinaryDictionary dictBinaries)
{
Debug.Assert(dictBinaries != null);
if(dictBinaries == null) throw new ArgumentNullException("dictBinaries");
foreach(KeyValuePair<string, ProtectedBinary> kvp in dictBinaries)
WriteObject(kvp.Key, kvp.Value, true);
}
private void WriteList(string name, AutoTypeConfig cfgAutoType)
{
Debug.Assert(name != null);
Debug.Assert(cfgAutoType != null);
if(cfgAutoType == null) throw new ArgumentNullException("cfgAutoType");
m_xmlWriter.WriteStartElement(name);
WriteObject(ElemAutoTypeEnabled, cfgAutoType.Enabled);
WriteObject(ElemAutoTypeObfuscation, (int)cfgAutoType.ObfuscationOptions);
if(cfgAutoType.DefaultSequence.Length > 0)
WriteObject(ElemAutoTypeDefaultSeq, cfgAutoType.DefaultSequence, true);
foreach(AutoTypeAssociation a in cfgAutoType.Associations)
WriteObject(ElemAutoTypeItem, ElemWindow, ElemKeystrokeSequence,
new KeyValuePair<string, string>(a.WindowName, a.Sequence));
m_xmlWriter.WriteEndElement();
}
private void WriteList(string name, ITimeLogger times)
{
Debug.Assert(name != null);
Debug.Assert(times != null); if(times == null) throw new ArgumentNullException("times");
m_xmlWriter.WriteStartElement(name);
WriteObject(ElemLastModTime, times.LastModificationTime);
WriteObject(ElemCreationTime, times.CreationTime);
WriteObject(ElemLastAccessTime, times.LastAccessTime);
WriteObject(ElemExpiryTime, times.ExpiryTime);
WriteObject(ElemExpires, times.Expires);
WriteObject(ElemUsageCount, times.UsageCount);
WriteObject(ElemLocationChanged, times.LocationChanged);
m_xmlWriter.WriteEndElement(); // Name
}
private void WriteList(string name, PwObjectList<PwEntry> value, bool bIsHistory)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(name);
foreach(PwEntry pe in value)
WriteEntry(pe, bIsHistory);
m_xmlWriter.WriteEndElement();
}
private void WriteList(string name, PwObjectList<PwDeletedObject> value)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(name);
foreach(PwDeletedObject pdo in value)
WriteObject(ElemDeletedObject, pdo);
m_xmlWriter.WriteEndElement();
}
private void WriteList(string name, MemoryProtectionConfig value)
{
Debug.Assert(name != null);
Debug.Assert(value != null);
m_xmlWriter.WriteStartElement(name);
WriteObject(ElemProtTitle, value.ProtectTitle);
WriteObject(ElemProtUserName, value.ProtectUserName);
WriteObject(ElemProtPassword, value.ProtectPassword);
WriteObject(ElemProtUrl, value.ProtectUrl);
WriteObject(ElemProtNotes, value.ProtectNotes);
// WriteObject(ElemProtAutoHide, value.AutoEnableVisualHiding);
m_xmlWriter.WriteEndElement();
}
private void WriteList(string name, StringDictionaryEx value)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(name);
foreach(KeyValuePair<string, string> kvp in value)
WriteObject(ElemStringDictExItem, ElemKey, ElemValue, kvp);
m_xmlWriter.WriteEndElement();
}
private void WriteCustomIconList()
{
if(m_pwDatabase.CustomIcons.Count == 0) return;
m_xmlWriter.WriteStartElement(ElemCustomIcons);
foreach(PwCustomIcon pwci in m_pwDatabase.CustomIcons)
{
m_xmlWriter.WriteStartElement(ElemCustomIconItem);
WriteObject(ElemCustomIconItemID, pwci.Uuid);
string strData = Convert.ToBase64String(pwci.ImageDataPng);
WriteObject(ElemCustomIconItemData, strData, false);
m_xmlWriter.WriteEndElement();
}
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, string value,
bool bFilterValueXmlChars)
{
Debug.Assert(name != null);
Debug.Assert(value != null);
m_xmlWriter.WriteStartElement(name);
if(bFilterValueXmlChars)
m_xmlWriter.WriteString(StrUtil.SafeXmlString(value));
else m_xmlWriter.WriteString(value);
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, bool value)
{
Debug.Assert(name != null);
WriteObject(name, value ? ValTrue : ValFalse, false);
}
private void WriteObject(string name, PwUuid value)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
WriteObject(name, Convert.ToBase64String(value.UuidBytes), false);
}
private void WriteObject(string name, int value)
{
Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString());
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, uint value)
{
Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString());
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, long value)
{
Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString());
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, ulong value)
{
Debug.Assert(name != null);
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteString(value.ToString());
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, DateTime value)
{
Debug.Assert(name != null);
WriteObject(name, TimeUtil.SerializeUtc(value), false);
}
private void WriteObject(string name, string strKeyName,
string strValueName, KeyValuePair<string, string> kvp)
{
m_xmlWriter.WriteStartElement(name);
m_xmlWriter.WriteStartElement(strKeyName);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Key));
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteStartElement(strValueName);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(kvp.Value));
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteEndElement();
}
private void WriteObject(string name, ProtectedString value, bool bIsEntryString)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(ElemString);
m_xmlWriter.WriteStartElement(ElemKey);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(name));
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteStartElement(ElemValue);
bool bProtected = value.IsProtected;
if(bIsEntryString)
{
// Adjust memory protection setting (which might be different
// from the database default, e.g. due to an import which
// didn't specify the correct setting)
if(name == PwDefs.TitleField)
bProtected = m_pwDatabase.MemoryProtection.ProtectTitle;
else if(name == PwDefs.UserNameField)
bProtected = m_pwDatabase.MemoryProtection.ProtectUserName;
else if(name == PwDefs.PasswordField)
bProtected = m_pwDatabase.MemoryProtection.ProtectPassword;
else if(name == PwDefs.UrlField)
bProtected = m_pwDatabase.MemoryProtection.ProtectUrl;
else if(name == PwDefs.NotesField)
bProtected = m_pwDatabase.MemoryProtection.ProtectNotes;
}
if(bProtected && (m_format != KdbxFormat.PlainXml))
{
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
byte[] pbEncoded = value.ReadXorredString(m_randomStream);
if(pbEncoded.Length > 0)
m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length);
}
else
{
string strValue = value.ReadString();
// If names should be localized, we need to apply the language-dependent
// string transformation here. By default, language-dependent conversions
// should be applied, otherwise characters could be rendered incorrectly
// (code page problems).
if(m_bLocalizedNames)
{
StringBuilder sb = new StringBuilder();
foreach(char ch in strValue)
{
char chMapped = ch;
// Symbols and surrogates must be moved into the correct code
// page area
if(char.IsSymbol(ch) || char.IsSurrogate(ch))
{
System.Globalization.UnicodeCategory cat = char.GetUnicodeCategory(ch);
// Map character to correct position in code page
chMapped = (char)((int)cat * 32 + ch);
}
else if(char.IsControl(ch))
{
if(ch >= 256) // Control character in high ANSI code page
{
// Some of the control characters map to corresponding ones
// in the low ANSI range (up to 255) when calling
// ToLower on them with invariant culture (see
// http://lists.ximian.com/pipermail/mono-patches/2002-February/086106.html )
chMapped = char.ToLower(ch, CultureInfo.InvariantCulture);
}
}
sb.Append(chMapped);
}
strValue = sb.ToString(); // Correct string for current code page
}
if((m_format == KdbxFormat.PlainXml) && bProtected)
m_xmlWriter.WriteAttributeString(AttrProtectedInMemPlainXml, ValTrue);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(strValue));
}
m_xmlWriter.WriteEndElement(); // ElemValue
m_xmlWriter.WriteEndElement(); // ElemString
}
private void WriteObject(string name, ProtectedBinary value, bool bAllowRef)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(ElemBinary);
m_xmlWriter.WriteStartElement(ElemKey);
m_xmlWriter.WriteString(StrUtil.SafeXmlString(name));
m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteStartElement(ElemValue);
string strRef = (bAllowRef ? BinPoolFind(value) : null);
if(strRef != null)
{
m_xmlWriter.WriteAttributeString(AttrRef, strRef);
}
else SubWriteValue(value);
m_xmlWriter.WriteEndElement(); // ElemValue
m_xmlWriter.WriteEndElement(); // ElemBinary
}
private void SubWriteValue(ProtectedBinary value)
{
if(value.IsProtected && (m_format != KdbxFormat.PlainXml))
{
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
byte[] pbEncoded = value.ReadXorredData(m_randomStream);
if(pbEncoded.Length > 0)
m_xmlWriter.WriteBase64(pbEncoded, 0, pbEncoded.Length);
}
else
{
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip)
{
m_xmlWriter.WriteAttributeString(AttrCompressed, ValTrue);
byte[] pbRaw = value.ReadData();
byte[] pbCmp = MemUtil.Compress(pbRaw);
m_xmlWriter.WriteBase64(pbCmp, 0, pbCmp.Length);
}
else
{
byte[] pbRaw = value.ReadData();
m_xmlWriter.WriteBase64(pbRaw, 0, pbRaw.Length);
}
}
}
private void WriteObject(string name, PwDeletedObject value)
{
Debug.Assert(name != null);
Debug.Assert(value != null); if(value == null) throw new ArgumentNullException("value");
m_xmlWriter.WriteStartElement(name);
WriteObject(ElemUuid, value.Uuid);
WriteObject(ElemDeletionTime, value.DeletionTime);
m_xmlWriter.WriteEndElement();
}
private void WriteBinPool()
{
m_xmlWriter.WriteStartElement(ElemBinaries);
foreach(KeyValuePair<string, ProtectedBinary> kvp in m_dictBinPool)
{
m_xmlWriter.WriteStartElement(ElemBinary);
m_xmlWriter.WriteAttributeString(AttrId, kvp.Key);
SubWriteValue(kvp.Value);
m_xmlWriter.WriteEndElement();
}
m_xmlWriter.WriteEndElement();
}
[Obsolete]
public static bool WriteEntries(Stream msOutput, PwDatabase pwDatabase,
PwEntry[] vEntries)
{
return WriteEntries(msOutput, vEntries);
}
/// <summary>
/// Write entries to a stream.
/// </summary>
/// <param name="msOutput">Output stream to which the entries will be written.</param>
/// <param name="vEntries">Entries to serialize.</param>
/// <returns>Returns <c>true</c>, if the entries were written successfully
/// to the stream.</returns>
public static bool WriteEntries(Stream msOutput, PwEntry[] vEntries)
{
/* KdbxFile f = new KdbxFile(pwDatabase);
f.m_format = KdbxFormat.PlainXml;
XmlTextWriter xtw = null;
try { xtw = new XmlTextWriter(msOutput, StrUtil.Utf8); }
catch(Exception) { Debug.Assert(false); return false; }
if(xtw == null) { Debug.Assert(false); return false; }
f.m_xmlWriter = xtw;
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = '\t';
xtw.Indentation = 1;
xtw.WriteStartDocument(true);
xtw.WriteStartElement(ElemRoot);
foreach(PwEntry pe in vEntries)
f.WriteEntry(pe, false);
xtw.WriteEndElement();
xtw.WriteEndDocument();
xtw.Flush();
xtw.Close();
return true; */
PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey());
foreach(PwEntry peCopy in vEntries)
pd.RootGroup.AddEntry(peCopy.CloneDeep(), true);
KdbxFile f = new KdbxFile(pd);
f.Save(msOutput, null, KdbxFormat.PlainXml, null);
return true;
}
}
}

View File

@ -0,0 +1,390 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Xml;
using System.Text;
using System.Globalization;
using System.IO;
using System.Diagnostics;
#if !KeePassLibSD
using System.IO.Compression;
#endif
using KeePassLib.Collections;
using KeePassLib.Cryptography;
using KeePassLib.Delegates;
using KeePassLib.Interfaces;
using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
/// <summary>
/// The <c>KdbxFile</c> class supports saving the data to various
/// formats.
/// </summary>
public enum KdbxFormat
{
/// <summary>
/// The default, encrypted file format.
/// </summary>
Default = 0,
/// <summary>
/// Use this flag when exporting data to a plain-text XML file.
/// </summary>
PlainXml
}
/// <summary>
/// Serialization to KeePass KDBX files.
/// </summary>
public sealed partial class KdbxFile
{
/// <summary>
/// File identifier, first 32-bit value.
/// </summary>
private const uint FileSignature1 = 0x9AA2D903;
/// <summary>
/// File identifier, second 32-bit value.
/// </summary>
private const uint FileSignature2 = 0xB54BFB67;
/// <summary>
/// File version of files saved by the current <c>KdbxFile</c> class.
/// KeePass 2.07 has version 1.01, 2.08 has 1.02, 2.09 has 2.00,
/// 2.10 has 2.02, 2.11 has 2.04, 2.15 has 3.00, 2.20 has 3.01.
/// The first 2 bytes are critical (i.e. loading will fail, if the
/// file version is too high), the last 2 bytes are informational.
/// </summary>
private const uint FileVersion32 = 0x00030001;
private const uint FileVersionCriticalMask = 0xFFFF0000;
// KeePass 1.x signature
private const uint FileSignatureOld1 = 0x9AA2D903;
private const uint FileSignatureOld2 = 0xB54BFB65;
// KeePass 2.x pre-release (alpha and beta) signature
private const uint FileSignaturePreRelease1 = 0x9AA2D903;
private const uint FileSignaturePreRelease2 = 0xB54BFB66;
private const string ElemDocNode = "KeePassFile";
private const string ElemMeta = "Meta";
private const string ElemRoot = "Root";
private const string ElemGroup = "Group";
private const string ElemEntry = "Entry";
private const string ElemGenerator = "Generator";
private const string ElemHeaderHash = "HeaderHash";
private const string ElemDbName = "DatabaseName";
private const string ElemDbNameChanged = "DatabaseNameChanged";
private const string ElemDbDesc = "DatabaseDescription";
private const string ElemDbDescChanged = "DatabaseDescriptionChanged";
private const string ElemDbDefaultUser = "DefaultUserName";
private const string ElemDbDefaultUserChanged = "DefaultUserNameChanged";
private const string ElemDbMntncHistoryDays = "MaintenanceHistoryDays";
private const string ElemDbColor = "Color";
private const string ElemDbKeyChanged = "MasterKeyChanged";
private const string ElemDbKeyChangeRec = "MasterKeyChangeRec";
private const string ElemDbKeyChangeForce = "MasterKeyChangeForce";
private const string ElemRecycleBinEnabled = "RecycleBinEnabled";
private const string ElemRecycleBinUuid = "RecycleBinUUID";
private const string ElemRecycleBinChanged = "RecycleBinChanged";
private const string ElemEntryTemplatesGroup = "EntryTemplatesGroup";
private const string ElemEntryTemplatesGroupChanged = "EntryTemplatesGroupChanged";
private const string ElemHistoryMaxItems = "HistoryMaxItems";
private const string ElemHistoryMaxSize = "HistoryMaxSize";
private const string ElemLastSelectedGroup = "LastSelectedGroup";
private const string ElemLastTopVisibleGroup = "LastTopVisibleGroup";
private const string ElemMemoryProt = "MemoryProtection";
private const string ElemProtTitle = "ProtectTitle";
private const string ElemProtUserName = "ProtectUserName";
private const string ElemProtPassword = "ProtectPassword";
private const string ElemProtUrl = "ProtectURL";
private const string ElemProtNotes = "ProtectNotes";
// private const string ElemProtAutoHide = "AutoEnableVisualHiding";
private const string ElemCustomIcons = "CustomIcons";
private const string ElemCustomIconItem = "Icon";
private const string ElemCustomIconItemID = "UUID";
private const string ElemCustomIconItemData = "Data";
private const string ElemAutoType = "AutoType";
private const string ElemHistory = "History";
private const string ElemName = "Name";
private const string ElemNotes = "Notes";
private const string ElemUuid = "UUID";
private const string ElemIcon = "IconID";
private const string ElemCustomIconID = "CustomIconUUID";
private const string ElemFgColor = "ForegroundColor";
private const string ElemBgColor = "BackgroundColor";
private const string ElemOverrideUrl = "OverrideURL";
private const string ElemTimes = "Times";
private const string ElemTags = "Tags";
private const string ElemCreationTime = "CreationTime";
private const string ElemLastModTime = "LastModificationTime";
private const string ElemLastAccessTime = "LastAccessTime";
private const string ElemExpiryTime = "ExpiryTime";
private const string ElemExpires = "Expires";
private const string ElemUsageCount = "UsageCount";
private const string ElemLocationChanged = "LocationChanged";
private const string ElemGroupDefaultAutoTypeSeq = "DefaultAutoTypeSequence";
private const string ElemEnableAutoType = "EnableAutoType";
private const string ElemEnableSearching = "EnableSearching";
private const string ElemString = "String";
private const string ElemBinary = "Binary";
private const string ElemKey = "Key";
private const string ElemValue = "Value";
private const string ElemAutoTypeEnabled = "Enabled";
private const string ElemAutoTypeObfuscation = "DataTransferObfuscation";
private const string ElemAutoTypeDefaultSeq = "DefaultSequence";
private const string ElemAutoTypeItem = "Association";
private const string ElemWindow = "Window";
private const string ElemKeystrokeSequence = "KeystrokeSequence";
private const string ElemBinaries = "Binaries";
private const string AttrId = "ID";
private const string AttrRef = "Ref";
private const string AttrProtected = "Protected";
private const string AttrProtectedInMemPlainXml = "ProtectInMemory";
private const string AttrCompressed = "Compressed";
private const string ElemIsExpanded = "IsExpanded";
private const string ElemLastTopVisibleEntry = "LastTopVisibleEntry";
private const string ElemDeletedObjects = "DeletedObjects";
private const string ElemDeletedObject = "DeletedObject";
private const string ElemDeletionTime = "DeletionTime";
private const string ValFalse = "False";
private const string ValTrue = "True";
private const string ElemCustomData = "CustomData";
private const string ElemStringDictExItem = "Item";
private PwDatabase m_pwDatabase; // Not null, see constructor
private XmlTextWriter m_xmlWriter = null;
private CryptoRandomStream m_randomStream = null;
private KdbxFormat m_format = KdbxFormat.Default;
private IStatusLogger m_slLogger = null;
private byte[] m_pbMasterSeed = null;
private byte[] m_pbTransformSeed = null;
private byte[] m_pbEncryptionIV = null;
private byte[] m_pbProtectedStreamKey = null;
private byte[] m_pbStreamStartBytes = null;
// ArcFourVariant only for compatibility; KeePass will default to a
// different (more secure) algorithm when *writing* databases
private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant;
private Dictionary<string, ProtectedBinary> m_dictBinPool =
new Dictionary<string, ProtectedBinary>();
private byte[] m_pbHashOfHeader = null;
private byte[] m_pbHashOfFileOnDisk = null;
private readonly DateTime m_dtNow = DateTime.Now; // Cache current time
private const uint NeutralLanguageOffset = 0x100000; // 2^20, see 32-bit Unicode specs
private const uint NeutralLanguageIDSec = 0x7DC5C; // See 32-bit Unicode specs
private const uint NeutralLanguageID = NeutralLanguageOffset + NeutralLanguageIDSec;
private static bool m_bLocalizedNames = false;
private enum KdbxHeaderFieldID : byte
{
EndOfHeader = 0,
Comment = 1,
CipherID = 2,
CompressionFlags = 3,
MasterSeed = 4,
TransformSeed = 5,
TransformRounds = 6,
EncryptionIV = 7,
ProtectedStreamKey = 8,
StreamStartBytes = 9,
InnerRandomStreamID = 10
}
public byte[] HashOfFileOnDisk
{
get { return m_pbHashOfFileOnDisk; }
}
private bool m_bRepairMode = false;
public bool RepairMode
{
get { return m_bRepairMode; }
set { m_bRepairMode = value; }
}
private string m_strDetachBins = null;
/// <summary>
/// Detach binaries when opening a file. If this isn't <c>null</c>,
/// all binaries are saved to the specified path and are removed
/// from the database.
/// </summary>
public string DetachBinaries
{
get { return m_strDetachBins; }
set { m_strDetachBins = value; }
}
/// <summary>
/// Default constructor.
/// </summary>
/// <param name="pwDataStore">The <c>PwDatabase</c> instance that the
/// class will load file data into or use to create a KDBX file.</param>
public KdbxFile(PwDatabase pwDataStore)
{
Debug.Assert(pwDataStore != null);
if(pwDataStore == null) throw new ArgumentNullException("pwDataStore");
m_pwDatabase = pwDataStore;
}
/// <summary>
/// Call this once to determine the current localization settings.
/// </summary>
public static void DetermineLanguageId()
{
// Test if localized names should be used. If localized names are used,
// the m_bLocalizedNames value must be set to true. By default, localized
// names should be used! (Otherwise characters could be corrupted
// because of different code pages).
unchecked
{
uint uTest = 0;
foreach(char ch in PwDatabase.LocalizedAppName)
uTest = uTest * 5 + ch;
m_bLocalizedNames = (uTest != NeutralLanguageID);
}
}
private void BinPoolBuild(PwGroup pgDataSource)
{
m_dictBinPool = new Dictionary<string, ProtectedBinary>();
if(pgDataSource == null) { Debug.Assert(false); return; }
EntryHandler eh = delegate(PwEntry pe)
{
foreach(PwEntry peHistory in pe.History)
{
BinPoolAdd(peHistory.Binaries);
}
BinPoolAdd(pe.Binaries);
return true;
};
pgDataSource.TraverseTree(TraversalMethod.PreOrder, null, eh);
}
private void BinPoolAdd(ProtectedBinaryDictionary dict)
{
foreach(KeyValuePair<string, ProtectedBinary> kvp in dict)
{
BinPoolAdd(kvp.Value);
}
}
private void BinPoolAdd(ProtectedBinary pb)
{
if(pb == null) { Debug.Assert(false); return; }
if(BinPoolFind(pb) != null) return; // Exists already
m_dictBinPool.Add(m_dictBinPool.Count.ToString(), pb);
}
private string BinPoolFind(ProtectedBinary pb)
{
if(pb == null) { Debug.Assert(false); return null; }
foreach(KeyValuePair<string, ProtectedBinary> kvp in m_dictBinPool)
{
if(pb.Equals(kvp.Value)) return kvp.Key;
}
return null;
}
private ProtectedBinary BinPoolGet(string strKey)
{
if(strKey == null) { Debug.Assert(false); return null; }
ProtectedBinary pb;
if(m_dictBinPool.TryGetValue(strKey, out pb)) return pb;
return null;
}
private static void SaveBinary(string strName, ProtectedBinary pb,
string strSaveDir)
{
if(pb == null) { Debug.Assert(false); return; }
if(string.IsNullOrEmpty(strName)) strName = "File.bin";
string strPath;
int iTry = 1;
do
{
strPath = UrlUtil.EnsureTerminatingSeparator(strSaveDir, false);
string strExt = UrlUtil.GetExtension(strName);
string strDesc = UrlUtil.StripExtension(strName);
strPath += strDesc;
if(iTry > 1) strPath += " (" + iTry.ToString() + ")";
if(!string.IsNullOrEmpty(strExt)) strPath += "." + strExt;
++iTry;
}
while(File.Exists(strPath));
#if !KeePassLibSD
byte[] pbData = pb.ReadData();
File.WriteAllBytes(strPath, pbData);
MemUtil.ZeroByteArray(pbData);
#else
FileStream fs = new FileStream(strPath, FileMode.Create,
FileAccess.Write, FileShare.None);
byte[] pbData = pb.ReadData();
fs.Write(pbData, 0, pbData.Length);
fs.Close();
#endif
}
}
}

View File

@ -0,0 +1,66 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using KeePassLib.Resources;
using KeePassLib.Utility;
namespace KeePassLib.Serialization
{
public sealed class OldFormatException : Exception
{
private string m_strFormat = string.Empty;
private OldFormatType m_type = OldFormatType.Unknown;
public enum OldFormatType
{
Unknown = 0,
KeePass1x = 1
}
public override string Message
{
get
{
string str = KLRes.OldFormat + ((m_strFormat.Length > 0) ?
(@" (" + m_strFormat + @")") : string.Empty) + ".";
if(m_type == OldFormatType.KeePass1x)
str += MessageService.NewParagraph + KLRes.KeePass1xHint;
return str;
}
}
public OldFormatException(string strFormatName)
{
if(strFormatName != null) m_strFormat = strFormatName;
}
public OldFormatException(string strFormatName, OldFormatType t)
{
if(strFormatName != null) m_strFormat = strFormatName;
m_type = t;
}
}
}

View File

@ -0,0 +1,400 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Drawing;
using KeePassLib.Utility;
namespace KeePassLib.Translation
{
public sealed class KpccLayout
{
public enum LayoutParameterEx
{
X, Y, Width, Height
}
private const string m_strControlRelative = @"%c";
internal const NumberStyles m_nsParser = NumberStyles.AllowLeadingSign |
NumberStyles.AllowDecimalPoint;
internal static readonly CultureInfo m_lclInv = CultureInfo.InvariantCulture;
private string m_strPosX = string.Empty;
[XmlAttribute]
[DefaultValue("")]
public string X
{
get { return m_strPosX; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strPosX = value;
}
}
private string m_strPosY = string.Empty;
[XmlAttribute]
[DefaultValue("")]
public string Y
{
get { return m_strPosY; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strPosY = value;
}
}
private string m_strSizeW = string.Empty;
[XmlAttribute]
[DefaultValue("")]
public string Width
{
get { return m_strSizeW; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strSizeW = value;
}
}
private string m_strSizeH = string.Empty;
[XmlAttribute]
[DefaultValue("")]
public string Height
{
get { return m_strSizeH; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strSizeH = value;
}
}
public void SetControlRelativeValue(LayoutParameterEx lp, string strValue)
{
Debug.Assert(strValue != null);
if(strValue == null) throw new ArgumentNullException("strValue");
if(strValue.Length > 0) strValue += m_strControlRelative;
if(lp == LayoutParameterEx.X) m_strPosX = strValue;
else if(lp == LayoutParameterEx.Y) m_strPosY = strValue;
else if(lp == LayoutParameterEx.Width) m_strSizeW = strValue;
else if(lp == LayoutParameterEx.Height) m_strSizeH = strValue;
else { Debug.Assert(false); }
}
#if !KeePassLibSD
internal void ApplyTo(Control c)
{
Debug.Assert(c != null); if(c == null) return;
int? v;
v = GetModControlParameter(c, LayoutParameterEx.X, m_strPosX);
if(v.HasValue) c.Left = v.Value;
v = GetModControlParameter(c, LayoutParameterEx.Y, m_strPosY);
if(v.HasValue) c.Top = v.Value;
v = GetModControlParameter(c, LayoutParameterEx.Width, m_strSizeW);
if(v.HasValue) c.Width = v.Value;
v = GetModControlParameter(c, LayoutParameterEx.Height, m_strSizeH);
if(v.HasValue) c.Height = v.Value;
}
private static int? GetModControlParameter(Control c, LayoutParameterEx p,
string strModParam)
{
if(strModParam.Length == 0) return null;
Debug.Assert(c.Left == c.Location.X);
Debug.Assert(c.Top == c.Location.Y);
Debug.Assert(c.Width == c.Size.Width);
Debug.Assert(c.Height == c.Size.Height);
int iPrev;
if(p == LayoutParameterEx.X) iPrev = c.Left;
else if(p == LayoutParameterEx.Y) iPrev = c.Top;
else if(p == LayoutParameterEx.Width) iPrev = c.Width;
else if(p == LayoutParameterEx.Height) iPrev = c.Height;
else { Debug.Assert(false); return null; }
double? dRel = ToControlRelativePercent(strModParam);
if(dRel.HasValue)
return (iPrev + (int)((dRel.Value * (double)iPrev) / 100.0));
Debug.Assert(false);
return null;
}
public static double? ToControlRelativePercent(string strEncoded)
{
Debug.Assert(strEncoded != null);
if(strEncoded == null) throw new ArgumentNullException("strEncoded");
if(strEncoded.Length == 0) return null;
if(strEncoded.EndsWith(m_strControlRelative))
{
string strValue = strEncoded.Substring(0, strEncoded.Length -
m_strControlRelative.Length);
if((strValue.Length == 1) && (strValue == "-"))
strValue = "0";
double dRel;
if(double.TryParse(strValue, m_nsParser, m_lclInv, out dRel))
{
return dRel;
}
else
{
Debug.Assert(false);
return null;
}
}
Debug.Assert(false);
return null;
}
#endif
public static string ToControlRelativeString(string strEncoded)
{
Debug.Assert(strEncoded != null);
if(strEncoded == null) throw new ArgumentNullException("strEncoded");
if(strEncoded.Length == 0) return string.Empty;
if(strEncoded.EndsWith(m_strControlRelative))
return strEncoded.Substring(0, strEncoded.Length -
m_strControlRelative.Length);
Debug.Assert(false);
return string.Empty;
}
}
public sealed class KPControlCustomization : IComparable<KPControlCustomization>
{
private string m_strMemberName = string.Empty;
/// <summary>
/// Member variable name of the control to be translated.
/// </summary>
[XmlAttribute]
public string Name
{
get { return m_strMemberName; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strMemberName = value;
}
}
private string m_strHash = string.Empty;
[XmlAttribute]
public string BaseHash
{
get { return m_strHash; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strHash = value;
}
}
private string m_strText = string.Empty;
[DefaultValue("")]
public string Text
{
get { return m_strText; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strText = value;
}
}
private string m_strEngText = string.Empty;
[XmlIgnore]
public string TextEnglish
{
get { return m_strEngText; }
set { m_strEngText = value; }
}
private KpccLayout m_layout = new KpccLayout();
public KpccLayout Layout
{
get { return m_layout; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_layout = value;
}
}
public int CompareTo(KPControlCustomization kpOther)
{
if(kpOther == null) { Debug.Assert(false); return 1; }
return m_strMemberName.CompareTo(kpOther.Name);
}
#if !KeePassLibSD
private static readonly Type[] m_vTextControls = new Type[] {
typeof(MenuStrip), typeof(PictureBox), typeof(ListView),
typeof(TreeView), typeof(ToolStrip), typeof(WebBrowser),
typeof(Panel), typeof(StatusStrip), typeof(ProgressBar),
typeof(NumericUpDown), typeof(TabControl)
};
public static bool ControlSupportsText(object oControl)
{
if(oControl == null) return false;
Type t = oControl.GetType();
for(int i = 0; i < m_vTextControls.Length; ++i)
{
if(t == m_vTextControls[i]) return false;
}
return true;
}
// Name-unchecked (!) property application method
internal void ApplyTo(Control c)
{
if((m_strText.Length > 0) && ControlSupportsText(c) &&
(c.Text.Length > 0))
{
c.Text = m_strText;
}
m_layout.ApplyTo(c);
}
public static string HashControl(Control c)
{
if(c == null) { Debug.Assert(false); return string.Empty; }
StringBuilder sb = new StringBuilder();
WriteCpiParam(sb, c.Text);
if(c is Form)
{
WriteCpiParam(sb, c.ClientSize.Width.ToString());
WriteCpiParam(sb, c.ClientSize.Height.ToString());
}
else // Normal control
{
WriteCpiParam(sb, c.Left.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.Top.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.Width.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.Height.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.Dock.ToString());
}
WriteCpiParam(sb, c.Font.Name);
WriteCpiParam(sb, c.Font.SizeInPoints.ToString(KpccLayout.m_lclInv));
WriteCpiParam(sb, c.Font.Bold ? "B" : "N");
WriteCpiParam(sb, c.Font.Italic ? "I" : "N");
WriteCpiParam(sb, c.Font.Underline ? "U" : "N");
WriteCpiParam(sb, c.Font.Strikeout ? "S" : "N");
WriteControlDependentParams(sb, c);
byte[] pb = StrUtil.Utf8.GetBytes(sb.ToString());
SHA256Managed sha256 = new SHA256Managed();
byte[] pbSha = sha256.ComputeHash(pb);
// Also see MatchHash
return "v1:" + Convert.ToBase64String(pbSha, 0, 3,
Base64FormattingOptions.None);
}
private static void WriteControlDependentParams(StringBuilder sb, Control c)
{
CheckBox cb = (c as CheckBox);
RadioButton rb = (c as RadioButton);
Button btn = (c as Button);
Label l = (c as Label);
LinkLabel ll = (c as LinkLabel);
if(cb != null)
{
WriteCpiParam(sb, cb.AutoSize ? "A" : "F");
WriteCpiParam(sb, cb.TextAlign.ToString());
WriteCpiParam(sb, cb.TextImageRelation.ToString());
WriteCpiParam(sb, cb.Appearance.ToString());
WriteCpiParam(sb, cb.CheckAlign.ToString());
}
else if(rb != null)
{
WriteCpiParam(sb, rb.AutoSize ? "A" : "F");
WriteCpiParam(sb, rb.TextAlign.ToString());
WriteCpiParam(sb, rb.TextImageRelation.ToString());
WriteCpiParam(sb, rb.Appearance.ToString());
WriteCpiParam(sb, rb.CheckAlign.ToString());
}
else if(btn != null)
{
WriteCpiParam(sb, btn.AutoSize ? "A" : "F");
WriteCpiParam(sb, btn.TextAlign.ToString());
WriteCpiParam(sb, btn.TextImageRelation.ToString());
}
else if(l != null)
{
WriteCpiParam(sb, l.AutoSize ? "A" : "F");
WriteCpiParam(sb, l.TextAlign.ToString());
}
else if(ll != null)
{
WriteCpiParam(sb, ll.AutoSize ? "A" : "F");
WriteCpiParam(sb, ll.TextAlign.ToString());
}
}
private static void WriteCpiParam(StringBuilder sb, string strProp)
{
sb.Append('/');
sb.Append(strProp);
}
public bool MatchHash(string strHash)
{
if(strHash == null) throw new ArgumentNullException("strHash");
// Currently only v1: is supported, see HashControl
return (m_strHash == strHash);
}
#endif
}
}

View File

@ -0,0 +1,106 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Reflection;
namespace KeePassLib.Translation
{
public sealed class KPFormCustomization
{
private string m_strFQName = string.Empty;
/// <summary>
/// The fully qualified name of the form.
/// </summary>
[XmlAttribute]
public string FullName
{
get { return m_strFQName; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strFQName = value;
}
}
private KPControlCustomization m_ccWindow = new KPControlCustomization();
public KPControlCustomization Window
{
get { return m_ccWindow; }
set { m_ccWindow = value; }
}
private List<KPControlCustomization> m_vControls =
new List<KPControlCustomization>();
[XmlArray("ChildControls")]
[XmlArrayItem("Control")]
public List<KPControlCustomization> Controls
{
get { return m_vControls; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_vControls = value;
}
}
private Form m_formEnglish = null;
[XmlIgnore]
public Form FormEnglish
{
get { return m_formEnglish; }
set { m_formEnglish = value; }
}
#if !KeePassLibSD
public void ApplyTo(Form form)
{
Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form");
// Not supported by TrlUtil (preview form):
// Debug.Assert(form.GetType().FullName == m_strFQName);
m_ccWindow.ApplyTo(form);
if(m_vControls.Count == 0) return;
foreach(Control c in form.Controls) ApplyToControl(c);
}
private void ApplyToControl(Control c)
{
foreach(KPControlCustomization cc in m_vControls)
{
if(c.Name == cc.Name)
{
cc.ApplyTo(c);
break;
}
}
foreach(Control cSub in c.Controls) ApplyToControl(cSub);
}
#endif
}
}

View File

@ -0,0 +1,99 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.Diagnostics;
namespace KeePassLib.Translation
{
public sealed class KPStringTable
{
private string m_strName = string.Empty;
[XmlAttribute]
public string Name
{
get { return m_strName; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strName = value;
}
}
private List<KPStringTableItem> m_vItems = new List<KPStringTableItem>();
[XmlArrayItem("Data")]
public List<KPStringTableItem> Strings
{
get { return m_vItems; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_vItems = value;
}
}
public Dictionary<string, string> ToDictionary()
{
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach(KPStringTableItem kpstItem in m_vItems)
{
if(kpstItem.Value.Length > 0)
dict[kpstItem.Name] = kpstItem.Value;
}
return dict;
}
#if !KeePassLibSD
public void ApplyTo(ToolStripItemCollection tsic)
{
if(tsic == null) throw new ArgumentNullException("tsic");
Dictionary<string, string> dict = this.ToDictionary();
if(dict.Count == 0) return;
this.ApplyTo(tsic, dict);
}
private void ApplyTo(ToolStripItemCollection tsic, Dictionary<string, string> dict)
{
if(tsic == null) return;
foreach(ToolStripItem tsi in tsic)
{
if(tsi.Text.Length == 0) continue;
string strTrl;
if(dict.TryGetValue(tsi.Name, out strTrl))
tsi.Text = strTrl;
ToolStripMenuItem tsmi = tsi as ToolStripMenuItem;
if((tsmi != null) && (tsmi.DropDownItems != null))
this.ApplyTo(tsmi.DropDownItems);
}
}
#endif
}
}

View File

@ -0,0 +1,51 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Xml.Serialization;
namespace KeePassLib.Translation
{
public sealed class KPStringTableItem
{
private string m_strName = string.Empty;
public string Name
{
get { return m_strName; }
set { m_strName = value; }
}
private string m_strValue = string.Empty;
public string Value
{
get { return m_strValue; }
set { m_strValue = value; }
}
private string m_strEnglish = string.Empty;
[XmlIgnore]
public string ValueEnglish
{
get { return m_strEnglish; }
set { m_strEnglish = value; }
}
}
}

View File

@ -0,0 +1,252 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Diagnostics;
using KeePassLib.Interfaces;
using KeePassLib.Utility;
#if !KeePassLibSD
using System.IO.Compression;
#else
using ICSharpCode.SharpZipLib.GZip;
#endif
namespace KeePassLib.Translation
{
[XmlRoot("Translation")]
public sealed class KPTranslation
{
public const string FileExtension = "lngx";
private KPTranslationProperties m_props = new KPTranslationProperties();
public KPTranslationProperties Properties
{
get { return m_props; }
set { m_props = value; }
}
private List<KPStringTable> m_vStringTables = new List<KPStringTable>();
[XmlArrayItem("StringTable")]
public List<KPStringTable> StringTables
{
get { return m_vStringTables; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_vStringTables = value;
}
}
private List<KPFormCustomization> m_vForms = new List<KPFormCustomization>();
[XmlArrayItem("Form")]
public List<KPFormCustomization> Forms
{
get { return m_vForms; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_vForms = value;
}
}
private string m_strUnusedText = string.Empty;
[DefaultValue("")]
public string UnusedText
{
get { return m_strUnusedText; }
set
{
if(value == null) throw new ArgumentNullException("value");
m_strUnusedText = value;
}
}
public static void SaveToFile(KPTranslation kpTrl, string strFileName,
IXmlSerializerEx xs)
{
if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFileName, FileMode.Create,
FileAccess.Write, FileShare.None);
#if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Compress);
#else
GZipOutputStream gz = new GZipOutputStream(fs);
#endif
XmlWriterSettings xws = new XmlWriterSettings();
xws.CheckCharacters = true;
xws.Encoding = StrUtil.Utf8;
xws.Indent = true;
xws.IndentChars = "\t";
XmlWriter xw = XmlWriter.Create(gz, xws);
xs.Serialize(xw, kpTrl);
xw.Close();
gz.Close();
fs.Close();
}
public static KPTranslation LoadFromFile(string strFile,
IXmlSerializerEx xs)
{
if(xs == null) throw new ArgumentNullException("xs");
FileStream fs = new FileStream(strFile, FileMode.Open,
FileAccess.Read, FileShare.Read);
#if !KeePassLibSD
GZipStream gz = new GZipStream(fs, CompressionMode.Decompress);
#else
GZipInputStream gz = new GZipInputStream(fs);
#endif
KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation);
gz.Close();
fs.Close();
return kpTrl;
}
public Dictionary<string, string> SafeGetStringTableDictionary(
string strTableName)
{
foreach(KPStringTable kpst in m_vStringTables)
{
if(kpst.Name == strTableName) return kpst.ToDictionary();
}
return new Dictionary<string, string>();
}
#if !KeePassLibSD
public void ApplyTo(Form form)
{
if(form == null) throw new ArgumentNullException("form");
if(m_props.RightToLeft)
{
try
{
form.RightToLeft = RightToLeft.Yes;
form.RightToLeftLayout = true;
}
catch(Exception) { Debug.Assert(false); }
}
string strTypeName = form.GetType().FullName;
foreach(KPFormCustomization kpfc in m_vForms)
{
if(kpfc.FullName == strTypeName)
{
kpfc.ApplyTo(form);
break;
}
}
if(m_props.RightToLeft)
{
try { RtlApplyToControls(form.Controls); }
catch(Exception) { Debug.Assert(false); }
}
}
private static void RtlApplyToControls(Control.ControlCollection cc)
{
foreach(Control c in cc)
{
if(c.Controls.Count > 0) RtlApplyToControls(c.Controls);
if(c is DateTimePicker)
((DateTimePicker)c).RightToLeftLayout = true;
else if(c is ListView)
((ListView)c).RightToLeftLayout = true;
else if(c is MonthCalendar)
((MonthCalendar)c).RightToLeftLayout = true;
else if(c is ProgressBar)
((ProgressBar)c).RightToLeftLayout = true;
else if(c is TabControl)
((TabControl)c).RightToLeftLayout = true;
else if(c is TrackBar)
((TrackBar)c).RightToLeftLayout = true;
else if(c is TreeView)
((TreeView)c).RightToLeftLayout = true;
else if(c is ToolStrip)
RtlApplyToToolStripItems(((ToolStrip)c).Items);
if((c is GroupBox) || (c is Panel)) RtlMoveChildControls(c);
}
}
private static void RtlMoveChildControls(Control cParent)
{
int nParentWidth = cParent.Size.Width;
foreach(Control c in cParent.Controls)
{
Point ptCur = c.Location;
c.Location = new Point(nParentWidth - c.Size.Width - ptCur.X, ptCur.Y);
}
}
private static void RtlApplyToToolStripItems(ToolStripItemCollection tsic)
{
foreach(ToolStripItem tsi in tsic)
{
tsi.RightToLeftAutoMirrorImage = true;
}
}
public void ApplyTo(string strTableName, ToolStripItemCollection tsic)
{
if(tsic == null) throw new ArgumentNullException("tsic");
KPStringTable kpst = null;
foreach(KPStringTable kpstEnum in m_vStringTables)
{
if(kpstEnum.Name == strTableName)
{
kpst = kpstEnum;
break;
}
}
if(kpst != null) kpst.ApplyTo(tsic);
}
#endif
}
}

View File

@ -0,0 +1,105 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
namespace KeePassLib.Translation
{
public sealed class KPTranslationProperties
{
private string m_strApp = string.Empty;
public string Application
{
get { return m_strApp; }
set { m_strApp = value; }
}
private string m_strForVersion = PwDefs.VersionString;
public string ApplicationVersion
{
get { return m_strForVersion; }
set { m_strForVersion = value; }
}
private string m_strNameEnglish = string.Empty;
public string NameEnglish
{
get { return m_strNameEnglish; }
set { m_strNameEnglish = value; }
}
private string m_strNameNative = string.Empty;
public string NameNative
{
get { return m_strNameNative; }
set { m_strNameNative = value; }
}
private string m_strIso6391Code = string.Empty;
public string Iso6391Code
{
get { return m_strIso6391Code; }
set { m_strIso6391Code = value; }
}
private bool m_bRtl = false;
public bool RightToLeft
{
get { return m_bRtl; }
set { m_bRtl = value; }
}
private string m_strAuthorName = string.Empty;
public string AuthorName
{
get { return m_strAuthorName; }
set { m_strAuthorName = value; }
}
private string m_strAuthorContact = string.Empty;
public string AuthorContact
{
get { return m_strAuthorContact; }
set { m_strAuthorContact = value; }
}
private string m_strGen = string.Empty;
public string Generator
{
get { return m_strGen; }
set { m_strGen = value; }
}
private string m_strUuid = string.Empty;
public string FileUuid
{
get { return m_strUuid; }
set { m_strUuid = value; }
}
private string m_strLastModified = string.Empty;
public string LastModified
{
get { return m_strLastModified; }
set { m_strLastModified = value; }
}
}
}

View File

@ -0,0 +1,104 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Diagnostics;
#if !KeePassLibSD
using System.IO.Compression;
#endif
namespace KeePassLib.Utility
{
/// <summary>
/// Application-wide logging services.
/// </summary>
public static class AppLogEx
{
private static StreamWriter m_swOut = null;
public static void Open(string strPrefix)
{
return; // Logging is not enabled in normal builds of KeePass!
/*
AppLogEx.Close();
Debug.Assert(strPrefix != null);
if(strPrefix == null) strPrefix = "Log";
try
{
string strDirSep = string.Empty;
strDirSep += Path.DirectorySeparatorChar;
string strTemp = UrlUtil.GetTempPath();
if(!strTemp.EndsWith(strDirSep))
strTemp += strDirSep;
string strPath = strTemp + strPrefix + "-";
Debug.Assert(strPath.IndexOf('/') < 0);
DateTime dtNow = DateTime.Now;
string strTime = dtNow.ToString("s");
strTime = strTime.Replace('T', '-');
strTime = strTime.Replace(':', '-');
strPath += strTime + "-" + Environment.TickCount.ToString(
CultureInfo.InvariantCulture) + ".log.gz";
FileStream fsOut = new FileStream(strPath, FileMode.Create,
FileAccess.Write, FileShare.None);
GZipStream gz = new GZipStream(fsOut, CompressionMode.Compress);
m_swOut = new StreamWriter(gz);
AppLogEx.Log("Started logging on " + dtNow.ToString("s") + ".");
}
catch(Exception) { Debug.Assert(false); }
*/
}
public static void Close()
{
if(m_swOut == null) return;
m_swOut.Close();
m_swOut = null;
}
public static void Log(string strText)
{
if(m_swOut == null) return;
if(strText == null) m_swOut.WriteLine();
else m_swOut.WriteLine(strText);
}
public static void Log(Exception ex)
{
if(m_swOut == null) return;
if(ex == null) m_swOut.WriteLine();
else m_swOut.WriteLine(ex.ToString());
}
}
}

View File

@ -0,0 +1,95 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
namespace KeePassLib.Utility
{
public static class GfxUtil
{
public static Image LoadImage(byte[] pb)
{
if(pb == null) throw new ArgumentNullException("pb");
MemoryStream ms = new MemoryStream(pb, false);
try { return LoadImagePriv(ms); }
catch(Exception)
{
Image imgIco = TryLoadIco(pb);
if(imgIco != null) return imgIco;
throw;
}
finally { ms.Close(); }
}
private static Image LoadImagePriv(Stream s)
{
// Image.FromStream wants the stream to be open during
// the whole lifetime of the image; as we can't guarantee
// this, we make a copy of the image
Image imgSrc = null;
try
{
#if !KeePassLibSD
imgSrc = Image.FromStream(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height,
PixelFormat.Format32bppArgb);
try
{
bmp.SetResolution(imgSrc.HorizontalResolution,
imgSrc.VerticalResolution);
Debug.Assert(bmp.Size == imgSrc.Size);
}
catch(Exception) { Debug.Assert(false); }
#else
imgSrc = new Bitmap(s);
Bitmap bmp = new Bitmap(imgSrc.Width, imgSrc.Height);
#endif
using(Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
g.DrawImage(imgSrc, 0, 0);
}
return bmp;
}
finally { if(imgSrc != null) imgSrc.Dispose(); }
}
private static Image TryLoadIco(byte[] pb)
{
#if !KeePassLibSD
MemoryStream ms = new MemoryStream(pb, false);
try { return (new Icon(ms)).ToBitmap(); }
catch(Exception) { }
finally { ms.Close(); }
#endif
return null;
}
}
}

View File

@ -0,0 +1,404 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Text;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
#if !KeePassLibSD
using System.IO.Compression;
#else
using KeePassLibSD;
#endif
namespace KeePassLib.Utility
{
/// <summary>
/// Contains static buffer manipulation and string conversion routines.
/// </summary>
public static class MemUtil
{
/// <summary>
/// Convert a hexadecimal string to a byte array. The input string must be
/// even (i.e. its length is a multiple of 2).
/// </summary>
/// <param name="strHex">String containing hexadecimal characters.</param>
/// <returns>Returns a byte array. Returns <c>null</c> if the string parameter
/// was <c>null</c> or is an uneven string (i.e. if its length isn't a
/// multiple of 2).</returns>
/// <exception cref="System.ArgumentNullException">Thrown if <paramref name="strHex" />
/// is <c>null</c>.</exception>
public static byte[] HexStringToByteArray(string strHex)
{
if(strHex == null) { Debug.Assert(false); throw new ArgumentNullException("strHex"); }
int nStrLen = strHex.Length;
if((nStrLen & 1) != 0) { Debug.Assert(false); return null; }
byte[] pb = new byte[nStrLen / 2];
byte bt;
char ch;
for(int i = 0; i < nStrLen; i += 2)
{
ch = strHex[i];
if((ch >= '0') && (ch <= '9'))
bt = (byte)(ch - '0');
else if((ch >= 'a') && (ch <= 'f'))
bt = (byte)(ch - 'a' + 10);
else if((ch >= 'A') && (ch <= 'F'))
bt = (byte)(ch - 'A' + 10);
else { Debug.Assert(false); bt = 0; }
bt <<= 4;
ch = strHex[i + 1];
if((ch >= '0') && (ch <= '9'))
bt += (byte)(ch - '0');
else if((ch >= 'a') && (ch <= 'f'))
bt += (byte)(ch - 'a' + 10);
else if((ch >= 'A') && (ch <= 'F'))
bt += (byte)(ch - 'A' + 10);
else { Debug.Assert(false); }
pb[i >> 1] = bt;
}
return pb;
}
/// <summary>
/// Convert a byte array to a hexadecimal string.
/// </summary>
/// <param name="pbArray">Input byte array.</param>
/// <returns>Returns the hexadecimal string representing the byte
/// array. Returns <c>null</c>, if the input byte array was <c>null</c>. Returns
/// an empty string, if the input byte array has length 0.</returns>
public static string ByteArrayToHexString(byte[] pbArray)
{
if(pbArray == null) return null;
int nLen = pbArray.Length;
if(nLen == 0) return string.Empty;
StringBuilder sb = new StringBuilder();
byte bt, btHigh, btLow;
for(int i = 0; i < nLen; ++i)
{
bt = pbArray[i];
btHigh = bt; btHigh >>= 4;
btLow = (byte)(bt & 0x0F);
if(btHigh >= 10) sb.Append((char)('A' + btHigh - 10));
else sb.Append((char)('0' + btHigh));
if(btLow >= 10) sb.Append((char)('A' + btLow - 10));
else sb.Append((char)('0' + btLow));
}
return sb.ToString();
}
/// <summary>
/// Set all bytes in a byte array to zero.
/// </summary>
/// <param name="pbArray">Input array. All bytes of this array will be set
/// to zero.</param>
public static void ZeroByteArray(byte[] pbArray)
{
Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray");
// for(int i = 0; i < pbArray.Length; ++i)
// pbArray[i] = 0;
Array.Clear(pbArray, 0, pbArray.Length);
}
/// <summary>
/// Convert 2 bytes to a 16-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes. Array must contain at least 2 bytes.</param>
/// <returns>16-bit unsigned integer.</returns>
public static ushort BytesToUInt16(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 2));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 2) throw new ArgumentException();
return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8));
}
/// <summary>
/// Convert 4 bytes to a 32-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>32-bit unsigned integer.</returns>
public static uint BytesToUInt32(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 4));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 4) throw new ArgumentException("Input array must contain 4 bytes!");
return (uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) |
((uint)pb[3] << 24);
}
/// <summary>
/// Convert 8 bytes to a 64-bit unsigned integer using Little-Endian
/// encoding.
/// </summary>
/// <param name="pb">Input bytes.</param>
/// <returns>64-bit unsigned integer.</returns>
public static ulong BytesToUInt64(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 8));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 8) throw new ArgumentException();
return (ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) |
((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) |
((ulong)pb[6] << 48) | ((ulong)pb[7] << 56);
}
/// <summary>
/// Convert a 16-bit unsigned integer to 2 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">16-bit input word.</param>
/// <returns>Two bytes representing the 16-bit value.</returns>
public static byte[] UInt16ToBytes(ushort uValue)
{
byte[] pb = new byte[2];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
}
return pb;
}
/// <summary>
/// Convert a 32-bit unsigned integer to 4 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">32-bit input word.</param>
/// <returns>Four bytes representing the 32-bit value.</returns>
public static byte[] UInt32ToBytes(uint uValue)
{
byte[] pb = new byte[4];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
pb[2] = (byte)(uValue >> 16);
pb[3] = (byte)(uValue >> 24);
}
return pb;
}
/// <summary>
/// Convert a 64-bit unsigned integer to 8 bytes using Little-Endian
/// encoding.
/// </summary>
/// <param name="uValue">64-bit input word.</param>
/// <returns>Eight bytes representing the 64-bit value.</returns>
public static byte[] UInt64ToBytes(ulong uValue)
{
byte[] pb = new byte[8];
unchecked
{
pb[0] = (byte)uValue;
pb[1] = (byte)(uValue >> 8);
pb[2] = (byte)(uValue >> 16);
pb[3] = (byte)(uValue >> 24);
pb[4] = (byte)(uValue >> 32);
pb[5] = (byte)(uValue >> 40);
pb[6] = (byte)(uValue >> 48);
pb[7] = (byte)(uValue >> 56);
}
return pb;
}
public static bool ArraysEqual(byte[] x, byte[] y)
{
// Return false if one of them is null (not comparable)!
if((x == null) || (y == null)) { Debug.Assert(false); return false; }
if(x.Length != y.Length) return false;
for(int i = 0; i < x.Length; ++i)
{
if(x[i] != y[i]) return false;
}
return true;
}
public static void XorArray(byte[] pbSource, int nSourceOffset,
byte[] pbBuffer, int nBufferOffset, int nLength)
{
if(pbSource == null) throw new ArgumentNullException("pbSource");
if(nSourceOffset < 0) throw new ArgumentException();
if(pbBuffer == null) throw new ArgumentNullException("pbBuffer");
if(nBufferOffset < 0) throw new ArgumentException();
if(nLength < 0) throw new ArgumentException();
if((nSourceOffset + nLength) > pbSource.Length) throw new ArgumentException();
if((nBufferOffset + nLength) > pbBuffer.Length) throw new ArgumentException();
for(int i = 0; i < nLength; ++i)
pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i];
}
public static void CopyStream(Stream sSource, Stream sTarget)
{
Debug.Assert((sSource != null) && (sTarget != null));
if(sSource == null) throw new ArgumentNullException("sSource");
if(sTarget == null) throw new ArgumentNullException("sTarget");
const int nBufSize = 4096;
byte[] pbBuf = new byte[nBufSize];
while(true)
{
int nRead = sSource.Read(pbBuf, 0, nBufSize);
if(nRead == 0) break;
sTarget.Write(pbBuf, 0, nRead);
}
// Do not close any of the streams
}
public static byte[] Read(Stream s, int nCount)
{
if(s == null) throw new ArgumentNullException("s");
if(nCount < 0) throw new ArgumentOutOfRangeException("nCount");
byte[] pb = new byte[nCount];
int iOffset = 0;
while(nCount > 0)
{
int iRead = s.Read(pb, iOffset, nCount);
if(iRead == 0) break;
iOffset += iRead;
nCount -= iRead;
}
if(iOffset != pb.Length)
{
byte[] pbPart = new byte[iOffset];
Array.Copy(pb, pbPart, iOffset);
return pbPart;
}
return pb;
}
public static void Write(Stream s, byte[] pbData)
{
if(s == null) { Debug.Assert(false); return; }
if(pbData == null) { Debug.Assert(false); return; }
s.Write(pbData, 0, pbData.Length);
}
public static byte[] Compress(byte[] pbData)
{
if(pbData == null) throw new ArgumentNullException("pbData");
if(pbData.Length == 0) return pbData;
MemoryStream msCompressed = new MemoryStream();
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress);
MemoryStream msSource = new MemoryStream(pbData, false);
MemUtil.CopyStream(msSource, gz);
gz.Close();
msSource.Close();
byte[] pbCompressed = msCompressed.ToArray();
msCompressed.Close();
return pbCompressed;
}
public static byte[] Decompress(byte[] pbCompressed)
{
if(pbCompressed == null) throw new ArgumentNullException("pbCompressed");
if(pbCompressed.Length == 0) return pbCompressed;
MemoryStream msCompressed = new MemoryStream(pbCompressed, false);
GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress);
MemoryStream msData = new MemoryStream();
MemUtil.CopyStream(gz, msData);
gz.Close();
msCompressed.Close();
byte[] pbData = msData.ToArray();
msData.Close();
return pbData;
}
public static int IndexOf<T>(T[] vHaystack, T[] vNeedle)
where T : IEquatable<T>
{
if(vHaystack == null) throw new ArgumentNullException("vHaystack");
if(vNeedle == null) throw new ArgumentNullException("vNeedle");
if(vNeedle.Length == 0) return 0;
for(int i = 0; i <= (vHaystack.Length - vNeedle.Length); ++i)
{
bool bFound = true;
for(int m = 0; m < vNeedle.Length; ++m)
{
if(!vHaystack[i + m].Equals(vNeedle[m]))
{
bFound = false;
break;
}
}
if(bFound) return i;
}
return -1;
}
public static T[] Mid<T>(T[] v, int iOffset, int iLength)
{
if(v == null) throw new ArgumentNullException("v");
if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset");
if(iLength < 0) throw new ArgumentOutOfRangeException("iLength");
if(iOffset + iLength > v.Length) throw new ArgumentException();
T[] r = new T[iLength];
Array.Copy(v, iOffset, r, 0, iLength);
return r;
}
}
}

View File

@ -0,0 +1,428 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Collections.Specialized;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using KeePassLib.Resources;
using KeePassLib.Serialization;
namespace KeePassLib.Utility
{
public sealed class MessageServiceEventArgs : EventArgs
{
private string m_strTitle = string.Empty;
private string m_strText = string.Empty;
private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
public string Title { get { return m_strTitle; } }
public string Text { get { return m_strText; } }
public MessageBoxButtons Buttons { get { return m_msgButtons; } }
public MessageBoxIcon Icon { get { return m_msgIcon; } }
public MessageServiceEventArgs() { }
public MessageServiceEventArgs(string strTitle, string strText,
MessageBoxButtons msgButtons, MessageBoxIcon msgIcon)
{
m_strTitle = (strTitle ?? string.Empty);
m_strText = (strText ?? string.Empty);
m_msgButtons = msgButtons;
m_msgIcon = msgIcon;
}
}
public static class MessageService
{
private static volatile uint m_uCurrentMessageCount = 0;
#if !KeePassLibSD
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Information;
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;
private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading |
MessageBoxOptions.RightAlign);
#else
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
#endif
private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
public static string NewLine
{
#if !KeePassLibSD
get { return Environment.NewLine; }
#else
get { return "\r\n"; }
#endif
}
public static string NewParagraph
{
#if !KeePassLibSD
get { return Environment.NewLine + Environment.NewLine; }
#else
get { return "\r\n\r\n"; }
#endif
}
public static uint CurrentMessageCount
{
get { return m_uCurrentMessageCount; }
}
public static event EventHandler<MessageServiceEventArgs> MessageShowing;
private static string ObjectsToMessage(object[] vLines)
{
return ObjectsToMessage(vLines, false);
}
private static string ObjectsToMessage(object[] vLines, bool bFullExceptions)
{
if(vLines == null) return string.Empty;
string strNewPara = MessageService.NewParagraph;
StringBuilder sbText = new StringBuilder();
bool bSeparator = false;
foreach(object obj in vLines)
{
if(obj == null) continue;
string strAppend = null;
Exception exObj = (obj as Exception);
string strObj = (obj as string);
#if !KeePassLibSD
StringCollection scObj = (obj as StringCollection);
#endif
if(exObj != null)
{
if(bFullExceptions)
strAppend = StrUtil.FormatException(exObj);
else if((exObj.Message != null) && (exObj.Message.Length > 0))
strAppend = exObj.Message;
}
#if !KeePassLibSD
else if(scObj != null)
{
StringBuilder sb = new StringBuilder();
foreach(string strCollLine in scObj)
{
if(sb.Length > 0) sb.AppendLine();
sb.Append(strCollLine.TrimEnd());
}
strAppend = sb.ToString();
}
#endif
else if(strObj != null)
strAppend = strObj;
else
strAppend = obj.ToString();
if(!string.IsNullOrEmpty(strAppend))
{
if(bSeparator) sbText.Append(strNewPara);
else bSeparator = true;
sbText.Append(strAppend);
}
}
return sbText.ToString();
}
#if !KeePassLibSD
internal static Form GetTopForm()
{
FormCollection fc = Application.OpenForms;
if((fc == null) || (fc.Count == 0)) return null;
return fc[fc.Count - 1];
}
#endif
private static DialogResult SafeShowMessageBox(string strText, string strTitle,
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{
#if KeePassLibSD
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else
IWin32Window wnd = null;
try
{
Form f = GetTopForm();
if((f != null) && f.InvokeRequired)
return (DialogResult)f.Invoke(new SafeShowMessageBoxInternalDelegate(
SafeShowMessageBoxInternal), f, strText, strTitle, mb, mi, mdb);
else wnd = f;
}
catch(Exception) { Debug.Assert(false); }
if(wnd == null)
{
if(StrUtil.RightToLeft)
return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
}
try
{
if(StrUtil.RightToLeft)
return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(wnd, strText, strTitle, mb, mi, mdb);
}
catch(Exception) { Debug.Assert(false); }
if(StrUtil.RightToLeft)
return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#endif
}
#if !KeePassLibSD
internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb);
internal static DialogResult SafeShowMessageBoxInternal(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb)
{
if(StrUtil.RightToLeft)
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
}
#endif
public static void ShowInfo(params object[] vLines)
{
ShowInfoEx(null, vLines);
}
public static void ShowInfoEx(string strTitle, params object[] vLines)
{
++m_uCurrentMessageCount;
strTitle = (strTitle ?? PwDefs.ShortProductName);
string strText = ObjectsToMessage(vLines);
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiInfo));
SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiInfo,
MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount;
}
public static void ShowWarning(params object[] vLines)
{
ShowWarningPriv(vLines, false);
}
internal static void ShowWarningExcp(params object[] vLines)
{
ShowWarningPriv(vLines, true);
}
private static void ShowWarningPriv(object[] vLines, bool bFullExceptions)
{
++m_uCurrentMessageCount;
string strTitle = PwDefs.ShortProductName;
string strText = ObjectsToMessage(vLines, bFullExceptions);
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiWarning));
SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiWarning,
MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount;
}
public static void ShowFatal(params object[] vLines)
{
++m_uCurrentMessageCount;
string strTitle = PwDefs.ShortProductName + @" - " + KLRes.FatalError;
string strText = KLRes.FatalErrorText + MessageService.NewParagraph +
KLRes.ErrorInClipboard + MessageService.NewParagraph +
// Please send it to the KeePass developers.
// KLRes.ErrorFeedbackRequest + MessageService.NewParagraph +
ObjectsToMessage(vLines);
try
{
#if !KeePassLibSD
Clipboard.Clear();
Clipboard.SetText(ObjectsToMessage(vLines, true));
#else
Clipboard.SetDataObject(ObjectsToMessage(vLines, true));
#endif
}
catch(Exception) { Debug.Assert(false); }
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitle, strText, MessageBoxButtons.OK, m_mbiFatal));
SafeShowMessageBox(strText, strTitle, MessageBoxButtons.OK, m_mbiFatal,
MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount;
}
public static DialogResult Ask(string strText, string strTitle,
MessageBoxButtons mbb)
{
++m_uCurrentMessageCount;
string strTextEx = (strText ?? string.Empty);
string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, mbb, m_mbiQuestion));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
m_mbiQuestion, MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount;
return dr;
}
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
{
++m_uCurrentMessageCount;
string strTextEx = (strText ?? string.Empty);
string strTitleEx = (strTitle ?? PwDefs.ShortProductName);
if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, m_mbiQuestion));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, m_mbiQuestion, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount;
return (dr == DialogResult.Yes);
}
public static bool AskYesNo(string strText, string strTitle)
{
return AskYesNo(strText, strTitle, true);
}
public static bool AskYesNo(string strText)
{
return AskYesNo(strText, null, true);
}
public static void ShowLoadWarning(string strFilePath, Exception ex)
{
ShowLoadWarning(strFilePath, ex, false);
}
public static void ShowLoadWarning(string strFilePath, Exception ex,
bool bFullException)
{
string str = string.Empty;
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileLoadFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
{
str += MessageService.NewParagraph;
if(!bFullException) str += ex.Message;
else str += ObjectsToMessage(new object[] { ex }, true);
}
ShowWarning(str);
}
public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
{
if(ioConnection != null)
ShowLoadWarning(ioConnection.GetDisplayName(), ex, false);
else ShowWarning(ex);
}
public static void ShowSaveWarning(string strFilePath, Exception ex,
bool bCorruptionWarning)
{
FileLockException fl = (ex as FileLockException);
if(fl != null)
{
ShowWarning(fl.Message);
return;
}
string str = string.Empty;
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
str += MessageService.NewParagraph + ex.Message;
if(bCorruptionWarning)
str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
ShowWarning(str);
}
public static void ShowSaveWarning(IOConnectionInfo ioConnection, Exception ex,
bool bCorruptionWarning)
{
if(ioConnection != null)
ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
else ShowWarning(ex);
}
public static void ExternalIncrementMessageCount()
{
++m_uCurrentMessageCount;
}
public static void ExternalDecrementMessageCount()
{
--m_uCurrentMessageCount;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,222 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.Diagnostics;
namespace KeePassLib.Utility
{
/// <summary>
/// Contains various static time structure manipulation and conversion
/// routines.
/// </summary>
public static class TimeUtil
{
/// <summary>
/// Length of a compressed <c>PW_TIME</c> structure in bytes.
/// </summary>
public const int PwTimeLength = 7;
/// <summary>
/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits,
/// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6
/// bits, second 6 bits.
/// </summary>
/// <param name="dt"></param>
/// <returns></returns>
public static byte[] PackTime(DateTime dt)
{
byte[] pb = new byte[5];
// Pack time to 5 byte structure:
// Byte bits: 11111111 22222222 33333333 44444444 55555555
// Contents : 00YYYYYY YYYYYYMM MMDDDDDH HHHHMMMM MMSSSSSS
pb[0] = (byte)((dt.Year >> 6) & 0x3F);
pb[1] = (byte)(((dt.Year & 0x3F) << 2) | ((dt.Month >> 2) & 0x03));
pb[2] = (byte)(((dt.Month & 0x03) << 6) | ((dt.Day & 0x1F) << 1) |
((dt.Hour >> 4) & 0x01));
pb[3] = (byte)(((dt.Hour & 0x0F) << 4) | ((dt.Minute >> 2) & 0x0F));
pb[4] = (byte)(((dt.Minute & 0x03) << 6) | (dt.Second & 0x3F));
return pb;
}
/// <summary>
/// Unpack a packed time (5 bytes, packed by the <c>PackTime</c>
/// member function) to a <c>DateTime</c> object.
/// </summary>
/// <param name="pb">Packed time, 5 bytes.</param>
/// <returns>Unpacked <c>DateTime</c> object.</returns>
public static DateTime UnpackTime(byte[] pb)
{
Debug.Assert((pb != null) && (pb.Length == 5));
if(pb == null) throw new ArgumentNullException("pb");
if(pb.Length != 5) throw new ArgumentException();
int n1 = pb[0], n2 = pb[1], n3 = pb[2], n4 = pb[3], n5 = pb[4];
// Unpack 5 byte structure to date and time
int nYear = (n1 << 6) | (n2 >> 2);
int nMonth = ((n2 & 0x00000003) << 2) | (n3 >> 6);
int nDay = (n3 >> 1) & 0x0000001F;
int nHour = ((n3 & 0x00000001) << 4) | (n4 >> 4);
int nMinute = ((n4 & 0x0000000F) << 2) | (n5 >> 6);
int nSecond = n5 & 0x0000003F;
return new DateTime(nYear, nMonth, nDay, nHour, nMinute, nSecond);
}
/// <summary>
/// Pack a <c>DateTime</c> object into 7 bytes (<c>PW_TIME</c>).
/// </summary>
/// <param name="dt">Object to be encoded.</param>
/// <returns>Packed time, 7 bytes (<c>PW_TIME</c>).</returns>
public static byte[] PackPwTime(DateTime dt)
{
Debug.Assert(PwTimeLength == 7);
byte[] pb = new byte[7];
pb[0] = (byte)(dt.Year & 0xFF);
pb[1] = (byte)(dt.Year >> 8);
pb[2] = (byte)dt.Month;
pb[3] = (byte)dt.Day;
pb[4] = (byte)dt.Hour;
pb[5] = (byte)dt.Minute;
pb[6] = (byte)dt.Second;
return pb;
}
/// <summary>
/// Unpack a packed time (7 bytes, <c>PW_TIME</c>) to a <c>DateTime</c> object.
/// </summary>
/// <param name="pb">Packed time, 7 bytes.</param>
/// <returns>Unpacked <c>DateTime</c> object.</returns>
public static DateTime UnpackPwTime(byte[] pb)
{
Debug.Assert(PwTimeLength == 7);
Debug.Assert(pb != null); if(pb == null) throw new ArgumentNullException("pb");
Debug.Assert(pb.Length == 7); if(pb.Length != 7) throw new ArgumentException();
return new DateTime(((int)pb[1] << 8) | (int)pb[0], (int)pb[2], (int)pb[3],
(int)pb[4], (int)pb[5], (int)pb[6]);
}
/// <summary>
/// Convert a <c>DateTime</c> object to a displayable string.
/// </summary>
/// <param name="dt"><c>DateTime</c> object to convert to a string.</param>
/// <returns>String representing the specified <c>DateTime</c> object.</returns>
public static string ToDisplayString(DateTime dt)
{
return dt.ToString();
}
public static string ToDisplayStringDateOnly(DateTime dt)
{
return dt.ToString("d");
}
public static DateTime FromDisplayString(string strDisplay)
{
DateTime dt;
#if !KeePassLibSD
if(DateTime.TryParse(strDisplay, out dt)) return dt;
#else
try { dt = DateTime.Parse(strDisplay); return dt; }
catch(Exception) { }
#endif
Debug.Assert(false);
return DateTime.Now;
}
public static string SerializeUtc(DateTime dt)
{
string str = dt.ToUniversalTime().ToString("s");
if(str.EndsWith("Z") == false) str += "Z";
return str;
}
public static bool TryDeserializeUtc(string str, out DateTime dt)
{
if(str == null) throw new ArgumentNullException("str");
if(str.EndsWith("Z")) str = str.Substring(0, str.Length - 1);
bool bResult = StrUtil.TryParseDateTime(str, out dt);
if(bResult) dt = dt.ToLocalTime();
return bResult;
}
private static DateTime? m_dtUnixRoot = null;
public static DateTime ConvertUnixTime(double dtUnix)
{
try
{
if(!m_dtUnixRoot.HasValue)
m_dtUnixRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0,
DateTimeKind.Utc)).ToLocalTime();
return m_dtUnixRoot.Value.AddSeconds(dtUnix);
}
catch(Exception) { Debug.Assert(false); }
return DateTime.Now;
}
#if !KeePassLibSD
private static string[] m_vUSMonths = null;
/// <summary>
/// Parse a US textual date string, like e.g. "January 02, 2012".
/// </summary>
public static DateTime? ParseUSTextDate(string strDate)
{
if(strDate == null) { Debug.Assert(false); return null; }
if(m_vUSMonths == null)
m_vUSMonths = new string[]{ "January", "February", "March",
"April", "May", "June", "July", "August", "September",
"October", "November", "December" };
string str = strDate.Trim();
for(int i = 0; i < m_vUSMonths.Length; ++i)
{
if(str.StartsWith(m_vUSMonths[i], StrUtil.CaseIgnoreCmp))
{
str = str.Substring(m_vUSMonths[i].Length);
string[] v = str.Split(new char[]{ ',', ';' });
if((v == null) || (v.Length != 2)) return null;
string strDay = v[0].Trim().TrimStart('0');
int iDay, iYear;
if(int.TryParse(strDay, out iDay) &&
int.TryParse(v[1].Trim(), out iYear))
return new DateTime(iYear, i + 1, iDay);
else { Debug.Assert(false); return null; }
}
}
return null;
}
#endif
}
}

View File

@ -0,0 +1,609 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2012 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.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;
using KeePassLib.Native;
namespace KeePassLib.Utility
{
/// <summary>
/// A class containing various static path utility helper methods (like
/// stripping extension from a file, etc.).
/// </summary>
public static class UrlUtil
{
private static readonly char[] m_vDirSeps = new char[] { '\\', '/',
Path.DirectorySeparatorChar };
/// <summary>
/// Get the directory (path) of a file name. The returned string is
/// terminated by a directory separator character. Example:
/// passing <c>C:\\My Documents\\My File.kdb</c> in <paramref name="strFile" />
/// would produce this string: <c>C:\\My Documents\\</c>.
/// </summary>
/// <param name="strFile">Full path of a file.</param>
/// <param name="bAppendTerminatingChar">Append a terminating directory separator
/// character to the returned path.</param>
/// <param name="bEnsureValidDirSpec">If <c>true</c>, the returned path
/// is guaranteed to be a valid directory path (for example <c>X:\\</c> instead
/// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />).
/// This should only be set to <c>true</c>, if the returned path is directly
/// passed to some directory API.</param>
/// <returns>Directory of the file. The return value is an empty string
/// (<c>""</c>) if the input parameter is <c>null</c>.</returns>
public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar,
bool bEnsureValidDirSpec)
{
Debug.Assert(strFile != null);
if(strFile == null) throw new ArgumentNullException("strFile");
int nLastSep = strFile.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return strFile; // None
if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') &&
(strFile[2] == '\\')) // Length >= 3 and Windows root directory
bAppendTerminatingChar = true;
if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep);
return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), false);
}
/// <summary>
/// Gets the file name of the specified file (full path). Example:
/// if <paramref name="strPath" /> is <c>C:\\My Documents\\My File.kdb</c>
/// the returned string is <c>My File.kdb</c>.
/// </summary>
/// <param name="strPath">Full path of a file.</param>
/// <returns>File name of the specified file. The return value is
/// an empty string (<c>""</c>) if the input parameter is <c>null</c>.</returns>
public static string GetFileName(string strPath)
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastSep = strPath.LastIndexOfAny(m_vDirSeps);
if(nLastSep < 0) return strPath;
if(nLastSep >= (strPath.Length - 1)) return string.Empty;
return strPath.Substring(nLastSep + 1);
}
/// <summary>
/// Strip the extension of a file.
/// </summary>
/// <param name="strPath">Full path of a file with extension.</param>
/// <returns>File name without extension.</returns>
public static string StripExtension(string strPath)
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
int nLastExtDot = strPath.LastIndexOf('.');
if(nLastExtDot <= nLastDirSep) return strPath;
return strPath.Substring(0, nLastExtDot);
}
/// <summary>
/// Get the extension of a file.
/// </summary>
/// <param name="strPath">Full path of a file with extension.</param>
/// <returns>Extension without prepending dot.</returns>
public static string GetExtension(string strPath)
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLastDirSep = strPath.LastIndexOfAny(m_vDirSeps);
int nLastExtDot = strPath.LastIndexOf('.');
if(nLastExtDot <= nLastDirSep) return string.Empty;
if(nLastExtDot == (strPath.Length - 1)) return string.Empty;
return strPath.Substring(nLastExtDot + 1);
}
/// <summary>
/// Ensure that a path is terminated with a directory separator character.
/// </summary>
/// <param name="strPath">Input path.</param>
/// <param name="bUrl">If <c>true</c>, a slash (<c>/</c>) is appended to
/// the string if it's not terminated already. If <c>false</c>, the
/// default system directory separator character is used.</param>
/// <returns>Path having a directory separator as last character.</returns>
public static string EnsureTerminatingSeparator(string strPath, bool bUrl)
{
Debug.Assert(strPath != null); if(strPath == null) throw new ArgumentNullException("strPath");
int nLength = strPath.Length;
if(nLength <= 0) return string.Empty;
char chLast = strPath[nLength - 1];
for(int i = 0; i < m_vDirSeps.Length; ++i)
{
if(chLast == m_vDirSeps[i]) return strPath;
}
if(bUrl) return (strPath + '/');
return (strPath + Path.DirectorySeparatorChar);
}
/* /// <summary>
/// File access mode enumeration. Used by the <c>FileAccessible</c>
/// method.
/// </summary>
public enum FileAccessMode
{
/// <summary>
/// Opening a file in read mode. The specified file must exist.
/// </summary>
Read = 0,
/// <summary>
/// Opening a file in create mode. If the file exists already, it
/// will be overwritten. If it doesn't exist, it will be created.
/// The return value is <c>true</c>, if data can be written to the
/// file.
/// </summary>
Create
} */
/* /// <summary>
/// Test if a specified path is accessible, either in read or write mode.
/// </summary>
/// <param name="strFilePath">Path to test.</param>
/// <param name="fMode">Requested file access mode.</param>
/// <returns>Returns <c>true</c> if the specified path is accessible in
/// the requested mode, otherwise the return value is <c>false</c>.</returns>
public static bool FileAccessible(string strFilePath, FileAccessMode fMode)
{
Debug.Assert(strFilePath != null);
if(strFilePath == null) throw new ArgumentNullException("strFilePath");
if(fMode == FileAccessMode.Read)
{
FileStream fs;
try { fs = File.OpenRead(strFilePath); }
catch(Exception) { return false; }
if(fs == null) return false;
fs.Close();
return true;
}
else if(fMode == FileAccessMode.Create)
{
FileStream fs;
try { fs = File.Create(strFilePath); }
catch(Exception) { return false; }
if(fs == null) return false;
fs.Close();
return true;
}
return false;
} */
public static string GetQuotedAppPath(string strPath)
{
int nFirst = strPath.IndexOf('\"');
int nSecond = strPath.IndexOf('\"', nFirst + 1);
if((nFirst >= 0) && (nSecond >= 0))
return strPath.Substring(nFirst + 1, nSecond - nFirst - 1);
return strPath;
}
public static string FileUrlToPath(string strUrl)
{
Debug.Assert(strUrl != null);
if(strUrl == null) throw new ArgumentNullException("strUrl");
string str = strUrl;
if(str.StartsWith(@"file:///", StrUtil.CaseIgnoreCmp))
str = str.Substring(8, str.Length - 8);
str = str.Replace('/', Path.DirectorySeparatorChar);
return str;
}
public static bool UnhideFile(string strFile)
{
#if KeePassLibSD
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
try
{
FileAttributes fa = File.GetAttributes(strFile);
if((long)(fa & FileAttributes.Hidden) == 0) return false;
return HideFile(strFile, false);
}
catch(Exception) { }
return false;
#endif
}
public static bool HideFile(string strFile, bool bHide)
{
#if KeePassLibSD
return false;
#else
if(strFile == null) throw new ArgumentNullException("strFile");
try
{
FileAttributes fa = File.GetAttributes(strFile);
if(bHide) fa = ((fa & ~FileAttributes.Normal) | FileAttributes.Hidden);
else // Unhide
{
fa &= ~FileAttributes.Hidden;
if((long)fa == 0) fa |= FileAttributes.Normal;
}
File.SetAttributes(strFile, fa);
return true;
}
catch(Exception) { }
return false;
#endif
}
public static string MakeRelativePath(string strBaseFile, string strTargetFile)
{
if(strBaseFile == null) throw new ArgumentNullException("strBasePath");
if(strTargetFile == null) throw new ArgumentNullException("strTargetPath");
if(strBaseFile.Length == 0) return strTargetFile;
if(strTargetFile.Length == 0) return string.Empty;
// Test whether on different Windows drives
if((strBaseFile.Length >= 3) && (strTargetFile.Length >= 3))
{
if((strBaseFile[1] == ':') && (strTargetFile[1] == ':') &&
(strBaseFile[2] == '\\') && (strTargetFile[2] == '\\') &&
(strBaseFile[0] != strTargetFile[0]))
return strTargetFile;
}
if(NativeLib.IsUnix())
{
bool bBaseUnc = IsUncPath(strBaseFile);
bool bTargetUnc = IsUncPath(strTargetFile);
if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc))
return strTargetFile;
string strBase = GetShortestAbsolutePath(strBaseFile);
string strTarget = GetShortestAbsolutePath(strTargetFile);
string[] vBase = strBase.Split(m_vDirSeps);
string[] vTarget = strTarget.Split(m_vDirSeps);
int i = 0;
while((i < (vBase.Length - 1)) && (i < (vTarget.Length - 1)) &&
(vBase[i] == vTarget[i])) { ++i; }
StringBuilder sbRel = new StringBuilder();
for(int j = i; j < (vBase.Length - 1); ++j)
{
if(sbRel.Length > 0) sbRel.Append(Path.DirectorySeparatorChar);
sbRel.Append("..");
}
for(int k = i; k < vTarget.Length; ++k)
{
if(sbRel.Length > 0) sbRel.Append(Path.DirectorySeparatorChar);
sbRel.Append(vTarget[k]);
}
return sbRel.ToString();
}
#if KeePassLibSD
return strTargetFile;
#else
try // Windows
{
const int nMaxPath = NativeMethods.MAX_PATH * 2;
StringBuilder sb = new StringBuilder(nMaxPath + 2);
if(NativeMethods.PathRelativePathTo(sb, strBaseFile, 0,
strTargetFile, 0) == false)
return strTargetFile;
string str = sb.ToString();
while(str.StartsWith(".\\")) str = str.Substring(2, str.Length - 2);
return str;
}
catch(Exception) { Debug.Assert(false); return strTargetFile; }
#endif
}
public static string MakeAbsolutePath(string strBaseFile, string strTargetFile)
{
if(strBaseFile == null) throw new ArgumentNullException("strBasePath");
if(strTargetFile == null) throw new ArgumentNullException("strTargetPath");
if(strBaseFile.Length == 0) return strTargetFile;
if(strTargetFile.Length == 0) return string.Empty;
if(IsAbsolutePath(strTargetFile)) return strTargetFile;
string strBaseDir = GetFileDirectory(strBaseFile, true, false);
return GetShortestAbsolutePath(strBaseDir + strTargetFile);
}
public static bool IsAbsolutePath(string strPath)
{
if(strPath == null) throw new ArgumentNullException("strPath");
if(strPath.Length == 0) return false;
if(IsUncPath(strPath)) return true;
try { return Path.IsPathRooted(strPath); }
catch(Exception) { Debug.Assert(false); }
return true;
}
public static string GetShortestAbsolutePath(string strPath)
{
if(strPath == null) throw new ArgumentNullException("strPath");
if(strPath.Length == 0) return string.Empty;
// Path.GetFullPath is incompatible with UNC paths traversing over
// different server shares (which are created by PathRelativePathTo);
// we need to build the absolute path on our own...
if(IsUncPath(strPath))
{
char chSep = strPath[0];
Debug.Assert(Array.IndexOf<char>(m_vDirSeps, chSep) >= 0);
List<string> l = new List<string>();
#if !KeePassLibSD
string[] v = strPath.Split(m_vDirSeps, StringSplitOptions.None);
#else
string[] v = strPath.Split(m_vDirSeps);
#endif
Debug.Assert((v.Length >= 3) && (v[0].Length == 0) &&
(v[1].Length == 0));
foreach(string strPart in v)
{
if(strPart.Equals(".")) continue;
else if(strPart.Equals(".."))
{
if(l.Count > 0) l.RemoveAt(l.Count - 1);
else { Debug.Assert(false); }
}
else l.Add(strPart); // Do not ignore zero length parts
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < l.Count; ++i)
{
// Don't test length of sb, might be 0 due to initial UNC seps
if(i > 0) sb.Append(chSep);
sb.Append(l[i]);
}
return sb.ToString();
}
string str;
try { str = Path.GetFullPath(strPath); }
catch(Exception) { Debug.Assert(false); return strPath; }
Debug.Assert(str.IndexOf("\\..\\") < 0);
foreach(char ch in m_vDirSeps)
{
string strSep = new string(ch, 1);
str = str.Replace(strSep + "." + strSep, strSep);
}
return str;
}
public static int GetUrlLength(string strText, int nOffset)
{
if(strText == null) throw new ArgumentNullException("strText");
if(nOffset > strText.Length) throw new ArgumentException(); // Not >= (0 len)
int iPosition = nOffset, nLength = 0, nStrLen = strText.Length;
while(iPosition < nStrLen)
{
char ch = strText[iPosition];
++iPosition;
if((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'))
break;
++nLength;
}
return nLength;
}
public static string RemoveScheme(string strUrl)
{
if(string.IsNullOrEmpty(strUrl)) return string.Empty;
int nNetScheme = strUrl.IndexOf(@"://", StrUtil.CaseIgnoreCmp);
int nShScheme = strUrl.IndexOf(@":/", StrUtil.CaseIgnoreCmp);
int nSmpScheme = strUrl.IndexOf(@":", StrUtil.CaseIgnoreCmp);
if((nNetScheme < 0) && (nShScheme < 0) && (nSmpScheme < 0))
return strUrl; // No scheme
int nMin = Math.Min(Math.Min((nNetScheme >= 0) ? nNetScheme : int.MaxValue,
(nShScheme >= 0) ? nShScheme : int.MaxValue),
(nSmpScheme >= 0) ? nSmpScheme : int.MaxValue);
if(nMin == nNetScheme) return strUrl.Substring(nMin + 3);
if(nMin == nShScheme) return strUrl.Substring(nMin + 2);
return strUrl.Substring(nMin + 1);
}
public static string ConvertSeparators(string strPath)
{
return ConvertSeparators(strPath, Path.DirectorySeparatorChar);
}
public static string ConvertSeparators(string strPath, char chSeparator)
{
if(string.IsNullOrEmpty(strPath)) return string.Empty;
strPath = strPath.Replace('/', chSeparator);
strPath = strPath.Replace('\\', chSeparator);
return strPath;
}
public static bool IsUncPath(string strPath)
{
if(strPath == null) throw new ArgumentNullException("strPath");
return (strPath.StartsWith("\\\\") || strPath.StartsWith("//"));
}
public static string FilterFileName(string strName)
{
if(strName == null) { Debug.Assert(false); return string.Empty; }
string str = strName;
str = str.Replace('/', '-');
str = str.Replace('\\', '-');
str = str.Replace(":", string.Empty);
str = str.Replace("*", string.Empty);
str = str.Replace("?", string.Empty);
str = str.Replace("\"", string.Empty);
str = str.Replace(@"'", string.Empty);
str = str.Replace('<', '(');
str = str.Replace('>', ')');
str = str.Replace('|', '-');
return str;
}
/// <summary>
/// Get the host component of an URL.
/// This method is faster and more fault-tolerant than creating
/// an <code>Uri</code> object and querying its <code>Host</code>
/// property.
/// </summary>
/// <example>
/// For the input <code>s://u:p@d.tld:p/p?q#f</code> the return
/// value is <code>d.tld</code>.
/// </example>
public static string GetHost(string strUrl)
{
if(strUrl == null) { Debug.Assert(false); return string.Empty; }
StringBuilder sb = new StringBuilder();
bool bInExtHost = false;
for(int i = 0; i < strUrl.Length; ++i)
{
char ch = strUrl[i];
if(bInExtHost)
{
if(ch == '/')
{
if(sb.Length == 0) { } // Ignore leading '/'s
else break;
}
else sb.Append(ch);
}
else // !bInExtHost
{
if(ch == ':') bInExtHost = true;
}
}
string str = sb.ToString();
if(str.Length == 0) str = strUrl;
// Remove the login part
int nLoginLen = str.IndexOf('@');
if(nLoginLen >= 0) str = str.Substring(nLoginLen + 1);
// Remove the port
int iPort = str.LastIndexOf(':');
if(iPort >= 0) str = str.Substring(0, iPort);
return str;
}
public static bool AssemblyEquals(string strExt, string strShort)
{
if((strExt == null) || (strShort == null)) { Debug.Assert(false); return false; }
if(strExt.Equals(strShort, StrUtil.CaseIgnoreCmp) ||
strExt.StartsWith(strShort + ",", StrUtil.CaseIgnoreCmp))
return true;
if(!strShort.EndsWith(".dll", StrUtil.CaseIgnoreCmp))
{
if(strExt.Equals(strShort + ".dll", StrUtil.CaseIgnoreCmp) ||
strExt.StartsWith(strShort + ".dll,", StrUtil.CaseIgnoreCmp))
return true;
}
if(!strShort.EndsWith(".exe", StrUtil.CaseIgnoreCmp))
{
if(strExt.Equals(strShort + ".exe", StrUtil.CaseIgnoreCmp) ||
strExt.StartsWith(strShort + ".exe,", StrUtil.CaseIgnoreCmp))
return true;
}
return false;
}
public static string GetTempPath()
{
string strDir;
if(NativeLib.IsUnix())
strDir = NativeMethods.GetUserRuntimeDir();
else strDir = Path.GetTempPath();
try
{
if(Directory.Exists(strDir) == false)
Directory.CreateDirectory(strDir);
}
catch(Exception) { Debug.Assert(false); }
return strDir;
}
}
}