Merge branch 'Keepass_Orig'

Conflicts:
	src/KeePassLib2Android/Cryptography/CryptoRandom.cs
	src/KeePassLib2Android/Cryptography/HashingStreamEx.cs
	src/KeePassLib2Android/Cryptography/HmacOtp.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/CharSetBasedGenerator.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGenerator.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/CustomPwGeneratorPool.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/PatternBasedGenerator.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/PwCharSet.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/PwGenerator.cs
	src/KeePassLib2Android/Cryptography/PasswordGenerator/PwProfile.cs
	src/KeePassLib2Android/Cryptography/PopularPasswords.cs
	src/KeePassLib2Android/Cryptography/QualityEstimation.cs
	src/KeePassLib2Android/Cryptography/SelfTest.cs
	src/KeePassLib2Android/Delegates/Handlers.cs
	src/KeePassLib2Android/Interfaces/IDeepCloneable.cs
	src/KeePassLib2Android/Interfaces/IStatusLogger.cs
	src/KeePassLib2Android/Interfaces/IStructureItem.cs
	src/KeePassLib2Android/Interfaces/ITimeLogger.cs
	src/KeePassLib2Android/Interfaces/IUIOperations.cs
	src/KeePassLib2Android/Interfaces/IXmlSerializerEx.cs
	src/KeePassLib2Android/Keys/IUserKey.cs
	src/KeePassLib2Android/Keys/KcpCustomKey.cs
	src/KeePassLib2Android/Keys/KcpUserAccount.cs
	src/KeePassLib2Android/PwCustomIcon.cs
	src/KeePassLib2Android/PwGroup.cs
	src/KeePassLib2Android/Serialization/FileTransactionEx.cs
	src/KeePassLib2Android/Serialization/HashedBlockStream.cs
	src/KeePassLib2Android/Serialization/IOConnection.cs
	src/KeePassLib2Android/Serialization/KdbxFile.Read.cs
	src/KeePassLib2Android/Serialization/KdbxFile.Write.cs
	src/KeePassLib2Android/Translation/KPControlCustomization.cs
	src/KeePassLib2Android/Translation/KPFormCustomization.cs
	src/KeePassLib2Android/Utility/GfxUtil.cs
	src/KeePassLib2Android/Utility/MessageService.cs
	src/KeePassLib2Android/Utility/MonoWorkarounds.cs
	src/KeePassLib2Android/Utility/TimeUtil.cs
This commit is contained in:
Philipp Crocoll 2017-01-11 18:02:44 +01:00
commit 34e572dad1
96 changed files with 2221 additions and 588 deletions

View File

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

View File

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

View File

@ -0,0 +1,174 @@
/*
KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2017 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.Delegates;
using KeePassLib.Security;
namespace KeePassLib.Collections
{
internal sealed class ProtectedBinarySet : IEnumerable<KeyValuePair<int, ProtectedBinary>>
{
private Dictionary<int, ProtectedBinary> m_d =
new Dictionary<int, ProtectedBinary>();
public ProtectedBinarySet()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return m_d.GetEnumerator();
}
public IEnumerator<KeyValuePair<int, ProtectedBinary>> GetEnumerator()
{
return m_d.GetEnumerator();
}
public void Clear()
{
m_d.Clear();
}
private int GetFreeID()
{
int i = m_d.Count;
while(m_d.ContainsKey(i)) { ++i; }
Debug.Assert(i == m_d.Count); // m_d.Count should be free
return i;
}
public ProtectedBinary Get(int iID)
{
ProtectedBinary pb;
if(m_d.TryGetValue(iID, out pb)) return pb;
// Debug.Assert(false); // No assert
return null;
}
public int Find(ProtectedBinary pb)
{
if(pb == null) { Debug.Assert(false); return -1; }
// Fast search by reference
foreach(KeyValuePair<int, ProtectedBinary> kvp in m_d)
{
if(object.ReferenceEquals(pb, kvp.Value))
{
Debug.Assert(pb.Equals(kvp.Value));
return kvp.Key;
}
}
// Slow search by content
foreach(KeyValuePair<int, ProtectedBinary> kvp in m_d)
{
if(pb.Equals(kvp.Value)) return kvp.Key;
}
// Debug.Assert(false); // No assert
return -1;
}
public void Set(int iID, ProtectedBinary pb)
{
if(iID < 0) { Debug.Assert(false); return; }
if(pb == null) { Debug.Assert(false); return; }
m_d[iID] = pb;
}
public void Add(ProtectedBinary pb)
{
if(pb == null) { Debug.Assert(false); return; }
int i = Find(pb);
if(i >= 0) return; // Exists already
i = GetFreeID();
m_d[i] = pb;
}
public void AddFrom(ProtectedBinaryDictionary d)
{
if(d == null) { Debug.Assert(false); return; }
foreach(KeyValuePair<string, ProtectedBinary> kvp in d)
{
Add(kvp.Value);
}
}
public void AddFrom(PwGroup pg)
{
if(pg == null) { Debug.Assert(false); return; }
EntryHandler eh = delegate(PwEntry pe)
{
if(pe == null) { Debug.Assert(false); return true; }
AddFrom(pe.Binaries);
foreach(PwEntry peHistory in pe.History)
{
if(peHistory == null) { Debug.Assert(false); continue; }
AddFrom(peHistory.Binaries);
}
return true;
};
pg.TraverseTree(TraversalMethod.PreOrder, null, eh);
}
public ProtectedBinary[] ToArray()
{
int n = m_d.Count;
ProtectedBinary[] v = new ProtectedBinary[n];
foreach(KeyValuePair<int, ProtectedBinary> kvp in m_d)
{
if((kvp.Key < 0) || (kvp.Key >= n))
{
Debug.Assert(false);
throw new InvalidOperationException();
}
v[kvp.Key] = kvp.Value;
}
for(int i = 0; i < n; ++i)
{
if(v[i] == null)
{
Debug.Assert(false);
throw new InvalidOperationException();
}
}
return v;
}
}
}

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -20,11 +20,12 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.Text;
using KeePassLib.Delegates; using KeePassLib.Delegates;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Utility;
#if KeePassLibSD #if KeePassLibSD
using KeePassLibSD; using KeePassLibSD;
@ -182,7 +183,7 @@ namespace KeePassLib.Collections
get { return ((m_l.Count > 0) ? m_l[0] : null); } get { return ((m_l.Count > 0) ? m_l[0] : null); }
} }
private DateTime m_dtLocationChanged = DateTime.MinValue; private DateTime m_dtLocationChanged = TimeUtil.SafeMinValueUtc;
public DateTime LocationChanged public DateTime LocationChanged
{ {
get { return m_dtLocationChanged; } get { return m_dtLocationChanged; }

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -107,8 +107,11 @@ namespace KeePassLib.Cryptography.Cipher
protected override void Dispose(bool bDisposing) protected override void Dispose(bool bDisposing)
{ {
MemUtil.ZeroArray<uint>(m_s); if(bDisposing)
MemUtil.ZeroArray<uint>(m_x); {
MemUtil.ZeroArray<uint>(m_s);
MemUtil.ZeroArray<uint>(m_x);
}
base.Dispose(bDisposing); base.Dispose(bDisposing);
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -115,18 +115,21 @@ namespace KeePassLib.Cryptography.Cipher
protected override void Dispose(bool bDisposing) protected override void Dispose(bool bDisposing)
{ {
if(!bDisposing) return; if(bDisposing)
if(m_sBase != null)
{ {
m_c.Dispose(); if(m_sBase != null)
m_c = null; {
m_c.Dispose();
m_c = null;
m_sBase.Close(); m_sBase.Close();
m_sBase = null; m_sBase = null;
}
m_pbBuffer = null;
} }
m_pbBuffer = null; base.Dispose(bDisposing);
} }
public override void Flush() public override void Flush()

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -53,8 +53,11 @@ namespace KeePassLib.Cryptography.Cipher
protected virtual void Dispose(bool bDisposing) protected virtual void Dispose(bool bDisposing)
{ {
MemUtil.ZeroByteArray(m_pBlock); if(bDisposing)
m_iBlockPos = m_pBlock.Length; {
MemUtil.ZeroByteArray(m_pBlock);
m_iBlockPos = m_pBlock.Length;
}
} }
protected void InvalidateBlock() protected void InvalidateBlock()

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -72,8 +72,11 @@ namespace KeePassLib.Cryptography.Cipher
protected override void Dispose(bool bDisposing) protected override void Dispose(bool bDisposing)
{ {
MemUtil.ZeroArray<uint>(m_s); if(bDisposing)
MemUtil.ZeroArray<uint>(m_x); {
MemUtil.ZeroArray<uint>(m_s);
MemUtil.ZeroArray<uint>(m_x);
}
base.Dispose(bDisposing); base.Dispose(bDisposing);
} }

View File

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

View File

@ -20,7 +20,10 @@
*/ */
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO; using System.IO;
#if !KeePassUAP #if !KeePassUAP
@ -34,8 +37,8 @@ using KeePassLib.Utility;
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
/// <summary> /// <summary>
/// Cryptographically strong random number generator. The returned values /// Cryptographically secure pseudo-random number generator.
/// are unpredictable and cannot be reproduced. /// The returned values are unpredictable and cannot be reproduced.
/// <c>CryptoRandom</c> is a singleton class. /// <c>CryptoRandom</c> is a singleton class.
/// </summary> /// </summary>
public sealed class CryptoRandom public sealed class CryptoRandom
@ -91,12 +94,13 @@ namespace KeePassLib.Cryptography
private CryptoRandom() private CryptoRandom()
{ {
Random rWeak = new Random();
byte[] pb = new byte[8];
rWeak.NextBytes(pb);
m_uCounter = MemUtil.BytesToUInt64(pb);
AddEntropy(GetSystemData(rWeak)); // byte[] pb = new byte[8];
// rWeak.NextBytes(pb);
// m_uCounter = MemUtil.BytesToUInt64(pb);
m_uCounter = (ulong)DateTime.UtcNow.ToBinary();
AddEntropy(GetSystemData());
AddEntropy(GetCspData()); AddEntropy(GetCspData());
} }
@ -148,7 +152,7 @@ namespace KeePassLib.Cryptography
} }
} }
private static byte[] GetSystemData(Random rWeak) private static byte[] GetSystemData()
{ {
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
byte[] pb; byte[] pb;
@ -175,32 +179,40 @@ namespace KeePassLib.Cryptography
*/ */
#endif #endif
pb = MemUtil.Int32ToBytes(rWeak.Next());
MemUtil.Write(ms, pb);
pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID());
MemUtil.Write(ms, pb); MemUtil.Write(ms, pb);
try try
{ {
#if KeePassUAP
string strOS = EnvironmentExt.OSVersion.VersionString;
#else
string strOS = Environment.OSVersion.VersionString;
#endif
AddStrHash(ms, strOS);
pb = MemUtil.Int32ToBytes(Environment.ProcessorCount); pb = MemUtil.Int32ToBytes(Environment.ProcessorCount);
MemUtil.Write(ms, pb); MemUtil.Write(ms, pb);
#if KeePassUAP
Version v = EnvironmentExt.OSVersion.Version;
#else
Version v = Environment.OSVersion.Version;
#endif
pb = MemUtil.Int32ToBytes(v.GetHashCode());
MemUtil.Write(ms, pb);
#if !KeePassUAP #if !KeePassUAP
AddStrHash(ms, Environment.CommandLine);
pb = MemUtil.Int64ToBytes(Environment.WorkingSet); pb = MemUtil.Int64ToBytes(Environment.WorkingSet);
MemUtil.Write(ms, pb); MemUtil.Write(ms, pb);
#endif #endif
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
try
{
foreach(DictionaryEntry de in Environment.GetEnvironmentVariables())
{
AddStrHash(ms, (de.Key as string));
AddStrHash(ms, (de.Value as string));
}
}
catch(Exception) { Debug.Assert(false); }
#if KeePassUAP #if KeePassUAP
pb = DiagnosticsExt.GetProcessEntropy(); pb = DiagnosticsExt.GetProcessEntropy();
MemUtil.Write(ms, pb); MemUtil.Write(ms, pb);
@ -249,6 +261,18 @@ namespace KeePassLib.Cryptography
} }
#endif #endif
try
{
CultureInfo ci = CultureInfo.CurrentCulture;
if(ci != null)
{
pb = MemUtil.Int32ToBytes(ci.GetHashCode());
MemUtil.Write(ms, pb);
}
else { Debug.Assert(false); }
}
catch(Exception) { Debug.Assert(false); }
pb = Guid.NewGuid().ToByteArray(); pb = Guid.NewGuid().ToByteArray();
MemUtil.Write(ms, pb); MemUtil.Write(ms, pb);
@ -257,6 +281,16 @@ namespace KeePassLib.Cryptography
return pbAll; return pbAll;
} }
private static void AddStrHash(Stream s, string str)
{
if(s == null) { Debug.Assert(false); return; }
if(string.IsNullOrEmpty(str)) return;
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(str);
byte[] pbHash = CryptoUtil.HashSha256(pbUtf8);
MemUtil.Write(s, pbHash);
}
private byte[] GetCspData() private byte[] GetCspData()
{ {
byte[] pbCspRandom = new byte[32]; byte[] pbCspRandom = new byte[32];
@ -321,7 +355,7 @@ namespace KeePassLib.Cryptography
byte[] pbRandom256 = GenerateRandom256(); byte[] pbRandom256 = GenerateRandom256();
Debug.Assert(pbRandom256.Length == 32); Debug.Assert(pbRandom256.Length == 32);
int cbCopy = Math.Min(cbRem, 32); int cbCopy = Math.Min(cbRem, pbRandom256.Length);
Array.Copy(pbRandom256, 0, pbRes, iPos, cbCopy); Array.Copy(pbRandom256, 0, pbRes, iPos, cbCopy);
MemUtil.ZeroByteArray(pbRandom256); MemUtil.ZeroByteArray(pbRandom256);

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -64,7 +64,7 @@ namespace KeePassLib.Cryptography
/// properties, but for the same seed always the same stream /// properties, but for the same seed always the same stream
/// is produced, i.e. this class can be used as stream cipher. /// is produced, i.e. this class can be used as stream cipher.
/// </summary> /// </summary>
public sealed class CryptoRandomStream public sealed class CryptoRandomStream : IDisposable
{ {
private readonly CrsAlgorithm m_crsAlgorithm; private readonly CrsAlgorithm m_crsAlgorithm;
@ -149,6 +149,30 @@ namespace KeePassLib.Cryptography
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if(disposing)
{
if(m_crsAlgorithm == CrsAlgorithm.ChaCha20)
m_chacha20.Dispose();
else if(m_crsAlgorithm == CrsAlgorithm.Salsa20)
m_salsa20.Dispose();
else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant)
{
MemUtil.ZeroByteArray(m_pbState);
m_i = 0;
m_j = 0;
}
else { Debug.Assert(false); }
}
}
/// <summary> /// <summary>
/// Get <paramref name="uRequestedCount" /> random bytes. /// Get <paramref name="uRequestedCount" /> random bytes.
/// </summary> /// </summary>
@ -220,8 +244,10 @@ namespace KeePassLib.Cryptography
int nStart = Environment.TickCount; int nStart = Environment.TickCount;
for(int i = 0; i < nRounds; ++i) for(int i = 0; i < nRounds; ++i)
{ {
CryptoRandomStream c = new CryptoRandomStream(cra, pbKey); using(CryptoRandomStream c = new CryptoRandomStream(cra, pbKey))
c.GetRandomBytes((uint)nDataSize); {
c.GetRandomBytes((uint)nDataSize);
}
} }
int nEnd = Environment.TickCount; int nEnd = Environment.TickCount;

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -30,7 +30,7 @@ namespace KeePassLib.Cryptography
{ {
public sealed class HashingStreamEx : Stream public sealed class HashingStreamEx : Stream
{ {
private Stream m_sBaseStream; private readonly Stream m_sBaseStream;
private bool m_bWriting; private bool m_bWriting;
private HashAlgorithm m_hash; private HashAlgorithm m_hash;
@ -105,11 +105,8 @@ namespace KeePassLib.Cryptography
#if KeePassRT #if KeePassRT
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if(!disposing) return; if(disposing)
#else
public override void Close()
{ {
#endif
if(m_hash != null) if(m_hash != null)
{ {
try try
@ -126,6 +123,14 @@ namespace KeePassLib.Cryptography
m_sBaseStream.Close(); m_sBaseStream.Close();
} }
base.Dispose(disposing);
}
public override void Flush()
{
m_sBaseStream.Flush();
}
public override long Seek(long lOffset, SeekOrigin soOrigin) public override long Seek(long lOffset, SeekOrigin soOrigin)
{ {
throw new NotSupportedException(); throw new NotSupportedException();

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -77,6 +77,16 @@ namespace KeePassLib.Cryptography.KeyDerivation
public ulong Lane = 0; public ulong Lane = 0;
public ulong Slice = 0; public ulong Slice = 0;
public ulong Index = 0; public ulong Index = 0;
public void Release()
{
if(this.Finished != null)
{
this.Finished.Close();
this.Finished = null;
}
else { Debug.Assert(false); }
}
} }
private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel, private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel,
@ -104,7 +114,12 @@ namespace KeePassLib.Cryptography.KeyDerivation
ctx.LaneLength = ctx.SegmentLength * NbSyncPoints; ctx.LaneLength = ctx.SegmentLength * NbSyncPoints;
Debug.Assert(NbBlockSize == (NbBlockSizeInQW * Debug.Assert(NbBlockSize == (NbBlockSizeInQW *
(ulong)Marshal.SizeOf(typeof(ulong)))); #if KeePassUAP
(ulong)Marshal.SizeOf<ulong>()
#else
(ulong)Marshal.SizeOf(typeof(ulong))
#endif
));
ctx.Mem = new ulong[ctx.MemoryBlocks * NbBlockSizeInQW]; ctx.Mem = new ulong[ctx.MemoryBlocks * NbBlockSizeInQW];
Blake2b h = new Blake2b(); Blake2b h = new Blake2b();
@ -186,8 +201,13 @@ namespace KeePassLib.Cryptography.KeyDerivation
// for(int i = 0; i < (int)NbBlockSizeInQW; ++i) // for(int i = 0; i < (int)NbBlockSizeInQW; ++i)
// vDst[iDstOffset + i] = vSrc[iSrcOffset + i]; // vDst[iDstOffset + i] = vSrc[iSrcOffset + i];
#if KeePassUAP
Array.Copy(vSrc, (int)uSrcOffset, vDst, (int)uDstOffset,
(int)NbBlockSizeInQW);
#else
Array.Copy(vSrc, (long)uSrcOffset, vDst, (long)uDstOffset, Array.Copy(vSrc, (long)uSrcOffset, vDst, (long)uDstOffset,
(long)NbBlockSizeInQW); (long)NbBlockSizeInQW);
#endif
} }
private static void XorBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc, private static void XorBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc,
@ -456,7 +476,10 @@ namespace KeePassLib.Cryptography.KeyDerivation
} }
for(int l = 0; l < np; ++l) for(int l = 0; l < np; ++l)
{
v[l].Finished.WaitOne(); v[l].Finished.WaitOne();
v[l].Release();
}
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -47,7 +47,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
if(ch == char.MinValue) if(ch == char.MinValue)
{ {
Array.Clear(vGenerated, 0, vGenerated.Length); MemUtil.ZeroArray<char>(vGenerated);
return PwgError.TooFewCharacters; return PwgError.TooFewCharacters;
} }
@ -57,7 +57,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated); byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vGenerated);
psOut = new ProtectedString(true, pbUtf8); psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8); MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vGenerated, 0, vGenerated.Length); MemUtil.ZeroArray<char>(vGenerated);
return PwgError.Success; return PwgError.Success;
} }

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -121,7 +121,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vArray); byte[] pbUtf8 = StrUtil.Utf8.GetBytes(vArray);
psOut = new ProtectedString(true, pbUtf8); psOut = new ProtectedString(true, pbUtf8);
MemUtil.ZeroByteArray(pbUtf8); MemUtil.ZeroByteArray(pbUtf8);
Array.Clear(vArray, 0, vArray.Length); MemUtil.ZeroArray<char>(vArray);
vGenerated.Clear(); vGenerated.Clear();
return PwgError.Success; return PwgError.Success;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -46,6 +46,8 @@ namespace KeePassLib.Cryptography.PasswordGenerator
public const string Invalid = "\t\r\n"; public const string Invalid = "\t\r\n";
public const string LookAlike = @"O0l1I|"; public const string LookAlike = @"O0l1I|";
internal const string MenuAccels = PwCharSet.LowerCase + PwCharSet.Digits;
private const int CharTabSize = (0x10000 / 8); private const int CharTabSize = (0x10000 / 8);
private List<char> m_vChars = new List<char>(); private List<char> m_vChars = new List<char>();

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -22,6 +22,10 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Diagnostics; using System.Diagnostics;
#if !KeePassUAP
using System.Security.Cryptography;
#endif
using KeePassLib.Security; using KeePassLib.Security;
namespace KeePassLib.Cryptography.PasswordGenerator namespace KeePassLib.Cryptography.PasswordGenerator
@ -46,8 +50,12 @@ namespace KeePassLib.Cryptography.PasswordGenerator
Debug.Assert(pwProfile != null); Debug.Assert(pwProfile != null);
if(pwProfile == null) throw new ArgumentNullException("pwProfile"); if(pwProfile == null) throw new ArgumentNullException("pwProfile");
CryptoRandomStream crs = CreateCryptoStream(pbUserEntropy);
PwgError e = PwgError.Unknown; PwgError e = PwgError.Unknown;
CryptoRandomStream crs = null;
byte[] pbKey = null;
try
{
crs = CreateRandomStream(pbUserEntropy, out pbKey);
if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet) if(pwProfile.GeneratorType == PasswordGeneratorType.CharSet)
e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs); e = CharSetBasedGenerator.Generate(out psOut, pwProfile, crs);
@ -56,13 +64,20 @@ namespace KeePassLib.Cryptography.PasswordGenerator
else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom) else if(pwProfile.GeneratorType == PasswordGeneratorType.Custom)
e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool); e = GenerateCustom(out psOut, pwProfile, crs, pwAlgorithmPool);
else { Debug.Assert(false); psOut = ProtectedString.Empty; } else { Debug.Assert(false); psOut = ProtectedString.Empty; }
}
finally
{
if(crs != null) crs.Dispose();
if(pbKey != null) MemUtil.ZeroByteArray(pbKey);
}
return e; return e;
} }
private static CryptoRandomStream CreateCryptoStream(byte[] pbAdditionalEntropy) private static CryptoRandomStream CreateRandomStream(byte[] pbAdditionalEntropy,
out byte[] pbKey)
{ {
byte[] pbKey = CryptoRandom.Instance.GetRandomBytes(256); pbKey = CryptoRandom.Instance.GetRandomBytes(256);
// Mix in additional entropy // Mix in additional entropy
if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0)) if((pbAdditionalEntropy != null) && (pbAdditionalEntropy.Length > 0))

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -265,7 +265,7 @@ namespace KeePassLib.Cryptography.PasswordGenerator
else pcs.Add(ch); else pcs.Add(ch);
} }
Array.Clear(vChars, 0, vChars.Length); MemUtil.ZeroArray<char>(vChars);
MemUtil.ZeroByteArray(pbUtf8); MemUtil.ZeroByteArray(pbUtf8);
return pp; return pp;
} }

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -422,7 +422,7 @@ namespace KeePassLib.Cryptography
char[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8); char[] vChars = StrUtil.Utf8.GetChars(pbUnprotectedUtf8);
uint uResult = EstimatePasswordBits(vChars); uint uResult = EstimatePasswordBits(vChars);
Array.Clear(vChars, 0, vChars.Length); MemUtil.ZeroArray<char>(vChars);
return uResult; return uResult;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,34 +19,35 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Globalization;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Security;
using System.Text;
#if KeePassUAP
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
#else
using System.Security.Cryptography;
#endif
using KeePassLib.Cryptography.Cipher; using KeePassLib.Cryptography.Cipher;
using KeePassLib.Cryptography.Hash;
using KeePassLib.Cryptography.KeyDerivation;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Native; using KeePassLib.Native;
using KeePassLib.Utility;
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
#if (KeePassUAP && KeePassLibSD)
#error KeePassUAP and KeePassLibSD are mutually exclusive.
#endif
namespace KeePassLib.Cryptography namespace KeePassLib.Cryptography
{ {
/* #pragma warning disable 1591
/// <summary>
/// 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> /// <summary>
/// Class containing self-test methods. /// Class containing self-test methods.
/// </summary> /// </summary>
@ -61,7 +62,11 @@ namespace KeePassLib.Cryptography
TestRijndael(); TestRijndael();
TestSalsa20(); TestSalsa20();
TestChaCha20();
TestBlake2b();
TestArgon2();
TestHmac();
TestNativeKeyTransform(); TestNativeKeyTransform();
TestHmacOtp(); TestHmacOtp();
@ -74,28 +79,31 @@ namespace KeePassLib.Cryptography
Debug.Assert((int)PwIcon.World == 1); Debug.Assert((int)PwIcon.World == 1);
Debug.Assert((int)PwIcon.Warning == 2); Debug.Assert((int)PwIcon.Warning == 2);
Debug.Assert((int)PwIcon.BlackBerry == 68); Debug.Assert((int)PwIcon.BlackBerry == 68);
#if KeePassUAP
SelfTestEx.Perform();
#endif
} }
internal static void TestFipsComplianceProblems() internal static void TestFipsComplianceProblems()
{ {
#if !KeePassRT #if !KeePassUAP
try { new RijndaelManaged(); } try { using(RijndaelManaged r = new RijndaelManaged()) { } }
catch(Exception exAes) catch(Exception exAes)
{ {
throw new SecurityException("AES/Rijndael: " + exAes.Message); throw new SecurityException("AES/Rijndael: " + exAes.Message);
} }
#endif
try { new SHA256Managed(); } try { using(SHA256Managed h = new SHA256Managed()) { } }
catch(Exception exSha256) catch(Exception exSha256)
{ {
throw new SecurityException("SHA-256: " + exSha256.Message); throw new SecurityException("SHA-256: " + exSha256.Message);
} }
#endif
} }
private static void TestRijndael() private static void TestRijndael()
{ {
#if !KeePassRT
// Test vector (official ECB test vector #356) // Test vector (official ECB test vector #356)
byte[] pbIV = new byte[16]; byte[] pbIV = new byte[16];
byte[] pbTestKey = new byte[32]; byte[] pbTestKey = new byte[32];
@ -110,6 +118,13 @@ namespace KeePassLib.Cryptography
for(i = 0; i < 16; ++i) pbTestData[i] = 0; for(i = 0; i < 16; ++i) pbTestData[i] = 0;
pbTestData[0] = 0x04; pbTestData[0] = 0x04;
#if KeePassUAP
AesEngine r = new AesEngine();
r.Init(true, new KeyParameter(pbTestKey));
if(r.GetBlockSize() != pbTestData.Length)
throw new SecurityException("AES (BC)");
r.ProcessBlock(pbTestData, 0, pbTestData, 0);
#else
RijndaelManaged r = new RijndaelManaged(); RijndaelManaged r = new RijndaelManaged();
if(r.BlockSize != 128) // AES block size if(r.BlockSize != 128) // AES block size
@ -125,16 +140,17 @@ namespace KeePassLib.Cryptography
ICryptoTransform iCrypt = r.CreateEncryptor(); ICryptoTransform iCrypt = r.CreateEncryptor();
iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0); iCrypt.TransformBlock(pbTestData, 0, 16, pbTestData, 0);
#endif
if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT)) if(!MemUtil.ArraysEqual(pbTestData, pbReferenceCT))
throw new SecurityException(KLRes.EncAlgorithmAes + "."); throw new SecurityException("AES");
#endif
} }
private static void TestSalsa20() private static void TestSalsa20()
{ {
#if DEBUG
// Test values from official set 6, vector 3 // Test values from official set 6, vector 3
byte[] pbKey= new byte[32] { byte[] pbKey = new byte[32] {
0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54, 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC, 0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC,
0x3F, 0x92, 0xE5, 0x38, 0x8B, 0xDE, 0x31, 0x84, 0x3F, 0x92, 0xE5, 0x38, 0x8B, 0xDE, 0x31, 0x84,
@ -149,12 +165,11 @@ namespace KeePassLib.Cryptography
byte[] pb = new byte[16]; byte[] pb = new byte[16];
Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV); Salsa20Cipher c = new Salsa20Cipher(pbKey, pbIV);
c.Encrypt(pb, pb.Length, false); c.Encrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpected)) if(!MemUtil.ArraysEqual(pb, pbExpected))
throw new SecurityException("Salsa20."); throw new SecurityException("Salsa20-1");
#if DEBUG // Extended test
// Extended test in debug mode
byte[] pbExpected2 = new byte[16] { byte[] pbExpected2 = new byte[16] {
0xAB, 0xF3, 0x9A, 0x21, 0x0E, 0xEE, 0x89, 0x59, 0xAB, 0xF3, 0x9A, 0x21, 0x0E, 0xEE, 0x89, 0x59,
0x8B, 0x71, 0x33, 0x37, 0x70, 0x56, 0xC2, 0xFE 0x8B, 0x71, 0x33, 0x37, 0x70, 0x56, 0xC2, 0xFE
@ -166,15 +181,27 @@ namespace KeePassLib.Cryptography
Random r = new Random(); Random r = new Random();
int nPos = Salsa20ToPos(c, r, pb.Length, 65536); int nPos = Salsa20ToPos(c, r, pb.Length, 65536);
c.Encrypt(pb, pb.Length, false); Array.Clear(pb, 0, pb.Length);
c.Encrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpected2)) if(!MemUtil.ArraysEqual(pb, pbExpected2))
throw new SecurityException("Salsa20-2."); throw new SecurityException("Salsa20-2");
nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008); nPos = Salsa20ToPos(c, r, nPos + pb.Length, 131008);
Array.Clear(pb, 0, pb.Length); Array.Clear(pb, 0, pb.Length);
c.Encrypt(pb, pb.Length, true); c.Encrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpected3)) if(!MemUtil.ArraysEqual(pb, pbExpected3))
throw new SecurityException("Salsa20-3."); throw new SecurityException("Salsa20-3");
Dictionary<string, bool> d = new Dictionary<string, bool>();
const int nRounds = 100;
for(int i = 0; i < nRounds; ++i)
{
byte[] z = new byte[32];
c = new Salsa20Cipher(z, MemUtil.Int64ToBytes(i));
c.Encrypt(z, 0, z.Length);
d[MemUtil.ByteArrayToHexString(z)] = true;
}
if(d.Count != nRounds) throw new SecurityException("Salsa20-4");
#endif #endif
} }
@ -188,7 +215,7 @@ namespace KeePassLib.Cryptography
{ {
int x = r.Next(1, 513); int x = r.Next(1, 513);
int nGen = Math.Min(nTargetPos - nPos, x); int nGen = Math.Min(nTargetPos - nPos, x);
c.Encrypt(pb, nGen, r.Next(0, 2) == 0); c.Encrypt(pb, 0, nGen);
nPos += nGen; nPos += nGen;
} }
@ -196,6 +223,484 @@ namespace KeePassLib.Cryptography
} }
#endif #endif
private static void TestChaCha20()
{
// ======================================================
// Test vector from RFC 7539, section 2.3.2
byte[] pbKey = new byte[32];
for(int i = 0; i < 32; ++i) pbKey[i] = (byte)i;
byte[] pbIV = new byte[12];
pbIV[3] = 0x09;
pbIV[7] = 0x4A;
byte[] pbExpc = new byte[64] {
0x10, 0xF1, 0xE7, 0xE4, 0xD1, 0x3B, 0x59, 0x15,
0x50, 0x0F, 0xDD, 0x1F, 0xA3, 0x20, 0x71, 0xC4,
0xC7, 0xD1, 0xF4, 0xC7, 0x33, 0xC0, 0x68, 0x03,
0x04, 0x22, 0xAA, 0x9A, 0xC3, 0xD4, 0x6C, 0x4E,
0xD2, 0x82, 0x64, 0x46, 0x07, 0x9F, 0xAA, 0x09,
0x14, 0xC2, 0xD7, 0x05, 0xD9, 0x8B, 0x02, 0xA2,
0xB5, 0x12, 0x9C, 0xD1, 0xDE, 0x16, 0x4E, 0xB9,
0xCB, 0xD0, 0x83, 0xE8, 0xA2, 0x50, 0x3C, 0x4E
};
byte[] pb = new byte[64];
using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV))
{
c.Seek(64, SeekOrigin.Begin); // Skip first block
c.Encrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("ChaCha20-1");
}
#if DEBUG
// ======================================================
// Test vector from RFC 7539, section 2.4.2
pbIV[3] = 0;
pb = StrUtil.Utf8.GetBytes("Ladies and Gentlemen of the clas" +
@"s of '99: If I could offer you only one tip for " +
@"the future, sunscreen would be it.");
pbExpc = new byte[] {
0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80,
0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81,
0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2,
0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B,
0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB,
0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57,
0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB,
0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8,
0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61,
0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E,
0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06,
0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36,
0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6,
0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42,
0x87, 0x4D
};
byte[] pb64 = new byte[64];
using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV))
{
c.Encrypt(pb64, 0, pb64.Length); // Skip first block
c.Encrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("ChaCha20-2");
}
// ======================================================
// Test vector from RFC 7539, appendix A.2 #2
Array.Clear(pbKey, 0, pbKey.Length);
pbKey[31] = 1;
Array.Clear(pbIV, 0, pbIV.Length);
pbIV[11] = 2;
pb = StrUtil.Utf8.GetBytes("Any submission to the IETF inten" +
"ded by the Contributor for publication as all or" +
" part of an IETF Internet-Draft or RFC and any s" +
"tatement made within the context of an IETF acti" +
"vity is considered an \"IETF Contribution\". Such " +
"statements include oral statements in IETF sessi" +
"ons, as well as written and electronic communica" +
"tions made at any time or place, which are addressed to");
pbExpc = MemUtil.HexStringToByteArray(
"A3FBF07DF3FA2FDE4F376CA23E82737041605D9F4F4F57BD8CFF2C1D4B7955EC" +
"2A97948BD3722915C8F3D337F7D370050E9E96D647B7C39F56E031CA5EB6250D" +
"4042E02785ECECFA4B4BB5E8EAD0440E20B6E8DB09D881A7C6132F420E527950" +
"42BDFA7773D8A9051447B3291CE1411C680465552AA6C405B7764D5E87BEA85A" +
"D00F8449ED8F72D0D662AB052691CA66424BC86D2DF80EA41F43ABF937D3259D" +
"C4B2D0DFB48A6C9139DDD7F76966E928E635553BA76C5C879D7B35D49EB2E62B" +
"0871CDAC638939E25E8A1E0EF9D5280FA8CA328B351C3C765989CBCF3DAA8B6C" +
"CC3AAF9F3979C92B3720FC88DC95ED84A1BE059C6499B9FDA236E7E818B04B0B" +
"C39C1E876B193BFE5569753F88128CC08AAA9B63D1A16F80EF2554D7189C411F" +
"5869CA52C5B83FA36FF216B9C1D30062BEBCFD2DC5BCE0911934FDA79A86F6E6" +
"98CED759C3FF9B6477338F3DA4F9CD8514EA9982CCAFB341B2384DD902F3D1AB" +
"7AC61DD29C6F21BA5B862F3730E37CFDC4FD806C22F221");
Random r = new Random();
using(MemoryStream msEnc = new MemoryStream())
{
using(ChaCha20Stream c = new ChaCha20Stream(msEnc, true, pbKey, pbIV))
{
r.NextBytes(pb64);
c.Write(pb64, 0, pb64.Length); // Skip first block
int p = 0;
while(p < pb.Length)
{
int cb = r.Next(1, pb.Length - p + 1);
c.Write(pb, p, cb);
p += cb;
}
Debug.Assert(p == pb.Length);
}
byte[] pbEnc0 = msEnc.ToArray();
byte[] pbEnc = MemUtil.Mid(pbEnc0, 64, pbEnc0.Length - 64);
if(!MemUtil.ArraysEqual(pbEnc, pbExpc))
throw new SecurityException("ChaCha20-3");
using(MemoryStream msCT = new MemoryStream(pbEnc0, false))
{
using(ChaCha20Stream cDec = new ChaCha20Stream(msCT, false,
pbKey, pbIV))
{
byte[] pbPT = MemUtil.Read(cDec, pbEnc0.Length);
if(cDec.ReadByte() >= 0)
throw new SecurityException("ChaCha20-4");
if(!MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 0, 64), pb64))
throw new SecurityException("ChaCha20-5");
if(!MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 64, pbEnc.Length), pb))
throw new SecurityException("ChaCha20-6");
}
}
}
// ======================================================
// Test vector TC8 from RFC draft by J. Strombergson:
// https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01
pbKey = new byte[32] {
0xC4, 0x6E, 0xC1, 0xB1, 0x8C, 0xE8, 0xA8, 0x78,
0x72, 0x5A, 0x37, 0xE7, 0x80, 0xDF, 0xB7, 0x35,
0x1F, 0x68, 0xED, 0x2E, 0x19, 0x4C, 0x79, 0xFB,
0xC6, 0xAE, 0xBE, 0xE1, 0xA6, 0x67, 0x97, 0x5D
};
// The first 4 bytes are set to zero and a large counter
// is used; this makes the RFC 7539 version of ChaCha20
// compatible with the original specification by
// D. J. Bernstein.
pbIV = new byte[12] { 0x00, 0x00, 0x00, 0x00,
0x1A, 0xDA, 0x31, 0xD5, 0xCF, 0x68, 0x82, 0x21
};
pb = new byte[128];
pbExpc = new byte[128] {
0xF6, 0x3A, 0x89, 0xB7, 0x5C, 0x22, 0x71, 0xF9,
0x36, 0x88, 0x16, 0x54, 0x2B, 0xA5, 0x2F, 0x06,
0xED, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2B, 0x00,
0xB5, 0xE8, 0xF8, 0x0A, 0xE9, 0xA4, 0x73, 0xAF,
0xC2, 0x5B, 0x21, 0x8F, 0x51, 0x9A, 0xF0, 0xFD,
0xD4, 0x06, 0x36, 0x2E, 0x8D, 0x69, 0xDE, 0x7F,
0x54, 0xC6, 0x04, 0xA6, 0xE0, 0x0F, 0x35, 0x3F,
0x11, 0x0F, 0x77, 0x1B, 0xDC, 0xA8, 0xAB, 0x92,
0xE5, 0xFB, 0xC3, 0x4E, 0x60, 0xA1, 0xD9, 0xA9,
0xDB, 0x17, 0x34, 0x5B, 0x0A, 0x40, 0x27, 0x36,
0x85, 0x3B, 0xF9, 0x10, 0xB0, 0x60, 0xBD, 0xF1,
0xF8, 0x97, 0xB6, 0x29, 0x0F, 0x01, 0xD1, 0x38,
0xAE, 0x2C, 0x4C, 0x90, 0x22, 0x5B, 0xA9, 0xEA,
0x14, 0xD5, 0x18, 0xF5, 0x59, 0x29, 0xDE, 0xA0,
0x98, 0xCA, 0x7A, 0x6C, 0xCF, 0xE6, 0x12, 0x27,
0x05, 0x3C, 0x84, 0xE4, 0x9A, 0x4A, 0x33, 0x32
};
using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV, true))
{
c.Decrypt(pb, 0, pb.Length);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("ChaCha20-7");
}
#endif
}
private static void TestBlake2b()
{
#if DEBUG
Blake2b h = new Blake2b();
// ======================================================
// From https://tools.ietf.org/html/rfc7693
byte[] pbData = StrUtil.Utf8.GetBytes("abc");
byte[] pbExpc = new byte[64] {
0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D,
0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9,
0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7,
0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1,
0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D,
0xC2, 0x52, 0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95,
0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A,
0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23
};
byte[] pbC = h.ComputeHash(pbData);
if(!MemUtil.ArraysEqual(pbC, pbExpc))
throw new SecurityException("Blake2b-1");
// ======================================================
// Computed using the official b2sum tool
pbExpc = new byte[64] {
0x78, 0x6A, 0x02, 0xF7, 0x42, 0x01, 0x59, 0x03,
0xC6, 0xC6, 0xFD, 0x85, 0x25, 0x52, 0xD2, 0x72,
0x91, 0x2F, 0x47, 0x40, 0xE1, 0x58, 0x47, 0x61,
0x8A, 0x86, 0xE2, 0x17, 0xF7, 0x1F, 0x54, 0x19,
0xD2, 0x5E, 0x10, 0x31, 0xAF, 0xEE, 0x58, 0x53,
0x13, 0x89, 0x64, 0x44, 0x93, 0x4E, 0xB0, 0x4B,
0x90, 0x3A, 0x68, 0x5B, 0x14, 0x48, 0xB7, 0x55,
0xD5, 0x6F, 0x70, 0x1A, 0xFE, 0x9B, 0xE2, 0xCE
};
pbC = h.ComputeHash(MemUtil.EmptyByteArray);
if(!MemUtil.ArraysEqual(pbC, pbExpc))
throw new SecurityException("Blake2b-2");
// ======================================================
// Computed using the official b2sum tool
string strS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;_-\r\n";
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 1000; ++i) sb.Append(strS);
pbData = StrUtil.Utf8.GetBytes(sb.ToString());
pbExpc = new byte[64] {
0x59, 0x69, 0x8D, 0x3B, 0x83, 0xF4, 0x02, 0x4E,
0xD8, 0x99, 0x26, 0x0E, 0xF4, 0xE5, 0x9F, 0x20,
0xDC, 0x31, 0xEE, 0x5B, 0x45, 0xEA, 0xBB, 0xFC,
0x1C, 0x0A, 0x8E, 0xED, 0xAA, 0x7A, 0xFF, 0x50,
0x82, 0xA5, 0x8F, 0xBC, 0x4A, 0x46, 0xFC, 0xC5,
0xEF, 0x44, 0x4E, 0x89, 0x80, 0x7D, 0x3F, 0x1C,
0xC1, 0x94, 0x45, 0xBB, 0xC0, 0x2C, 0x95, 0xAA,
0x3F, 0x08, 0x8A, 0x93, 0xF8, 0x75, 0x91, 0xB0
};
Random r = new Random();
int p = 0;
while(p < pbData.Length)
{
int cb = r.Next(1, pbData.Length - p + 1);
h.TransformBlock(pbData, p, cb, pbData, p);
p += cb;
}
Debug.Assert(p == pbData.Length);
h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0);
if(!MemUtil.ArraysEqual(h.Hash, pbExpc))
throw new SecurityException("Blake2b-3");
h.Clear();
#endif
}
private static void TestArgon2()
{
#if DEBUG
Argon2Kdf kdf = new Argon2Kdf();
// ======================================================
// From the official Argon2 1.3 reference code package
// (test vector for Argon2d 1.3); also on
// https://tools.ietf.org/html/draft-irtf-cfrg-argon2-00
KdfParameters p = kdf.GetDefaultParameters();
kdf.Randomize(p);
Debug.Assert(p.GetUInt32(Argon2Kdf.ParamVersion, 0) == 0x13U);
byte[] pbMsg = new byte[32];
for(int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = 1;
p.SetUInt64(Argon2Kdf.ParamMemory, 32 * 1024);
p.SetUInt64(Argon2Kdf.ParamIterations, 3);
p.SetUInt32(Argon2Kdf.ParamParallelism, 4);
byte[] pbSalt = new byte[16];
for(int i = 0; i < pbSalt.Length; ++i) pbSalt[i] = 2;
p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt);
byte[] pbKey = new byte[8];
for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 3;
p.SetByteArray(Argon2Kdf.ParamSecretKey, pbKey);
byte[] pbAssoc = new byte[12];
for(int i = 0; i < pbAssoc.Length; ++i) pbAssoc[i] = 4;
p.SetByteArray(Argon2Kdf.ParamAssocData, pbAssoc);
byte[] pbExpc = new byte[32] {
0x51, 0x2B, 0x39, 0x1B, 0x6F, 0x11, 0x62, 0x97,
0x53, 0x71, 0xD3, 0x09, 0x19, 0x73, 0x42, 0x94,
0xF8, 0x68, 0xE3, 0xBE, 0x39, 0x84, 0xF3, 0xC1,
0xA1, 0x3A, 0x4D, 0xB9, 0xFA, 0xBE, 0x4A, 0xCB
};
byte[] pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-1");
// ======================================================
// From the official Argon2 1.3 reference code package
// (test vector for Argon2d 1.0)
p.SetUInt32(Argon2Kdf.ParamVersion, 0x10);
pbExpc = new byte[32] {
0x96, 0xA9, 0xD4, 0xE5, 0xA1, 0x73, 0x40, 0x92,
0xC8, 0x5E, 0x29, 0xF4, 0x10, 0xA4, 0x59, 0x14,
0xA5, 0xDD, 0x1F, 0x5C, 0xBF, 0x08, 0xB2, 0x67,
0x0D, 0xA6, 0x8A, 0x02, 0x85, 0xAB, 0xF3, 0x2B
};
pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-2");
// ======================================================
// From the official 'phc-winner-argon2-20151206.zip'
// (test vector for Argon2d 1.0)
p.SetUInt64(Argon2Kdf.ParamMemory, 16 * 1024);
pbExpc = new byte[32] {
0x57, 0xB0, 0x61, 0x3B, 0xFD, 0xD4, 0x13, 0x1A,
0x0C, 0x34, 0x88, 0x34, 0xC6, 0x72, 0x9C, 0x2C,
0x72, 0x29, 0x92, 0x1E, 0x6B, 0xBA, 0x37, 0x66,
0x5D, 0x97, 0x8C, 0x4F, 0xE7, 0x17, 0x5E, 0xD2
};
pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-3");
#if SELFTEST_ARGON2_LONG
// ======================================================
// Computed using the official 'argon2' application
// (test vectors for Argon2d 1.3)
p = kdf.GetDefaultParameters();
pbMsg = StrUtil.Utf8.GetBytes("ABC1234");
p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 11) * 1024); // 2 MB
p.SetUInt64(Argon2Kdf.ParamIterations, 2);
p.SetUInt32(Argon2Kdf.ParamParallelism, 2);
pbSalt = StrUtil.Utf8.GetBytes("somesalt");
p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt);
pbExpc = new byte[32] {
0x29, 0xCB, 0xD3, 0xA1, 0x93, 0x76, 0xF7, 0xA2,
0xFC, 0xDF, 0xB0, 0x68, 0xAC, 0x0B, 0x99, 0xBA,
0x40, 0xAC, 0x09, 0x01, 0x73, 0x42, 0xCE, 0xF1,
0x29, 0xCC, 0xA1, 0x4F, 0xE1, 0xC1, 0xB7, 0xA3
};
pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-4");
p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 10) * 1024); // 1 MB
p.SetUInt64(Argon2Kdf.ParamIterations, 3);
pbExpc = new byte[32] {
0x7A, 0xBE, 0x1C, 0x1C, 0x8D, 0x7F, 0xD6, 0xDC,
0x7C, 0x94, 0x06, 0x3E, 0xD8, 0xBC, 0xD8, 0x1C,
0x2F, 0x87, 0x84, 0x99, 0x12, 0x83, 0xFE, 0x76,
0x00, 0x64, 0xC4, 0x58, 0xA4, 0xDA, 0x35, 0x70
};
pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-5");
#if SELFTEST_ARGON2_LONGER
p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 20) * 1024); // 1 GB
p.SetUInt64(Argon2Kdf.ParamIterations, 2);
p.SetUInt32(Argon2Kdf.ParamParallelism, 3);
pbExpc = new byte[32] {
0xE6, 0xE7, 0xCB, 0xF5, 0x5A, 0x06, 0x93, 0x05,
0x32, 0xBA, 0x86, 0xC6, 0x1F, 0x45, 0x17, 0x99,
0x65, 0x41, 0x77, 0xF9, 0x30, 0x55, 0x9A, 0xE8,
0x3D, 0x21, 0x48, 0xC6, 0x2D, 0x0C, 0x49, 0x11
};
pb = kdf.Transform(pbMsg, p);
if(!MemUtil.ArraysEqual(pb, pbExpc))
throw new SecurityException("Argon2-6");
#endif // SELFTEST_ARGON2_LONGER
#endif // SELFTEST_ARGON2_LONG
#endif // DEBUG
}
private static void TestHmac()
{
#if DEBUG
// Test vectors from RFC 4231
byte[] pbKey = new byte[20];
for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 0x0B;
byte[] pbMsg = StrUtil.Utf8.GetBytes("Hi There");
byte[] pbExpc = new byte[32] {
0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53,
0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B,
0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7,
0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7
};
HmacEval(pbKey, pbMsg, pbExpc, "1");
pbKey = new byte[131];
for(int i = 0; i < pbKey.Length; ++i) pbKey[i] = 0xAA;
pbMsg = StrUtil.Utf8.GetBytes(
"This is a test using a larger than block-size key and " +
"a larger than block-size data. The key needs to be " +
"hashed before being used by the HMAC algorithm.");
pbExpc = new byte[32] {
0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB,
0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44,
0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93,
0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2
};
HmacEval(pbKey, pbMsg, pbExpc, "2");
#endif
}
#if DEBUG
private static void HmacEval(byte[] pbKey, byte[] pbMsg,
byte[] pbExpc, string strID)
{
using(HMACSHA256 h = new HMACSHA256(pbKey))
{
h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0);
h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0);
byte[] pbHash = h.Hash;
if(!MemUtil.ArraysEqual(pbHash, pbExpc))
throw new SecurityException("HMAC-SHA-256-" + strID);
// Reuse the object
h.Initialize();
h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0);
h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0);
pbHash = h.Hash;
if(!MemUtil.ArraysEqual(pbHash, pbExpc))
throw new SecurityException("HMAC-SHA-256-" + strID + "-R");
}
}
#endif
private static void TestNativeKeyTransform() private static void TestNativeKeyTransform()
{ {
#if DEBUG #if DEBUG
@ -205,16 +710,16 @@ namespace KeePassLib.Cryptography
byte[] pbManaged = new byte[32]; byte[] pbManaged = new byte[32];
Array.Copy(pbOrgKey, pbManaged, 32); Array.Copy(pbOrgKey, pbManaged, 32);
if(CompositeKey.TransformKeyManaged(pbManaged, pbSeed, uRounds) == false) if(!AesKdf.TransformKeyManaged(pbManaged, pbSeed, uRounds))
throw new SecurityException("Managed transform."); throw new SecurityException("AES-KDF-1");
byte[] pbNative = new byte[32]; byte[] pbNative = new byte[32];
Array.Copy(pbOrgKey, pbNative, 32); Array.Copy(pbOrgKey, pbNative, 32);
if(NativeLib.TransformKey256(pbNative, pbSeed, uRounds) == false) if(!NativeLib.TransformKey256(pbNative, pbSeed, uRounds))
return; // Native library not available ("success") return; // Native library not available ("success")
if(!MemUtil.ArraysEqual(pbManaged, pbNative)) if(!MemUtil.ArraysEqual(pbManaged, pbNative))
throw new SecurityException("Native transform."); throw new SecurityException("AES-KDF-2");
#endif #endif
} }
@ -252,12 +757,49 @@ namespace KeePassLib.Cryptography
pbN = enc.GetBytes("012b"); pbN = enc.GetBytes("012b");
if(MemUtil.IndexOf<byte>(pb, pbN) >= 0) if(MemUtil.IndexOf<byte>(pb, pbN) >= 0)
throw new InvalidOperationException("MemUtil-7"); throw new InvalidOperationException("MemUtil-7");
byte[] pbRes = MemUtil.ParseBase32("MY======");
byte[] pbExp = Encoding.ASCII.GetBytes("f");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-1");
pbRes = MemUtil.ParseBase32("MZXQ====");
pbExp = Encoding.ASCII.GetBytes("fo");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-2");
pbRes = MemUtil.ParseBase32("MZXW6===");
pbExp = Encoding.ASCII.GetBytes("foo");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-3");
pbRes = MemUtil.ParseBase32("MZXW6YQ=");
pbExp = Encoding.ASCII.GetBytes("foob");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-4");
pbRes = MemUtil.ParseBase32("MZXW6YTB");
pbExp = Encoding.ASCII.GetBytes("fooba");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-5");
pbRes = MemUtil.ParseBase32("MZXW6YTBOI======");
pbExp = Encoding.ASCII.GetBytes("foobar");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-6");
pbRes = MemUtil.ParseBase32("JNSXSIDQOJXXM2LEMVZCAYTBONSWIIDPNYQG63TFFV2GS3LFEBYGC43TO5XXEZDTFY======");
pbExp = Encoding.ASCII.GetBytes("Key provider based on one-time passwords.");
if(!MemUtil.ArraysEqual(pbRes, pbExp)) throw new Exception("Base32-7");
int i = 0 - 0x10203040;
pbRes = MemUtil.Int32ToBytes(i);
if(MemUtil.ByteArrayToHexString(pbRes) != "C0CFDFEF")
throw new Exception("MemUtil-8"); // Must be little-endian
if(MemUtil.BytesToUInt32(pbRes) != (uint)i)
throw new Exception("MemUtil-9");
if(MemUtil.BytesToInt32(pbRes) != i)
throw new Exception("MemUtil-10");
#endif #endif
} }
private static void TestHmacOtp() private static void TestHmacOtp()
{ {
#if (DEBUG && !KeePassLibSD && !KeePassRT) #if (DEBUG && !KeePassLibSD)
byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890"); byte[] pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890");
string[] vExp = new string[]{ "755224", "287082", "359152", string[] vExp = new string[]{ "755224", "287082", "359152",
"969429", "338314", "254676", "287922", "162583", "399871", "969429", "338314", "254676", "287922", "162583", "399871",
@ -325,6 +867,41 @@ namespace KeePassLib.Cryptography
throw new SecurityException("ProtectedString-8"); throw new SecurityException("ProtectedString-8");
if(!ps.IsProtected) throw new SecurityException("ProtectedString-9"); if(!ps.IsProtected) throw new SecurityException("ProtectedString-9");
if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10"); if(!ps2.IsProtected) throw new SecurityException("ProtectedString-10");
Random r = new Random();
string str = string.Empty;
ps = new ProtectedString();
for(int i = 0; i < 100; ++i)
{
bool bProt = ((r.Next() % 4) != 0);
ps = ps.WithProtection(bProt);
int x = r.Next(str.Length + 1);
int c = r.Next(20);
char ch = (char)r.Next(1, 256);
string strIns = new string(ch, c);
str = str.Insert(x, strIns);
ps = ps.Insert(x, strIns);
if(ps.IsProtected != bProt)
throw new SecurityException("ProtectedString-11");
if(ps.ReadString() != str)
throw new SecurityException("ProtectedString-12");
ps = ps.WithProtection(bProt);
x = r.Next(str.Length);
c = r.Next(str.Length - x + 1);
str = str.Remove(x, c);
ps = ps.Remove(x, c);
if(ps.IsProtected != bProt)
throw new SecurityException("ProtectedString-13");
if(ps.ReadString() != str)
throw new SecurityException("ProtectedString-14");
}
#endif #endif
} }
@ -365,10 +942,16 @@ namespace KeePassLib.Cryptography
throw new InvalidOperationException("StrUtil-V3"); throw new InvalidOperationException("StrUtil-V3");
if(StrUtil.VersionToString(0x00FF000000000000UL) != "255") if(StrUtil.VersionToString(0x00FF000000000000UL) != "255")
throw new InvalidOperationException("StrUtil-V4"); throw new InvalidOperationException("StrUtil-V4");
if(StrUtil.VersionToString(0x00FF000000000000UL, true) != "255.0") if(StrUtil.VersionToString(0x00FF000000000000UL, 2) != "255.0")
throw new InvalidOperationException("StrUtil-V5"); throw new InvalidOperationException("StrUtil-V5");
if(StrUtil.VersionToString(0x0000000000070000UL, true) != "0.0.7") if(StrUtil.VersionToString(0x0000000000070000UL) != "0.0.7")
throw new InvalidOperationException("StrUtil-V6"); throw new InvalidOperationException("StrUtil-V6");
if(StrUtil.VersionToString(0x0000000000000000UL) != "0")
throw new InvalidOperationException("StrUtil-V7");
if(StrUtil.VersionToString(0x00000000FFFF0000UL, 4) != "0.0.65535.0")
throw new InvalidOperationException("StrUtil-V8");
if(StrUtil.VersionToString(0x0000000000000000UL, 4) != "0.0.0.0")
throw new InvalidOperationException("StrUtil-V9");
if(StrUtil.RtfEncodeChar('\u0000') != "\\u0?") if(StrUtil.RtfEncodeChar('\u0000') != "\\u0?")
throw new InvalidOperationException("StrUtil-Rtf1"); throw new InvalidOperationException("StrUtil-Rtf1");
@ -411,12 +994,22 @@ namespace KeePassLib.Cryptography
if(short.MinValue.ToString(NumberFormatInfo.InvariantInfo) != if(short.MinValue.ToString(NumberFormatInfo.InvariantInfo) !=
"-32768") "-32768")
throw new InvalidOperationException("StrUtil-Inv4"); throw new InvalidOperationException("StrUtil-Inv4");
if(!string.Equals("abcd", "aBcd", StrUtil.CaseIgnoreCmp))
throw new InvalidOperationException("StrUtil-Case1");
if(string.Equals(@"a<b", @"a>b", StrUtil.CaseIgnoreCmp))
throw new InvalidOperationException("StrUtil-Case2");
#endif #endif
} }
private static void TestUrlUtil() private static void TestUrlUtil()
{ {
#if DEBUG #if DEBUG
#if !KeePassUAP
Debug.Assert(Uri.UriSchemeHttp.Equals("http", StrUtil.CaseIgnoreCmp));
Debug.Assert(Uri.UriSchemeHttps.Equals("https", StrUtil.CaseIgnoreCmp));
#endif
if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") != if(UrlUtil.GetHost(@"scheme://domain:port/path?query_string#fragment_id") !=
"domain") "domain")
throw new InvalidOperationException("UrlUtil-H1"); throw new InvalidOperationException("UrlUtil-H1");

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -39,18 +39,18 @@ namespace KeePassLib.Interfaces
} }
/// <summary> /// <summary>
/// The date/time when the object was last accessed. /// The date/time when the object was last modified.
/// </summary> /// </summary>
DateTime LastAccessTime DateTime LastModificationTime
{ {
get; get;
set; set;
} }
/// <summary> /// <summary>
/// The date/time when the object was last modified. /// The date/time when the object was last accessed.
/// </summary> /// </summary>
DateTime LastModificationTime DateTime LastAccessTime
{ {
get; get;
set; set;
@ -101,19 +101,5 @@ namespace KeePassLib.Interfaces
/// </summary> /// </summary>
/// <param name="bModified">Update last modification time.</param> /// <param name="bModified">Update last modification time.</param>
void Touch(bool bModified); void Touch(bool bModified);
#region Set times lazily
// Passing xml datetime string to be parsed only on demand
void SetLazyLastModificationTime(string xmlDateTime);
void SetLazyCreationTime(string xmlDateTime);
void SetLazyLastAccessTime(string xmlDateTime);
void SetLazyExpiryTime(string xmlDateTime);
void SetLazyLocationChanged(string xmlDateTime);
#endregion
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,12 +19,11 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Diagnostics; using System.Diagnostics;
using System.Security.Cryptography; using System.Text;
using KeePassLib.Cryptography;
using KeePassLib.Security; using KeePassLib.Security;
using KeePassLib.Utility;
namespace KeePassLib.Keys namespace KeePassLib.Keys
{ {
@ -55,8 +54,7 @@ namespace KeePassLib.Keys
if(bPerformHash) if(bPerformHash)
{ {
SHA256Managed sha256 = new SHA256Managed(); byte[] pbRaw = CryptoUtil.HashSha256(pbKeyData);
byte[] pbRaw = sha256.ComputeHash(pbKeyData);
m_pbKey = new ProtectedBinary(true, pbRaw); m_pbKey = new ProtectedBinary(true, pbRaw);
} }
else m_pbKey = new ProtectedBinary(true, pbKeyData); else m_pbKey = new ProtectedBinary(true, pbKeyData);

View File

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

View File

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

View File

@ -1,8 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -43,7 +41,7 @@ namespace KeePassLib.Keys
private ProtectedBinary m_pbKeyData = null; private ProtectedBinary m_pbKeyData = null;
// Constant initialization vector (unique for KeePass) // Constant initialization vector (unique for KeePass)
private static readonly byte[] m_pbEntropy = new byte[]{ private static readonly byte[] m_pbEntropy = new byte[] {
0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70, 0xDE, 0x13, 0x5B, 0x5F, 0x18, 0xA3, 0x46, 0x70,
0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6 0xB2, 0x57, 0x24, 0x29, 0x69, 0x88, 0x98, 0xE6
}; };
@ -65,7 +63,22 @@ namespace KeePassLib.Keys
/// </summary> /// </summary>
public KcpUserAccount() public KcpUserAccount()
{ {
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!"); // 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) // Should never happen
{
Debug.Assert(false);
throw new SecurityException(KLRes.UserAccountKeyError);
}
m_pbKeyData = new ProtectedBinary(true, pbKey);
MemUtil.ZeroByteArray(pbKey);
} }
// public void Clear() // public void Clear()
@ -75,8 +88,8 @@ namespace KeePassLib.Keys
private static string GetUserKeyFilePath(bool bCreate) private static string GetUserKeyFilePath(bool bCreate)
{ {
#if KeePassRT #if KeePassUAP
string strUserDir = Windows.Storage.ApplicationData.Current.RoamingFolder.Path; string strUserDir = EnvironmentExt.AppDataRoamingFolderPath;
#else #else
string strUserDir = Environment.GetFolderPath( string strUserDir = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData); Environment.SpecialFolder.ApplicationData);
@ -89,22 +102,25 @@ namespace KeePassLib.Keys
Directory.CreateDirectory(strUserDir); Directory.CreateDirectory(strUserDir);
strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false); strUserDir = UrlUtil.EnsureTerminatingSeparator(strUserDir, false);
return strUserDir + UserKeyFileName; return (strUserDir + UserKeyFileName);
} }
private static byte[] LoadUserKey(bool bShowWarning) private static byte[] LoadUserKey(bool bThrow)
{ {
byte[] pbKey = null; byte[] pbKey = null;
#if !KeePassLibSD #if !KeePassLibSD
try try
{ {
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!"); string strFilePath = GetUserKeyFilePath(false);
} byte[] pbProtectedKey = File.ReadAllBytes(strFilePath);
catch(Exception exLoad)
{
if(bShowWarning) MessageService.ShowWarning(exLoad);
pbKey = ProtectedData.Unprotect(pbProtectedKey, m_pbEntropy,
DataProtectionScope.CurrentUser);
}
catch(Exception)
{
if(bThrow) throw;
pbKey = null; pbKey = null;
} }
#endif #endif
@ -114,17 +130,23 @@ namespace KeePassLib.Keys
private static byte[] CreateUserKey() private static byte[] CreateUserKey()
{ {
byte[] pbKey = null; #if KeePassLibSD
return null;
#else
string strFilePath = GetUserKeyFilePath(true);
#if !KeePassLibSD byte[] pbRandomKey = CryptoRandom.Instance.GetRandomBytes(64);
try byte[] pbProtectedKey = ProtectedData.Protect(pbRandomKey,
{ m_pbEntropy, DataProtectionScope.CurrentUser);
throw new NotSupportedException("DataProtection not supported on MonoForAndroid!");
}
catch(Exception) { pbKey = null; }
#endif
File.WriteAllBytes(strFilePath, pbProtectedKey);
byte[] pbKey = LoadUserKey(true);
Debug.Assert(MemUtil.ArraysEqual(pbKey, pbRandomKey));
MemUtil.ZeroByteArray(pbRandomKey);
return pbKey; return pbKey;
#endif
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -27,7 +27,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Dominik Reichl")] [assembly: AssemblyCompany("Dominik Reichl")]
[assembly: AssemblyProduct("KeePassLib")] [assembly: AssemblyProduct("KeePassLib")]
[assembly: AssemblyCopyright("Copyright © 2003-2016 Dominik Reichl")] [assembly: AssemblyCopyright("Copyright © 2003-2017 Dominik Reichl")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
@ -38,5 +38,5 @@ using System.Runtime.InteropServices;
[assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")] [assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")]
// Assembly version information // Assembly version information
[assembly: AssemblyVersion("2.34.0.*")] [assembly: AssemblyVersion("2.35.0.*")]
[assembly: AssemblyFileVersion("2.34.0.0")] [assembly: AssemblyFileVersion("2.35.0.0")]

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -79,6 +79,7 @@ namespace KeePassLib
private DateTime m_dtKeyLastChanged = PwDefs.DtDefaultNow; private DateTime m_dtKeyLastChanged = PwDefs.DtDefaultNow;
private long m_lKeyChangeRecDays = -1; private long m_lKeyChangeRecDays = -1;
private long m_lKeyChangeForceDays = -1; private long m_lKeyChangeForceDays = -1;
private bool m_bKeyChangeForceOnce = false;
private IOConnectionInfo m_ioSource = new IOConnectionInfo(); private IOConnectionInfo m_ioSource = new IOConnectionInfo();
private bool m_bDatabaseOpened = false; private bool m_bDatabaseOpened = false;
@ -269,6 +270,12 @@ namespace KeePassLib
set { m_lKeyChangeForceDays = value; } set { m_lKeyChangeForceDays = value; }
} }
public bool MasterKeyChangeForceOnce
{
get { return m_bKeyChangeForceOnce; }
set { m_bKeyChangeForceOnce = value; }
}
/// <summary> /// <summary>
/// The encryption algorithm used to encrypt the data part of the database. /// The encryption algorithm used to encrypt the data part of the database.
/// </summary> /// </summary>
@ -537,7 +544,7 @@ namespace KeePassLib
m_vCustomIcons = new List<PwCustomIcon>(); m_vCustomIcons = new List<PwCustomIcon>();
m_bUINeedsIconUpdate = true; m_bUINeedsIconUpdate = true;
DateTime dtNow = DateTime.Now; DateTime dtNow = DateTime.UtcNow;
m_dtSettingsChanged = dtNow; m_dtSettingsChanged = dtNow;
m_strName = string.Empty; m_strName = string.Empty;
@ -552,6 +559,7 @@ namespace KeePassLib
m_dtKeyLastChanged = dtNow; m_dtKeyLastChanged = dtNow;
m_lKeyChangeRecDays = -1; m_lKeyChangeRecDays = -1;
m_lKeyChangeForceDays = -1; m_lKeyChangeForceDays = -1;
m_bKeyChangeForceOnce = false;
m_ioSource = new IOConnectionInfo(); m_ioSource = new IOConnectionInfo();
m_bDatabaseOpened = false; m_bDatabaseOpened = false;
@ -1347,7 +1355,7 @@ namespace KeePassLib
where T : class, ITimeLogger, IStructureItem, IDeepCloneable<T> where T : class, ITimeLogger, IStructureItem, IDeepCloneable<T>
{ {
PwObjectPoolEx p = null; PwObjectPoolEx p = null;
dtLoc = DateTime.MinValue; dtLoc = TimeUtil.SafeMinValueUtc;
IStructureItem ptOrg = ppOrg.GetItemByUuid(t.Uuid); IStructureItem ptOrg = ppOrg.GetItemByUuid(t.Uuid);
if(ptOrg != null) if(ptOrg != null)
@ -1374,7 +1382,7 @@ namespace KeePassLib
pPool = null; pPool = null;
int iPosMax = kvpRange.Key; int iPosMax = kvpRange.Key;
DateTime dtMax = DateTime.MinValue; DateTime dtMax = TimeUtil.SafeMinValueUtc;
for(int i = kvpRange.Key; i <= kvpRange.Value; ++i) for(int i = kvpRange.Key; i <= kvpRange.Value; ++i)
{ {
@ -1885,7 +1893,7 @@ namespace KeePassLib
if(m_bUseRecycleBin) if(m_bUseRecycleBin)
pgRecycleBin = m_pgRootGroup.FindGroup(m_pwRecycleBin, true); pgRecycleBin = m_pgRootGroup.FindGroup(m_pwRecycleBin, true);
DateTime dtNow = DateTime.Now; DateTime dtNow = DateTime.UtcNow;
PwObjectList<PwEntry> l = m_pgRootGroup.GetEntries(true); PwObjectList<PwEntry> l = m_pgRootGroup.GetEntries(true);
int i = 0; int i = 0;
while(true) while(true)
@ -2010,7 +2018,7 @@ namespace KeePassLib
if((pg.Groups.UCount > 0) || (pg.Entries.UCount > 0)) continue; if((pg.Groups.UCount > 0) || (pg.Entries.UCount > 0)) continue;
pg.ParentGroup.Groups.Remove(pg); pg.ParentGroup.Groups.Remove(pg);
m_vDeletedObjects.Add(new PwDeletedObject(pg.Uuid, DateTime.Now)); m_vDeletedObjects.Add(new PwDeletedObject(pg.Uuid, DateTime.UtcNow));
++uDeleted; ++uDeleted;
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -55,20 +55,20 @@ namespace KeePassLib
/// e.g. 2.19 = 0x02130000. /// e.g. 2.19 = 0x02130000.
/// It is highly recommended to use <c>FileVersion64</c> instead. /// It is highly recommended to use <c>FileVersion64</c> instead.
/// </summary> /// </summary>
public const uint Version32 = 0x02220000; public const uint Version32 = 0x02230000;
/// <summary> /// <summary>
/// Version, encoded as 64-bit unsigned integer /// Version, encoded as 64-bit unsigned integer
/// (component-wise, 16 bits per component). /// (component-wise, 16 bits per component).
/// </summary> /// </summary>
public const ulong FileVersion64 = 0x0002002200000000UL; public const ulong FileVersion64 = 0x0002002300000000UL;
/// <summary> /// <summary>
/// Version, encoded as string. /// Version, encoded as string.
/// </summary> /// </summary>
public const string VersionString = "2.34"; public const string VersionString = "2.35";
public const string Copyright = @"Copyright © 2003-2016 Dominik Reichl"; public const string Copyright = @"Copyright © 2003-2017 Dominik Reichl";
/// <summary> /// <summary>
/// Product website URL. Terminated by a forward slash. /// Product website URL. Terminated by a forward slash.
@ -107,10 +107,11 @@ namespace KeePassLib
/// A <c>DateTime</c> object that represents the time when the assembly /// A <c>DateTime</c> object that represents the time when the assembly
/// was loaded. /// was loaded.
/// </summary> /// </summary>
public static readonly DateTime DtDefaultNow = DateTime.Now; public static readonly DateTime DtDefaultNow = DateTime.UtcNow;
/// <summary> /// <summary>
/// Default number of master key encryption/transformation rounds (making dictionary attacks harder). /// Default number of master key encryption/transformation rounds
/// (making dictionary attacks harder).
/// </summary> /// </summary>
public const ulong DefaultKeyEncryptionRounds = 500000; public const ulong DefaultKeyEncryptionRounds = 500000;

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -343,8 +343,11 @@ namespace KeePassLib
if(bSetTimes) if(bSetTimes)
{ {
m_tCreation = m_tLastMod = m_tLastAccess = DateTime dtNow = DateTime.UtcNow;
m_tParentGroupLastMod = DateTime.Now; m_tCreation = dtNow;
m_tLastMod = dtNow;
m_tLastAccess = dtNow;
m_tParentGroupLastMod = dtNow;
} }
} }
@ -368,8 +371,11 @@ namespace KeePassLib
if(bSetTimes) if(bSetTimes)
{ {
m_tCreation = m_tLastMod = m_tLastAccess = DateTime dtNow = DateTime.UtcNow;
m_tParentGroupLastMod = DateTime.Now; m_tCreation = dtNow;
m_tLastMod = dtNow;
m_tLastAccess = dtNow;
m_tParentGroupLastMod = dtNow;
} }
} }
@ -622,7 +628,7 @@ namespace KeePassLib
/// get touched, too.</param> /// get touched, too.</param>
public void Touch(bool bModified, bool bTouchParents) public void Touch(bool bModified, bool bTouchParents)
{ {
m_tLastAccess = DateTime.Now; m_tLastAccess = DateTime.UtcNow;
++m_uUsageCount; ++m_uUsageCount;
if(bModified) m_tLastMod = m_tLastAccess; if(bModified) m_tLastMod = m_tLastAccess;
@ -761,7 +767,7 @@ namespace KeePassLib
private void RemoveOldestBackup() private void RemoveOldestBackup()
{ {
DateTime dtMin = DateTime.MaxValue; DateTime dtMin = TimeUtil.SafeMaxValueUtc;
uint idxRemove = uint.MaxValue; uint idxRemove = uint.MaxValue;
for(uint u = 0; u < m_listHistory.UCount; ++u) for(uint u = 0; u < m_listHistory.UCount; ++u)
@ -936,7 +942,7 @@ namespace KeePassLib
public void SetCreatedNow() public void SetCreatedNow()
{ {
DateTime dt = DateTime.Now; DateTime dt = DateTime.UtcNow;
m_tCreation = dt; m_tCreation = dt;
m_tLastAccess = dt; m_tLastAccess = dt;

View File

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

View File

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

View File

@ -33,7 +33,9 @@ namespace KeePassLib.Resources
m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError); m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError);
m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText); m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText);
m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted); m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted);
m_strFileHeaderEndEarly = TryGetEx(dictNew, "FileHeaderEndEarly", m_strFileHeaderEndEarly); m_strFileHeaderCorrupted = TryGetEx(dictNew, "FileHeaderCorrupted", m_strFileHeaderCorrupted);
m_strFileIncomplete = TryGetEx(dictNew, "FileIncomplete", m_strFileIncomplete);
m_strFileIncompleteExpc = TryGetEx(dictNew, "FileIncompleteExpc", m_strFileIncompleteExpc);
m_strFileLoadFailed = TryGetEx(dictNew, "FileLoadFailed", m_strFileLoadFailed); m_strFileLoadFailed = TryGetEx(dictNew, "FileLoadFailed", m_strFileLoadFailed);
m_strFileLockedWrite = TryGetEx(dictNew, "FileLockedWrite", m_strFileLockedWrite); m_strFileLockedWrite = TryGetEx(dictNew, "FileLockedWrite", m_strFileLockedWrite);
m_strFileNewVerOrPlgReq = TryGetEx(dictNew, "FileNewVerOrPlgReq", m_strFileNewVerOrPlgReq); m_strFileNewVerOrPlgReq = TryGetEx(dictNew, "FileNewVerOrPlgReq", m_strFileNewVerOrPlgReq);
@ -73,7 +75,9 @@ namespace KeePassLib.Resources
"FatalError", "FatalError",
"FatalErrorText", "FatalErrorText",
"FileCorrupted", "FileCorrupted",
"FileHeaderEndEarly", "FileHeaderCorrupted",
"FileIncomplete",
"FileIncompleteExpc",
"FileLoadFailed", "FileLoadFailed",
"FileLockedWrite", "FileLockedWrite",
"FileNewVerOrPlgReq", "FileNewVerOrPlgReq",
@ -187,15 +191,37 @@ namespace KeePassLib.Resources
get { return m_strFileCorrupted; } get { return m_strFileCorrupted; }
} }
private static string m_strFileHeaderEndEarly = private static string m_strFileHeaderCorrupted =
@"The file header is corrupted! Some header data was declared but is not present."; @"The file header is corrupted.";
/// <summary> /// <summary>
/// Look up a localized string similar to /// Look up a localized string similar to
/// 'The file header is corrupted! Some header data was declared but is not present.'. /// 'The file header is corrupted.'.
/// </summary> /// </summary>
public static string FileHeaderEndEarly public static string FileHeaderCorrupted
{ {
get { return m_strFileHeaderEndEarly; } get { return m_strFileHeaderCorrupted; }
}
private static string m_strFileIncomplete =
@"Data is missing at the end of the file, i.e. the file is incomplete.";
/// <summary>
/// Look up a localized string similar to
/// 'Data is missing at the end of the file, i.e. the file is incomplete.'.
/// </summary>
public static string FileIncomplete
{
get { return m_strFileIncomplete; }
}
private static string m_strFileIncompleteExpc =
@"Less data than expected could be read from the file.";
/// <summary>
/// Look up a localized string similar to
/// 'Less data than expected could be read from the file.'.
/// </summary>
public static string FileIncompleteExpc
{
get { return m_strFileIncompleteExpc; }
} }
private static string m_strFileLoadFailed = private static string m_strFileLoadFailed =

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -165,7 +165,7 @@ namespace KeePassLib.Security
/// </summary> /// </summary>
public ProtectedBinary() public ProtectedBinary()
{ {
Init(false, MemUtil.EmptyByteArray); Init(false, MemUtil.EmptyByteArray, 0, 0);
} }
/// <summary> /// <summary>
@ -180,7 +180,27 @@ namespace KeePassLib.Security
/// i.e. the caller is responsible for clearing it.</param> /// i.e. the caller is responsible for clearing it.</param>
public ProtectedBinary(bool bEnableProtection, byte[] pbData) public ProtectedBinary(bool bEnableProtection, byte[] pbData)
{ {
Init(bEnableProtection, pbData); if(pbData == null) throw new ArgumentNullException("pbData");
Init(bEnableProtection, pbData, 0, pbData.Length);
}
/// <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>
/// <param name="iOffset">Offset for <paramref name="pbData" />.</param>
/// <param name="cbSize">Size for <paramref name="pbData" />.</param>
public ProtectedBinary(bool bEnableProtection, byte[] pbData,
int iOffset, int cbSize)
{
Init(bEnableProtection, pbData, iOffset, cbSize);
} }
/// <summary> /// <summary>
@ -196,14 +216,19 @@ namespace KeePassLib.Security
if(xbProtected == null) throw new ArgumentNullException("xbProtected"); if(xbProtected == null) throw new ArgumentNullException("xbProtected");
byte[] pb = xbProtected.ReadPlainText(); byte[] pb = xbProtected.ReadPlainText();
Init(bEnableProtection, pb); Init(bEnableProtection, pb, 0, pb.Length);
if(bEnableProtection) MemUtil.ZeroByteArray(pb); if(bEnableProtection) MemUtil.ZeroByteArray(pb);
} }
private void Init(bool bEnableProtection, byte[] pbData) private void Init(bool bEnableProtection, byte[] pbData, int iOffset,
int cbSize)
{ {
if(pbData == null) throw new ArgumentNullException("pbData"); if(pbData == null) throw new ArgumentNullException("pbData");
if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset");
if(cbSize < 0) throw new ArgumentOutOfRangeException("cbSize");
if(iOffset > (pbData.Length - cbSize))
throw new ArgumentOutOfRangeException("cbSize");
#if KeePassLibSD #if KeePassLibSD
m_lID = ++g_lCurID; m_lID = ++g_lCurID;
@ -212,15 +237,15 @@ namespace KeePassLib.Security
#endif #endif
m_bProtected = bEnableProtection; m_bProtected = bEnableProtection;
m_uDataLen = (uint)pbData.Length; m_uDataLen = (uint)cbSize;
const int bs = ProtectedBinary.BlockSize; const int bs = ProtectedBinary.BlockSize;
int nBlocks = (int)m_uDataLen / bs; int nBlocks = cbSize / bs;
if((nBlocks * bs) < (int)m_uDataLen) ++nBlocks; if((nBlocks * bs) < cbSize) ++nBlocks;
Debug.Assert((nBlocks * bs) >= (int)m_uDataLen); Debug.Assert((nBlocks * bs) >= cbSize);
m_pbData = new byte[nBlocks * bs]; m_pbData = new byte[nBlocks * bs];
Array.Copy(pbData, m_pbData, (int)m_uDataLen); Array.Copy(pbData, iOffset, m_pbData, 0, cbSize);
Encrypt(); Encrypt();
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -282,7 +282,7 @@ namespace KeePassLib.Security
} }
finally finally
{ {
Array.Clear(v, 0, v.Length); MemUtil.ZeroArray<char>(v);
MemUtil.ZeroByteArray(pb); MemUtil.ZeroByteArray(pb);
} }
@ -292,7 +292,7 @@ namespace KeePassLib.Security
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Insert(iStart, strInsert)); ReadString().Insert(iStart, strInsert));
Array.Clear(vNew, 0, vNew.Length); MemUtil.ZeroArray<char>(vNew);
MemUtil.ZeroByteArray(pbNew); MemUtil.ZeroByteArray(pbNew);
return ps; return ps;
} }
@ -328,7 +328,7 @@ namespace KeePassLib.Security
} }
finally finally
{ {
Array.Clear(v, 0, v.Length); MemUtil.ZeroArray<char>(v);
MemUtil.ZeroByteArray(pb); MemUtil.ZeroByteArray(pb);
} }
@ -338,7 +338,7 @@ namespace KeePassLib.Security
Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) ==
ReadString().Remove(iStart, nCount)); ReadString().Remove(iStart, nCount));
Array.Clear(vNew, 0, vNew.Length); MemUtil.ZeroArray<char>(vNew);
MemUtil.ZeroByteArray(pbNew); MemUtil.ZeroByteArray(pbNew);
return ps; return ps;
} }

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -31,7 +31,7 @@ namespace KeePassLib.Serialization
private Stream m_s; private Stream m_s;
// private Encoding m_enc; // See constructor // private Encoding m_enc; // See constructor
private string m_strReadExcp; private string m_strReadExcp; // May be null
public string ReadExceptionText public string ReadExceptionText
{ {
get { return m_strReadExcp; } get { return m_strReadExcp; }
@ -67,7 +67,8 @@ namespace KeePassLib.Serialization
byte[] pb = MemUtil.Read(m_s, nCount); byte[] pb = MemUtil.Read(m_s, nCount);
if((pb == null) || (pb.Length != nCount)) if((pb == null) || (pb.Length != nCount))
{ {
if(m_strReadExcp != null) throw new IOException(m_strReadExcp); if(!string.IsNullOrEmpty(m_strReadExcp))
throw new EndOfStreamException(m_strReadExcp);
else throw new EndOfStreamException(); else throw new EndOfStreamException();
} }
@ -76,7 +77,8 @@ namespace KeePassLib.Serialization
} }
catch(Exception) catch(Exception)
{ {
if(m_strReadExcp != null) throw new IOException(m_strReadExcp); if(!string.IsNullOrEmpty(m_strReadExcp))
throw new IOException(m_strReadExcp);
else throw; else throw;
} }
} }

View File

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

View File

@ -164,21 +164,10 @@ namespace KeePassLib.Serialization
} }
} }
public override void Flush()
{
if(m_bWriting) m_bwOutput.Flush();
}
#if KeePassUAP
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if(!disposing) return; if(disposing && (m_sBaseStream != null))
#else
public override void Close()
{ {
#endif
if(m_sBaseStream != null)
{
if(!m_bWriting) // Reading mode if(!m_bWriting) // Reading mode
{ {
m_brInput.Close(); m_brInput.Close();
@ -202,6 +191,13 @@ namespace KeePassLib.Serialization
m_sBaseStream.Close(); m_sBaseStream.Close();
m_sBaseStream = null; m_sBaseStream = null;
} }
base.Dispose(disposing);
}
public override void Flush()
{
if(m_bWriting) m_bwOutput.Flush();
} }
public override long Seek(long lOffset, SeekOrigin soOrigin) public override long Seek(long lOffset, SeekOrigin soOrigin)

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -98,21 +98,9 @@ namespace KeePassLib.Serialization
} }
} }
public override void Flush()
{
Debug.Assert(m_sBase != null); // Object should not be disposed
if(m_bWriting && (m_sBase != null)) m_sBase.Flush();
}
#if KeePassUAP
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
if(!disposing) return; if(disposing && (m_sBase != null))
#else
public override void Close()
{
#endif
if(m_sBase != null)
{ {
if(m_bWriting) if(m_bWriting)
{ {
@ -130,6 +118,14 @@ namespace KeePassLib.Serialization
m_sBase.Close(); m_sBase.Close();
m_sBase = null; m_sBase = null;
} }
base.Dispose(disposing);
}
public override void Flush()
{
Debug.Assert(m_sBase != null); // Object should not be disposed
if(m_bWriting && (m_sBase != null)) m_sBase.Flush();
} }
public override long Seek(long lOffset, SeekOrigin soOrigin) public override long Seek(long lOffset, SeekOrigin soOrigin)
@ -206,7 +202,8 @@ namespace KeePassLib.Serialization
byte[] pbStoredHmac = MemUtil.Read(m_sBase, 32); byte[] pbStoredHmac = MemUtil.Read(m_sBase, 32);
if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) if((pbStoredHmac == null) || (pbStoredHmac.Length != 32))
throw new EndOfStreamException(); throw new EndOfStreamException(KLRes.FileCorrupted + " " +
KLRes.FileIncomplete);
// Block index is implicit: it's used in the HMAC computation, // Block index is implicit: it's used in the HMAC computation,
// but does not need to be stored // but does not need to be stored
@ -220,7 +217,8 @@ namespace KeePassLib.Serialization
byte[] pbBlockSize = MemUtil.Read(m_sBase, 4); byte[] pbBlockSize = MemUtil.Read(m_sBase, 4);
if((pbBlockSize == null) || (pbBlockSize.Length != 4)) if((pbBlockSize == null) || (pbBlockSize.Length != 4))
throw new EndOfStreamException(); throw new EndOfStreamException(KLRes.FileCorrupted + " " +
KLRes.FileIncomplete);
int nBlockSize = MemUtil.BytesToInt32(pbBlockSize); int nBlockSize = MemUtil.BytesToInt32(pbBlockSize);
if(nBlockSize < 0) if(nBlockSize < 0)
throw new InvalidDataException(KLRes.FileCorrupted); throw new InvalidDataException(KLRes.FileCorrupted);
@ -229,7 +227,8 @@ namespace KeePassLib.Serialization
m_pbBuffer = MemUtil.Read(m_sBase, nBlockSize); m_pbBuffer = MemUtil.Read(m_sBase, nBlockSize);
if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBlockSize) && m_bVerify)) if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBlockSize) && m_bVerify))
throw new EndOfStreamException(); throw new EndOfStreamException(KLRes.FileCorrupted + " " +
KLRes.FileIncompleteExpc);
if(m_bVerify) if(m_bVerify)
{ {

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
@ -53,6 +53,185 @@ namespace KeePassLib.Serialization
} }
#endif #endif
internal abstract class WrapperStream : Stream
{
private readonly Stream m_s;
protected Stream BaseStream
{
get { return m_s; }
}
public override bool CanRead
{
get { return m_s.CanRead; }
}
public override bool CanSeek
{
get { return m_s.CanSeek; }
}
public override bool CanTimeout
{
get { return m_s.CanTimeout; }
}
public override bool CanWrite
{
get { return m_s.CanWrite; }
}
public override long Length
{
get { return m_s.Length; }
}
public override long Position
{
get { return m_s.Position; }
set { m_s.Position = value; }
}
public override int ReadTimeout
{
get { return m_s.ReadTimeout; }
set { m_s.ReadTimeout = value; }
}
public override int WriteTimeout
{
get { return m_s.WriteTimeout; }
set { m_s.WriteTimeout = value; }
}
public WrapperStream(Stream sBase) : base()
{
if(sBase == null) throw new ArgumentNullException("sBase");
m_s = sBase;
}
#if !KeePassUAP
public override IAsyncResult BeginRead(byte[] buffer, int offset,
int count, AsyncCallback callback, object state)
{
return m_s.BeginRead(buffer, offset, count, callback, state);
}
public override IAsyncResult BeginWrite(byte[] buffer, int offset,
int count, AsyncCallback callback, object state)
{
return BeginWrite(buffer, offset, count, callback, state);
}
#endif
protected override void Dispose(bool disposing)
{
if(disposing) m_s.Dispose();
base.Dispose(disposing);
}
#if !KeePassUAP
public override int EndRead(IAsyncResult asyncResult)
{
return m_s.EndRead(asyncResult);
}
public override void EndWrite(IAsyncResult asyncResult)
{
m_s.EndWrite(asyncResult);
}
#endif
public override void Flush()
{
m_s.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return m_s.Read(buffer, offset, count);
}
public override int ReadByte()
{
return m_s.ReadByte();
}
public override long Seek(long offset, SeekOrigin origin)
{
return m_s.Seek(offset, origin);
}
public override void SetLength(long value)
{
m_s.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
m_s.Write(buffer, offset, count);
}
public override void WriteByte(byte value)
{
m_s.WriteByte(value);
}
}
internal sealed class IocStream : WrapperStream
{
private readonly bool m_bWrite; // Initially opened for writing
private bool m_bDisposed = false;
public IocStream(Stream sBase) : base(sBase)
{
m_bWrite = sBase.CanWrite;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if(disposing && MonoWorkarounds.IsRequired(10163) && m_bWrite &&
!m_bDisposed)
{
try
{
Stream s = this.BaseStream;
Type t = s.GetType();
if(t.Name == "WebConnectionStream")
{
PropertyInfo pi = t.GetProperty("Request",
BindingFlags.Instance | BindingFlags.NonPublic);
if(pi != null)
{
WebRequest wr = (pi.GetValue(s, null) as WebRequest);
if(wr != null)
IOConnection.DisposeResponse(wr.GetResponse(), false);
else { Debug.Assert(false); }
}
else { Debug.Assert(false); }
}
}
catch(Exception) { Debug.Assert(false); }
}
m_bDisposed = true;
}
public static Stream WrapIfRequired(Stream s)
{
if(s == null) { Debug.Assert(false); return null; }
if(MonoWorkarounds.IsRequired(10163) && s.CanWrite)
return new IocStream(s);
return s;
}
}
public static class IOConnection public static class IOConnection
{ {
#if (!KeePassLibSD && !KeePassRT) #if (!KeePassLibSD && !KeePassRT)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -132,7 +132,6 @@ namespace KeePassLib.Serialization
if(xr == null) throw new ArgumentNullException("xr"); if(xr == null) throw new ArgumentNullException("xr");
m_ctxGroups.Clear(); m_ctxGroups.Clear();
m_dictBinPool = new Dictionary<string, ProtectedBinary>();
KdbContext ctx = KdbContext.Null; KdbContext ctx = KdbContext.Null;
@ -233,11 +232,11 @@ namespace KeePassLib.Serialization
if(!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) && if(!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) &&
!m_bRepairMode) !m_bRepairMode)
{ {
Debug.Assert(m_uFileVersion <= FileVersion32_3); Debug.Assert(m_uFileVersion < FileVersion32_4);
byte[] pbHash = Convert.FromBase64String(strHash); byte[] pbHash = Convert.FromBase64String(strHash);
if(!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader)) if(!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader))
throw new IOException(KLRes.FileCorrupted); throw new InvalidDataException(KLRes.FileCorrupted);
} }
} }
else if(xr.Name == ElemSettingsChanged) else if(xr.Name == ElemSettingsChanged)
@ -268,6 +267,8 @@ namespace KeePassLib.Serialization
m_pwDatabase.MasterKeyChangeRec = ReadLong(xr, -1); m_pwDatabase.MasterKeyChangeRec = ReadLong(xr, -1);
else if(xr.Name == ElemDbKeyChangeForce) else if(xr.Name == ElemDbKeyChangeForce)
m_pwDatabase.MasterKeyChangeForce = ReadLong(xr, -1); m_pwDatabase.MasterKeyChangeForce = ReadLong(xr, -1);
else if(xr.Name == ElemDbKeyChangeForceOnce)
m_pwDatabase.MasterKeyChangeForceOnce = ReadBool(xr, false);
else if(xr.Name == ElemMemoryProt) else if(xr.Name == ElemMemoryProt)
return SwitchContext(ctx, KdbContext.MemoryProtection, xr); return SwitchContext(ctx, KdbContext.MemoryProtection, xr);
else if(xr.Name == ElemCustomIcons) else if(xr.Name == ElemCustomIcons)
@ -340,7 +341,14 @@ namespace KeePassLib.Serialization
string strKey = xr.Value; string strKey = xr.Value;
ProtectedBinary pbData = ReadProtectedBinary(xr); ProtectedBinary pbData = ReadProtectedBinary(xr);
m_dictBinPool[strKey ?? string.Empty] = pbData; int iKey;
if(!StrUtil.TryParseIntInvariant(strKey, out iKey))
throw new FormatException();
if(iKey < 0) throw new FormatException();
Debug.Assert(m_pbsBinaries.Get(iKey) == null);
Debug.Assert(m_pbsBinaries.Find(pbData) < 0);
m_pbsBinaries.Set(iKey, pbData);
} }
else ReadUnknown(xr); else ReadUnknown(xr);
} }
@ -386,7 +394,7 @@ namespace KeePassLib.Serialization
else if(xr.Name == ElemNotes) else if(xr.Name == ElemNotes)
m_ctxGroup.Notes = ReadString(xr); m_ctxGroup.Notes = ReadString(xr);
else if(xr.Name == ElemIcon) else if(xr.Name == ElemIcon)
m_ctxGroup.IconId = (PwIcon)ReadInt(xr, (int)PwIcon.Folder); m_ctxGroup.IconId = ReadIconId(xr, PwIcon.Folder);
else if(xr.Name == ElemCustomIconID) else if(xr.Name == ElemCustomIconID)
m_ctxGroup.CustomIconUuid = ReadUuid(xr); m_ctxGroup.CustomIconUuid = ReadUuid(xr);
else if(xr.Name == ElemTimes) else if(xr.Name == ElemTimes)
@ -441,7 +449,7 @@ namespace KeePassLib.Serialization
if(xr.Name == ElemUuid) if(xr.Name == ElemUuid)
m_ctxEntry.Uuid = ReadUuid(xr); m_ctxEntry.Uuid = ReadUuid(xr);
else if(xr.Name == ElemIcon) else if(xr.Name == ElemIcon)
m_ctxEntry.IconId = (PwIcon)ReadInt(xr, (int)PwIcon.Key); m_ctxEntry.IconId = ReadIconId(xr, PwIcon.Key);
else if(xr.Name == ElemCustomIconID) else if(xr.Name == ElemCustomIconID)
m_ctxEntry.CustomIconUuid = ReadUuid(xr); m_ctxEntry.CustomIconUuid = ReadUuid(xr);
else if(xr.Name == ElemFgColor) else if(xr.Name == ElemFgColor)
@ -849,15 +857,45 @@ namespace KeePassLib.Serialization
private DateTime ReadTime(XmlReader xr) private DateTime ReadTime(XmlReader xr)
{ {
string str = ReadString(xr); // Cf. WriteObject(string, DateTime)
if((m_format == KdbxFormat.Default) && (m_uFileVersion >= FileVersion32_4))
{
// long l = ReadLong(xr, -1);
// if(l != -1) return DateTime.FromBinary(l);
DateTime dt; string str = ReadString(xr);
if(TimeUtil.TryDeserializeUtc(str, out dt)) return dt; byte[] pb = Convert.FromBase64String(str);
if(pb.Length != 8)
{
Debug.Assert(false);
byte[] pb8 = new byte[8];
Array.Copy(pb, pb8, Math.Min(pb.Length, 8)); // Little-endian
pb = pb8;
}
long lSec = MemUtil.BytesToInt64(pb);
return new DateTime(lSec * TimeSpan.TicksPerSecond, DateTimeKind.Utc);
}
else
{
string str = ReadString(xr);
DateTime dt;
if(TimeUtil.TryDeserializeUtc(str, out dt)) return dt;
}
Debug.Assert(false); Debug.Assert(false);
return m_dtNow; return m_dtNow;
} }
private PwIcon ReadIconId(XmlReader xr, PwIcon icDefault)
{
int i = ReadInt(xr, (int)icDefault);
if((i >= 0) && (i < (int)PwIcon.Count)) return (PwIcon)i;
Debug.Assert(false);
return icDefault;
}
private ProtectedString ReadProtectedString(XmlReader xr) private ProtectedString ReadProtectedString(XmlReader xr)
{ {
XorredBuffer xb = ProcessNode(xr); XorredBuffer xb = ProcessNode(xr);
@ -882,21 +920,26 @@ namespace KeePassLib.Serialization
if(xr.MoveToAttribute(AttrRef)) if(xr.MoveToAttribute(AttrRef))
{ {
string strRef = xr.Value; string strRef = xr.Value;
if(strRef != null) if(!string.IsNullOrEmpty(strRef))
{ {
ProtectedBinary pb = BinPoolGet(strRef); int iRef;
if(pb != null) if(StrUtil.TryParseIntInvariant(strRef, out iRef))
{ {
// https://sourceforge.net/p/keepass/feature-requests/2023/ ProtectedBinary pb = m_pbsBinaries.Get(iRef);
xr.MoveToElement(); if(pb != null)
{
// https://sourceforge.net/p/keepass/feature-requests/2023/
xr.MoveToElement();
#if DEBUG #if DEBUG
string strInner = ReadStringRaw(xr); string strInner = ReadStringRaw(xr);
Debug.Assert(string.IsNullOrEmpty(strInner)); Debug.Assert(string.IsNullOrEmpty(strInner));
#else #else
ReadStringRaw(xr); ReadStringRaw(xr);
#endif #endif
return pb; return pb;
}
else { Debug.Assert(false); }
} }
else { Debug.Assert(false); } else { Debug.Assert(false); }
} }

View File

@ -17,6 +17,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
// #define KDBX_BENCHMARK
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -42,6 +44,7 @@ using KeePassLib.Cryptography.KeyDerivation;
using KeePassLib.Interfaces; using KeePassLib.Interfaces;
using KeePassLib.Keys; using KeePassLib.Keys;
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Security;
using KeePassLib.Utility; using KeePassLib.Utility;
using keepass2android; using keepass2android;
@ -77,9 +80,19 @@ namespace KeePassLib.Serialization
Debug.Assert(sSource != null); Debug.Assert(sSource != null);
if(sSource == null) throw new ArgumentNullException("sSource"); if(sSource == null) throw new ArgumentNullException("sSource");
if(m_bUsedOnce)
throw new InvalidOperationException("Do not reuse KdbxFile objects!");
m_bUsedOnce = true;
#if KDBX_BENCHMARK
Stopwatch swTime = Stopwatch.StartNew();
#endif
m_format = fmt; m_format = fmt;
m_slLogger = slLogger; m_slLogger = slLogger;
m_pbsBinaries.Clear();
UTF8Encoding encNoBom = StrUtil.Utf8; UTF8Encoding encNoBom = StrUtil.Utf8;
byte[] pbCipherKey = null; byte[] pbCipherKey = null;
byte[] pbHmacKey64 = null; byte[] pbHmacKey64 = null;
@ -98,6 +111,7 @@ namespace KeePassLib.Serialization
BinaryReaderEx br = new BinaryReaderEx(sHashing, BinaryReaderEx br = new BinaryReaderEx(sHashing,
encNoBom, KLRes.FileCorrupted); encNoBom, KLRes.FileCorrupted);
byte[] pbHeader = LoadHeader(br); byte[] pbHeader = LoadHeader(br);
m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader);
int cbEncKey, cbEncIV; int cbEncKey, cbEncIV;
ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV); ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV);
@ -107,8 +121,11 @@ namespace KeePassLib.Serialization
ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64);
string strIncomplete = KLRes.FileHeaderCorrupted + " " +
KLRes.FileIncomplete;
Stream sPlain; Stream sPlain;
if(m_uFileVersion <= FileVersion32_3) if(m_uFileVersion < FileVersion32_4)
{ {
Stream sDecrypted = EncryptStream(sHashing, iCipher, Stream sDecrypted = EncryptStream(sHashing, iCipher,
pbCipherKey, cbEncIV, false); pbCipherKey, cbEncIV, false);
@ -121,11 +138,11 @@ namespace KeePassLib.Serialization
lStreams.Add(sDecrypted); lStreams.Add(sDecrypted);
BinaryReaderEx brDecrypted = new BinaryReaderEx(sDecrypted, BinaryReaderEx brDecrypted = new BinaryReaderEx(sDecrypted,
encNoBom, KLRes.FileCorrupted); encNoBom, strIncomplete);
byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32); byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32);
if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32)) if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32))
throw new InvalidDataException(); throw new EndOfStreamException(strIncomplete);
if(!MemUtil.ArraysEqual(pbStoredStartBytes, m_pbStreamStartBytes)) if(!MemUtil.ArraysEqual(pbStoredStartBytes, m_pbStreamStartBytes))
throw new InvalidCompositeKeyException(); throw new InvalidCompositeKeyException();
@ -137,10 +154,16 @@ namespace KeePassLib.Serialization
} }
else // KDBX >= 4 else // KDBX >= 4
{ {
byte[] pbStoredHash = MemUtil.Read(sHashing, 32);
if((pbStoredHash == null) || (pbStoredHash.Length != 32))
throw new EndOfStreamException(strIncomplete);
if(!MemUtil.ArraysEqual(m_pbHashOfHeader, pbStoredHash))
throw new InvalidDataException(KLRes.FileHeaderCorrupted);
byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64);
byte[] pbStoredHmac = MemUtil.Read(sHashing, 32); byte[] pbStoredHmac = MemUtil.Read(sHashing, 32);
if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) if((pbStoredHmac == null) || (pbStoredHmac.Length != 32))
throw new InvalidDataException(); throw new EndOfStreamException(strIncomplete);
if(!MemUtil.ArraysEqual(pbHeaderHmac, pbStoredHmac)) if(!MemUtil.ArraysEqual(pbHeaderHmac, pbStoredHmac))
throw new InvalidCompositeKeyException(); throw new InvalidCompositeKeyException();
@ -161,6 +184,9 @@ namespace KeePassLib.Serialization
lStreams.Add(sXml); lStreams.Add(sXml);
} }
else sXml = sPlain; else sXml = sPlain;
if(m_uFileVersion >= FileVersion32_4)
LoadInnerHeader(sXml); // Binary header before XML
} }
else if(fmt == KdbxFormat.PlainXml) else if(fmt == KdbxFormat.PlainXml)
sXml = sHashing; sXml = sHashing;
@ -168,16 +194,15 @@ namespace KeePassLib.Serialization
if(fmt == KdbxFormat.Default) if(fmt == KdbxFormat.Default)
{ {
if(m_pbProtectedStreamKey == null) if(m_pbInnerRandomStreamKey == null)
{ {
Debug.Assert(false); Debug.Assert(false);
throw new SecurityException("Invalid protected stream key!"); throw new SecurityException("Invalid inner random stream key!");
} }
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream, m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbProtectedStreamKey); m_pbInnerRandomStreamKey);
} }
else m_randomStream = null; // No random stream for plain-text files
if (m_slLogger != null) if (m_slLogger != null)
m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo); m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo);
@ -225,6 +250,12 @@ namespace KeePassLib.Serialization
CommonCleanUpRead(lStreams, sHashing); CommonCleanUpRead(lStreams, sHashing);
} }
#if KDBX_BENCHMARK
swTime.Stop();
MessageService.ShowInfo("Loading KDBX took " +
swTime.ElapsedMilliseconds.ToString() + " ms.");
#endif
} }
private void CommonCleanUpRead(List<Stream> lStreams, HashingStreamEx sHashing) private void CommonCleanUpRead(List<Stream> lStreams, HashingStreamEx sHashing)
@ -235,8 +266,10 @@ namespace KeePassLib.Serialization
m_pbHashOfFileOnDisk = sHashing.Hash; m_pbHashOfFileOnDisk = sHashing.Hash;
Debug.Assert(m_pbHashOfFileOnDisk != null); Debug.Assert(m_pbHashOfFileOnDisk != null);
CleanUpInnerRandomStream();
// Reset memory protection settings (to always use reasonable // Reset memory protection settings (to always use reasonable
// defaults) // defaults)
// defaults)
m_pwDatabase.MemoryProtection = new MemoryProtectionConfig(); m_pwDatabase.MemoryProtection = new MemoryProtectionConfig();
// Remove old backups (this call is required here in order to apply // Remove old backups (this call is required here in order to apply
@ -257,6 +290,10 @@ namespace KeePassLib.Serialization
private byte[] LoadHeader(BinaryReaderEx br) private byte[] LoadHeader(BinaryReaderEx br)
{ {
string strPrevExcpText = br.ReadExceptionText;
br.ReadExceptionText = KLRes.FileHeaderCorrupted + " " +
KLRes.FileIncompleteExpc;
MemoryStream msHeader = new MemoryStream(); MemoryStream msHeader = new MemoryStream();
Debug.Assert(br.CopyDataTo == null); Debug.Assert(br.CopyDataTo == null);
br.CopyDataTo = msHeader; br.CopyDataTo = msHeader;
@ -291,7 +328,7 @@ namespace KeePassLib.Serialization
byte[] pbHeader = msHeader.ToArray(); byte[] pbHeader = msHeader.ToArray();
msHeader.Close(); msHeader.Close();
m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader); br.ReadExceptionText = strPrevExcpText;
return pbHeader; return pbHeader;
} }
@ -304,21 +341,13 @@ namespace KeePassLib.Serialization
int cbSize; int cbSize;
Debug.Assert(m_uFileVersion > 0); Debug.Assert(m_uFileVersion > 0);
if(m_uFileVersion <= FileVersion32_3) if(m_uFileVersion < FileVersion32_4)
cbSize = (int)MemUtil.BytesToUInt16(brSource.ReadBytes(2)); cbSize = (int)MemUtil.BytesToUInt16(brSource.ReadBytes(2));
else cbSize = MemUtil.BytesToInt32(brSource.ReadBytes(4)); else cbSize = MemUtil.BytesToInt32(brSource.ReadBytes(4));
if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted); if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted);
byte[] pbData = MemUtil.EmptyByteArray; byte[] pbData = MemUtil.EmptyByteArray;
if(cbSize > 0) if(cbSize > 0) pbData = brSource.ReadBytes(cbSize);
{
string strPrevExcpText = brSource.ReadExceptionText;
brSource.ReadExceptionText = KLRes.FileHeaderEndEarly;
pbData = brSource.ReadBytes(cbSize);
brSource.ReadExceptionText = strPrevExcpText;
}
bool bResult = true; bool bResult = true;
KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID; KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID;
@ -343,6 +372,8 @@ namespace KeePassLib.Serialization
// Obsolete; for backward compatibility only // Obsolete; for backward compatibility only
case KdbxHeaderFieldID.TransformSeed: case KdbxHeaderFieldID.TransformSeed:
Debug.Assert(m_uFileVersion < FileVersion32_4);
AesKdf kdfS = new AesKdf(); AesKdf kdfS = new AesKdf();
if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfS.Uuid)) if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfS.Uuid))
m_pwDatabase.KdfParameters = kdfS.GetDefaultParameters(); m_pwDatabase.KdfParameters = kdfS.GetDefaultParameters();
@ -355,6 +386,8 @@ namespace KeePassLib.Serialization
// Obsolete; for backward compatibility only // Obsolete; for backward compatibility only
case KdbxHeaderFieldID.TransformRounds: case KdbxHeaderFieldID.TransformRounds:
Debug.Assert(m_uFileVersion < FileVersion32_4);
AesKdf kdfR = new AesKdf(); AesKdf kdfR = new AesKdf();
if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfR.Uuid)) if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfR.Uuid))
m_pwDatabase.KdfParameters = kdfR.GetDefaultParameters(); m_pwDatabase.KdfParameters = kdfR.GetDefaultParameters();
@ -368,17 +401,20 @@ namespace KeePassLib.Serialization
m_pbEncryptionIV = pbData; m_pbEncryptionIV = pbData;
break; break;
case KdbxHeaderFieldID.ProtectedStreamKey: case KdbxHeaderFieldID.InnerRandomStreamKey:
m_pbProtectedStreamKey = pbData; Debug.Assert(m_uFileVersion < FileVersion32_4);
Debug.Assert(m_pbInnerRandomStreamKey == null);
m_pbInnerRandomStreamKey = pbData;
CryptoRandom.Instance.AddEntropy(pbData); CryptoRandom.Instance.AddEntropy(pbData);
break; break;
case KdbxHeaderFieldID.StreamStartBytes: case KdbxHeaderFieldID.StreamStartBytes:
Debug.Assert(m_uFileVersion <= FileVersion32_3); Debug.Assert(m_uFileVersion < FileVersion32_4);
m_pbStreamStartBytes = pbData; m_pbStreamStartBytes = pbData;
break; break;
case KdbxHeaderFieldID.InnerRandomStreamID: case KdbxHeaderFieldID.InnerRandomStreamID:
Debug.Assert(m_uFileVersion < FileVersion32_4);
SetInnerRandomStreamID(pbData); SetInnerRandomStreamID(pbData);
break; break;
@ -402,6 +438,68 @@ namespace KeePassLib.Serialization
return bResult; return bResult;
} }
private void LoadInnerHeader(Stream s)
{
BinaryReaderEx br = new BinaryReaderEx(s, StrUtil.Utf8,
KLRes.FileCorrupted + " " + KLRes.FileIncompleteExpc);
while(true)
{
if(!ReadInnerHeaderField(br)) break;
}
}
private bool ReadInnerHeaderField(BinaryReaderEx br)
{
Debug.Assert(br != null);
if(br == null) throw new ArgumentNullException("br");
byte btFieldID = br.ReadByte();
int cbSize = MemUtil.BytesToInt32(br.ReadBytes(4));
if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted);
byte[] pbData = MemUtil.EmptyByteArray;
if(cbSize > 0) pbData = br.ReadBytes(cbSize);
bool bResult = true;
KdbxInnerHeaderFieldID kdbID = (KdbxInnerHeaderFieldID)btFieldID;
switch(kdbID)
{
case KdbxInnerHeaderFieldID.EndOfHeader:
bResult = false; // Returning false indicates end of header
break;
case KdbxInnerHeaderFieldID.InnerRandomStreamID:
SetInnerRandomStreamID(pbData);
break;
case KdbxInnerHeaderFieldID.InnerRandomStreamKey:
Debug.Assert(m_pbInnerRandomStreamKey == null);
m_pbInnerRandomStreamKey = pbData;
CryptoRandom.Instance.AddEntropy(pbData);
break;
case KdbxInnerHeaderFieldID.Binary:
if(pbData.Length < 1) throw new FormatException();
KdbxBinaryFlags f = (KdbxBinaryFlags)pbData[0];
bool bProt = ((f & KdbxBinaryFlags.Protected) != KdbxBinaryFlags.None);
ProtectedBinary pb = new ProtectedBinary(bProt, pbData,
1, pbData.Length - 1);
m_pbsBinaries.Add(pb);
if(bProt) MemUtil.ZeroByteArray(pbData);
break;
default:
Debug.Assert(false);
break;
}
return bResult;
}
private void SetCipher(byte[] pbID) private void SetCipher(byte[] pbID)
{ {
if((pbID == null) || (pbID.Length != (int)PwUuid.UuidSize)) if((pbID == null) || (pbID.Length != (int)PwUuid.UuidSize))
@ -429,19 +527,31 @@ namespace KeePassLib.Serialization
} }
[Obsolete] [Obsolete]
public static List<PwEntry> ReadEntries(PwDatabase pwDatabase, Stream msData) public static List<PwEntry> ReadEntries(Stream msData)
{ {
return ReadEntries(msData); return ReadEntries(msData, null, false);
} }
[Obsolete]
public static List<PwEntry> ReadEntries(PwDatabase pdContext, Stream msData)
{
return ReadEntries(msData, pdContext, true);
}
/// <summary> /// <summary>
/// Read entries from a stream. /// Read entries from a stream.
/// </summary> /// </summary>
/// <param name="msData">Input stream to read the entries from.</param> /// <param name="msData">Input stream to read the entries from.</param>
/// <returns>Extracted entries.</returns> /// <returns>Extracted entries.</returns>
public static List<PwEntry> ReadEntries(Stream msData) /// <param name="pdContext">Context database (e.g. for storing icons).</param>
/// <param name="bCopyIcons">If <c>true</c>, custom icons required by
/// the loaded entries are copied to the context database.</param>
/// <returns>Loaded entries.</returns>
public static List<PwEntry> ReadEntries(Stream msData, PwDatabase pdContext,
bool bCopyIcons)
{ {
List<PwEntry> lEntries = new List<PwEntry>();
/* KdbxFile f = new KdbxFile(pwDatabase); /* KdbxFile f = new KdbxFile(pwDatabase);
if(msData == null) { Debug.Assert(false); return lEntries; }
f.m_format = KdbxFormat.PlainXml; f.m_format = KdbxFormat.PlainXml;
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
@ -467,20 +577,43 @@ namespace KeePassLib.Serialization
else { Debug.Assert(false); } else { Debug.Assert(false); }
} }
return vEntries; */
return vEntries; */ return vEntries; */
PwDatabase pd = new PwDatabase(); PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey());
KdbxFile f = new KdbxFile(pd); KdbxFile f = new KdbxFile(pd);
f.Load(msData, KdbxFormat.PlainXml, null); f.Load(msData, KdbxFormat.PlainXml, null);
List<PwEntry> vEntries = new List<PwEntry>();
foreach(PwEntry pe in pd.RootGroup.Entries) foreach(PwEntry pe in pd.RootGroup.Entries)
{ {
pe.SetUuid(new PwUuid(true), true); pe.SetUuid(new PwUuid(true), true);
vEntries.Add(pe); lEntries.Add(pe);
if(bCopyIcons && (pdContext != null))
{
PwUuid pu = pe.CustomIconUuid;
if(!pu.Equals(PwUuid.Zero))
{
int iSrc = pd.GetCustomIconIndex(pu);
int iDst = pdContext.GetCustomIconIndex(pu);
if(iSrc < 0) { Debug.Assert(false); }
else if(iDst < 0)
{
pdContext.CustomIcons.Add(pd.CustomIcons[iSrc]);
pdContext.Modified = true;
pdContext.UINeedsIconUpdate = true;
}
}
}
} }
return vEntries; return lEntries;
} }
} }
} }

View File

@ -83,14 +83,22 @@ namespace KeePassLib.Serialization
Debug.Assert(sSaveTo != null); Debug.Assert(sSaveTo != null);
if(sSaveTo == null) throw new ArgumentNullException("sSaveTo"); if(sSaveTo == null) throw new ArgumentNullException("sSaveTo");
if(m_bUsedOnce)
throw new InvalidOperationException("Do not reuse KdbxFile objects!");
m_bUsedOnce = true;
m_format = fmt; m_format = fmt;
m_slLogger = slLogger; m_slLogger = slLogger;
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
UTF8Encoding encNoBom = StrUtil.Utf8; UTF8Encoding encNoBom = StrUtil.Utf8;
CryptoRandom cr = CryptoRandom.Instance; CryptoRandom cr = CryptoRandom.Instance;
byte[] pbCipherKey = null; byte[] pbCipherKey = null;
byte[] pbHmacKey64 = null; byte[] pbHmacKey64 = null;
m_pbsBinaries.Clear();
m_pbsBinaries.AddFrom(pgRoot);
List<Stream> lStreams = new List<Stream>(); List<Stream> lStreams = new List<Stream>();
lStreams.Add(sSaveTo); lStreams.Add(sSaveTo);
@ -116,20 +124,24 @@ namespace KeePassLib.Serialization
"UUID: " + puKdf.ToHexString() + "."); "UUID: " + puKdf.ToHexString() + ".");
kdf.Randomize(m_pwDatabase.KdfParameters); kdf.Randomize(m_pwDatabase.KdfParameters);
if(m_uFileVersion <= FileVersion32_3) if(m_format == KdbxFormat.Default)
{ {
if(m_uFileVersion < FileVersion32_4)
{
m_craInnerRandomStream = CrsAlgorithm.Salsa20; m_craInnerRandomStream = CrsAlgorithm.Salsa20;
m_pbProtectedStreamKey = cr.GetRandomBytes(32); m_pbInnerRandomStreamKey = cr.GetRandomBytes(32);
} }
else // KDBX >= 4 else // KDBX >= 4
{ {
m_craInnerRandomStream = CrsAlgorithm.ChaCha20; m_craInnerRandomStream = CrsAlgorithm.ChaCha20;
m_pbProtectedStreamKey = cr.GetRandomBytes(64); m_pbInnerRandomStreamKey = cr.GetRandomBytes(64);
} }
m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbProtectedStreamKey);
if(m_uFileVersion <= FileVersion32_3) m_randomStream = new CryptoRandomStream(m_craInnerRandomStream,
m_pbInnerRandomStreamKey);
}
if(m_uFileVersion < FileVersion32_4)
m_pbStreamStartBytes = cr.GetRandomBytes(32); m_pbStreamStartBytes = cr.GetRandomBytes(32);
Stream sXml; Stream sXml;
@ -144,7 +156,7 @@ namespace KeePassLib.Serialization
ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64);
Stream sPlain; Stream sPlain;
if(m_uFileVersion <= FileVersion32_3) if(m_uFileVersion < FileVersion32_4)
{ {
Stream sEncrypted = EncryptStream(sHashing, iCipher, Stream sEncrypted = EncryptStream(sHashing, iCipher,
pbCipherKey, cbEncIV, true); pbCipherKey, cbEncIV, true);
@ -158,6 +170,9 @@ namespace KeePassLib.Serialization
} }
else // KDBX >= 4 else // KDBX >= 4
{ {
// For integrity checking (without knowing the master key)
MemUtil.Write(sHashing, m_pbHashOfHeader);
byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64);
MemUtil.Write(sHashing, pbHeaderHmac); MemUtil.Write(sHashing, pbHeaderHmac);
@ -178,6 +193,9 @@ namespace KeePassLib.Serialization
lStreams.Add(sXml); lStreams.Add(sXml);
} }
else sXml = sPlain; else sXml = sPlain;
if(m_uFileVersion >= FileVersion32_4)
WriteInnerHeader(sXml); // Binary header before XML
} }
else if(m_format == KdbxFormat.PlainXml) else if(m_format == KdbxFormat.PlainXml)
sXml = sHashing; sXml = sHashing;
@ -213,7 +231,7 @@ namespace KeePassLib.Serialization
#endif #endif
m_xmlWriter = xw; m_xmlWriter = xw;
WriteDocument(pgDataSource); WriteDocument(pgRoot);
m_xmlWriter.Flush(); m_xmlWriter.Flush();
m_xmlWriter.Close(); m_xmlWriter.Close();
@ -239,6 +257,8 @@ namespace KeePassLib.Serialization
m_pbHashOfFileOnDisk = sHashing.Hash; m_pbHashOfFileOnDisk = sHashing.Hash;
Debug.Assert(m_pbHashOfFileOnDisk != null); Debug.Assert(m_pbHashOfFileOnDisk != null);
CleanUpInnerRandomStream();
m_xmlWriter = null; m_xmlWriter = null;
m_pbHashOfHeader = null; m_pbHashOfHeader = null;
} }
@ -261,7 +281,7 @@ namespace KeePassLib.Serialization
WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed); WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed);
if(m_uFileVersion <= FileVersion32_3) if(m_uFileVersion < FileVersion32_4)
{ {
Debug.Assert(m_pwDatabase.KdfParameters.KdfUuid.Equals( Debug.Assert(m_pwDatabase.KdfParameters.KdfUuid.Equals(
(new AesKdf()).Uuid)); (new AesKdf()).Uuid));
@ -278,15 +298,18 @@ namespace KeePassLib.Serialization
if(m_pbEncryptionIV.Length > 0) if(m_pbEncryptionIV.Length > 0)
WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV); WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV);
WriteHeaderField(ms, KdbxHeaderFieldID.ProtectedStreamKey, m_pbProtectedStreamKey); if(m_uFileVersion < FileVersion32_4)
{
WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamKey,
m_pbInnerRandomStreamKey);
if(m_uFileVersion <= FileVersion32_3)
WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes, WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes,
m_pbStreamStartBytes); m_pbStreamStartBytes);
int nIrsID = (int)m_craInnerRandomStream; int nIrsID = (int)m_craInnerRandomStream;
WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID, WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID,
MemUtil.Int32ToBytes(nIrsID)); MemUtil.Int32ToBytes(nIrsID));
}
// Write public custom data only when there is at least one item, // Write public custom data only when there is at least one item,
// because KDBX 3.1 didn't support this field yet // because KDBX 3.1 didn't support this field yet
@ -313,7 +336,7 @@ namespace KeePassLib.Serialization
if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); } if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); }
Debug.Assert(m_uFileVersion > 0); Debug.Assert(m_uFileVersion > 0);
if(m_uFileVersion <= FileVersion32_3) if(m_uFileVersion < FileVersion32_4)
{ {
if(cb > (int)ushort.MaxValue) if(cb > (int)ushort.MaxValue)
{ {
@ -325,21 +348,64 @@ namespace KeePassLib.Serialization
} }
else MemUtil.Write(s, MemUtil.Int32ToBytes(cb)); else MemUtil.Write(s, MemUtil.Int32ToBytes(cb));
if(cb > 0) s.Write(pb, 0, cb); MemUtil.Write(s, pb);
} }
private void WriteDocument(PwGroup pgDataSource) private void WriteInnerHeader(Stream s)
{
int nIrsID = (int)m_craInnerRandomStream;
WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.InnerRandomStreamID,
MemUtil.Int32ToBytes(nIrsID), null);
WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.InnerRandomStreamKey,
m_pbInnerRandomStreamKey, null);
ProtectedBinary[] vBin = m_pbsBinaries.ToArray();
for(int i = 0; i < vBin.Length; ++i)
{
ProtectedBinary pb = vBin[i];
if(pb == null) throw new InvalidOperationException();
KdbxBinaryFlags f = KdbxBinaryFlags.None;
if(pb.IsProtected) f |= KdbxBinaryFlags.Protected;
byte[] pbFlags = new byte[1] { (byte)f };
byte[] pbData = pb.ReadData();
WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.Binary,
pbFlags, pbData);
if(pb.IsProtected) MemUtil.ZeroByteArray(pbData);
}
WriteInnerHeaderField(s, KdbxInnerHeaderFieldID.EndOfHeader,
null, null);
}
private void WriteInnerHeaderField(Stream s, KdbxInnerHeaderFieldID kdbID,
byte[] pbData1, byte[] pbData2)
{
s.WriteByte((byte)kdbID);
byte[] pb1 = (pbData1 ?? MemUtil.EmptyByteArray);
byte[] pb2 = (pbData2 ?? MemUtil.EmptyByteArray);
int cb = pb1.Length + pb2.Length;
if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); }
MemUtil.Write(s, MemUtil.Int32ToBytes(cb));
MemUtil.Write(s, pb1);
MemUtil.Write(s, pb2);
}
private void WriteDocument(PwGroup pgRoot)
{ {
Debug.Assert(m_xmlWriter != null); Debug.Assert(m_xmlWriter != null);
if(m_xmlWriter == null) throw new InvalidOperationException(); if(m_xmlWriter == null) throw new InvalidOperationException();
PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup);
uint uNumGroups, uNumEntries, uCurEntry = 0; uint uNumGroups, uNumEntries, uCurEntry = 0;
pgRoot.GetCounts(true, out uNumGroups, out uNumEntries); pgRoot.GetCounts(true, out uNumGroups, out uNumEntries);
BinPoolBuild(pgRoot);
m_xmlWriter.WriteStartDocument(true); m_xmlWriter.WriteStartDocument(true);
m_xmlWriter.WriteStartElement(ElemDocNode); m_xmlWriter.WriteStartElement(ElemDocNode);
@ -413,11 +479,11 @@ namespace KeePassLib.Serialization
WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false); WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false);
if((m_pbHashOfHeader != null) && (m_uFileVersion <= FileVersion32_3)) if((m_pbHashOfHeader != null) && (m_uFileVersion < FileVersion32_4))
WriteObject(ElemHeaderHash, Convert.ToBase64String( WriteObject(ElemHeaderHash, Convert.ToBase64String(
m_pbHashOfHeader), false); m_pbHashOfHeader), false);
if(m_uFileVersion > FileVersion32_3) if(m_uFileVersion >= FileVersion32_4)
WriteObject(ElemSettingsChanged, m_pwDatabase.SettingsChanged); WriteObject(ElemSettingsChanged, m_pwDatabase.SettingsChanged);
WriteObject(ElemDbName, m_pwDatabase.Name, true); WriteObject(ElemDbName, m_pwDatabase.Name, true);
@ -431,6 +497,8 @@ namespace KeePassLib.Serialization
WriteObject(ElemDbKeyChanged, m_pwDatabase.MasterKeyChanged); WriteObject(ElemDbKeyChanged, m_pwDatabase.MasterKeyChanged);
WriteObject(ElemDbKeyChangeRec, m_pwDatabase.MasterKeyChangeRec); WriteObject(ElemDbKeyChangeRec, m_pwDatabase.MasterKeyChangeRec);
WriteObject(ElemDbKeyChangeForce, m_pwDatabase.MasterKeyChangeForce); WriteObject(ElemDbKeyChangeForce, m_pwDatabase.MasterKeyChangeForce);
if(m_pwDatabase.MasterKeyChangeForceOnce)
WriteObject(ElemDbKeyChangeForceOnce, true);
WriteList(ElemMemoryProt, m_pwDatabase.MemoryProtection); WriteList(ElemMemoryProt, m_pwDatabase.MemoryProtection);
@ -447,7 +515,9 @@ namespace KeePassLib.Serialization
WriteObject(ElemLastSelectedGroup, m_pwDatabase.LastSelectedGroup); WriteObject(ElemLastSelectedGroup, m_pwDatabase.LastSelectedGroup);
WriteObject(ElemLastTopVisibleGroup, m_pwDatabase.LastTopVisibleGroup); WriteObject(ElemLastTopVisibleGroup, m_pwDatabase.LastTopVisibleGroup);
if((m_format != KdbxFormat.Default) || (m_uFileVersion < FileVersion32_4))
WriteBinPool(); WriteBinPool();
WriteList(ElemCustomData, m_pwDatabase.CustomData); WriteList(ElemCustomData, m_pwDatabase.CustomData);
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
@ -715,8 +785,28 @@ namespace KeePassLib.Serialization
private void WriteObject(string name, DateTime value) private void WriteObject(string name, DateTime value)
{ {
Debug.Assert(name != null); Debug.Assert(name != null);
Debug.Assert(value.Kind == DateTimeKind.Utc);
WriteObject(name, TimeUtil.SerializeUtc(value), false); // Cf. ReadTime
if((m_format == KdbxFormat.Default) && (m_uFileVersion >= FileVersion32_4))
{
DateTime dt = TimeUtil.ToUtc(value, false);
// DateTime dtBase = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
// dt -= new TimeSpan(dtBase.Ticks);
// WriteObject(name, dt.ToBinary());
// dt = TimeUtil.RoundToMultOf2PowLess1s(dt);
// long lBin = dt.ToBinary();
long lSec = dt.Ticks / TimeSpan.TicksPerSecond;
// WriteObject(name, lSec);
byte[] pb = MemUtil.Int64ToBytes(lSec);
WriteObject(name, Convert.ToBase64String(pb), false);
}
else WriteObject(name, TimeUtil.SerializeUtc(value), false);
} }
private void WriteObject(string name, string strKeyName, private void WriteObject(string name, string strKeyName,
@ -763,7 +853,7 @@ namespace KeePassLib.Serialization
bProtected = m_pwDatabase.MemoryProtection.ProtectNotes; bProtected = m_pwDatabase.MemoryProtection.ProtectNotes;
} }
if(bProtected && (m_format != KdbxFormat.PlainXml)) if(bProtected && (m_format == KdbxFormat.Default))
{ {
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue); m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
@ -838,11 +928,15 @@ namespace KeePassLib.Serialization
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
m_xmlWriter.WriteStartElement(ElemValue); m_xmlWriter.WriteStartElement(ElemValue);
string strRef = (bAllowRef ? BinPoolFind(value) : null); string strRef = null;
if(strRef != null) if(bAllowRef)
{ {
m_xmlWriter.WriteAttributeString(AttrRef, strRef); int iRef = m_pbsBinaries.Find(value);
if(iRef >= 0) strRef = iRef.ToString(NumberFormatInfo.InvariantInfo);
else { Debug.Assert(false); }
} }
if(strRef != null)
m_xmlWriter.WriteAttributeString(AttrRef, strRef);
else SubWriteValue(value); else SubWriteValue(value);
m_xmlWriter.WriteEndElement(); // ElemValue m_xmlWriter.WriteEndElement(); // ElemValue
@ -851,7 +945,7 @@ namespace KeePassLib.Serialization
private void SubWriteValue(ProtectedBinary value) private void SubWriteValue(ProtectedBinary value)
{ {
if(value.IsProtected && (m_format != KdbxFormat.PlainXml)) if(value.IsProtected && (m_format == KdbxFormat.Default))
{ {
m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue); m_xmlWriter.WriteAttributeString(AttrProtected, ValTrue);
@ -861,18 +955,26 @@ namespace KeePassLib.Serialization
} }
else else
{ {
if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip) if(m_pwDatabase.Compression != PwCompressionAlgorithm.None)
{ {
m_xmlWriter.WriteAttributeString(AttrCompressed, ValTrue); m_xmlWriter.WriteAttributeString(AttrCompressed, ValTrue);
byte[] pbRaw = value.ReadData(); byte[] pbRaw = value.ReadData();
byte[] pbCmp = MemUtil.Compress(pbRaw); byte[] pbCmp = MemUtil.Compress(pbRaw);
m_xmlWriter.WriteBase64(pbCmp, 0, pbCmp.Length); m_xmlWriter.WriteBase64(pbCmp, 0, pbCmp.Length);
if(value.IsProtected)
{
MemUtil.ZeroByteArray(pbRaw);
MemUtil.ZeroByteArray(pbCmp);
}
} }
else else
{ {
byte[] pbRaw = value.ReadData(); byte[] pbRaw = value.ReadData();
m_xmlWriter.WriteBase64(pbRaw, 0, pbRaw.Length); m_xmlWriter.WriteBase64(pbRaw, 0, pbRaw.Length);
if(value.IsProtected) MemUtil.ZeroByteArray(pbRaw);
} }
} }
} }
@ -892,11 +994,13 @@ namespace KeePassLib.Serialization
{ {
m_xmlWriter.WriteStartElement(ElemBinaries); m_xmlWriter.WriteStartElement(ElemBinaries);
foreach(KeyValuePair<string, ProtectedBinary> kvp in m_dictBinPool) ProtectedBinary[] v = m_pbsBinaries.ToArray();
for(int i = 0; i < v.Length; ++i)
{ {
m_xmlWriter.WriteStartElement(ElemBinary); m_xmlWriter.WriteStartElement(ElemBinary);
m_xmlWriter.WriteAttributeString(AttrId, kvp.Key); m_xmlWriter.WriteAttributeString(AttrId,
SubWriteValue(kvp.Value); i.ToString(NumberFormatInfo.InvariantInfo));
SubWriteValue(v[i]);
m_xmlWriter.WriteEndElement(); m_xmlWriter.WriteEndElement();
} }
@ -904,21 +1008,23 @@ namespace KeePassLib.Serialization
} }
[Obsolete] [Obsolete]
public static bool WriteEntries(Stream msOutput, PwDatabase pwDatabase, public static bool WriteEntries(Stream msOutput, PwEntry[] vEntries)
PwEntry[] vEntries)
{ {
return WriteEntries(msOutput, vEntries); return WriteEntries(msOutput, null, vEntries);
} }
public static bool WriteEntries(Stream msOutput, PwDatabase pdContext,
PwEntry[] vEntries)
{
if(msOutput == null) { Debug.Assert(false); return false; }
/// <summary> /// <summary>
if(vEntries == null) { Debug.Assert(false); return false; }
/// Write entries to a stream. /// Write entries to a stream.
/// </summary> /// </summary>
/// <param name="msOutput">Output stream to which the entries will be written.</param> /// <param name="msOutput">Output stream to which the entries will be written.</param>
/// <param name="vEntries">Entries to serialize.</param> /// <param name="vEntries">Entries to serialize.</param>
/// <returns>Returns <c>true</c>, if the entries were written successfully /// <returns>Returns <c>true</c>, if the entries were written successfully
/// to the stream.</returns> /// to the stream.</returns>
public static bool WriteEntries(Stream msOutput, PwEntry[] vEntries)
{
/* KdbxFile f = new KdbxFile(pwDatabase); /* KdbxFile f = new KdbxFile(pwDatabase);
f.m_format = KdbxFormat.PlainXml; f.m_format = KdbxFormat.PlainXml;
@ -941,17 +1047,31 @@ namespace KeePassLib.Serialization
xtw.WriteEndElement(); xtw.WriteEndElement();
xtw.WriteEndDocument(); xtw.WriteEndDocument();
xtw.Flush();
xtw.Close();
return true; */
PwDatabase pd = new PwDatabase(); PwDatabase pd = new PwDatabase();
pd.New(new IOConnectionInfo(), new CompositeKey()); pd.New(new IOConnectionInfo(), new CompositeKey());
foreach(PwEntry peCopy in vEntries) PwGroup pg = pd.RootGroup;
pd.RootGroup.AddEntry(peCopy.CloneDeep(), true); if(pg == null) { Debug.Assert(false); return false; }
xtw.Flush();
foreach(PwEntry pe in vEntries)
{
PwUuid pu = pe.CustomIconUuid;
if(!pu.Equals(PwUuid.Zero) && (pd.GetCustomIconIndex(pu) < 0))
{
int i = -1;
if(pdContext != null) i = pdContext.GetCustomIconIndex(pu);
if(i >= 0)
{
PwCustomIcon ci = pdContext.CustomIcons[i];
pd.CustomIcons.Add(ci);
}
else { Debug.Assert(pdContext == null); }
}
xtw.Close();
PwEntry peCopy = pe.CloneDeep();
pg.AddEntry(peCopy, true);
}
return true; */
KdbxFile f = new KdbxFile(pd); KdbxFile f = new KdbxFile(pd);
f.Save(msOutput, null, KdbxFormat.PlainXml, null); f.Save(msOutput, null, KdbxFormat.PlainXml, null);
return true; return true;

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -125,7 +125,9 @@ namespace KeePassLib.Serialization
/// file version is too high), the last 2 bytes are informational. /// file version is too high), the last 2 bytes are informational.
/// </summary> /// </summary>
private const uint FileVersion32 = 0x00040000; private const uint FileVersion32 = 0x00040000;
private const uint FileVersion32_3 = 0x00030001; // Old format
internal const uint FileVersion32_4 = 0x00040000; // First of 4.x series
internal const uint FileVersion32_3 = 0x00030001; // Old format 3.1
private const uint FileVersionCriticalMask = 0xFFFF0000; private const uint FileVersionCriticalMask = 0xFFFF0000;
@ -156,6 +158,7 @@ namespace KeePassLib.Serialization
private const string ElemDbKeyChanged = "MasterKeyChanged"; private const string ElemDbKeyChanged = "MasterKeyChanged";
private const string ElemDbKeyChangeRec = "MasterKeyChangeRec"; private const string ElemDbKeyChangeRec = "MasterKeyChangeRec";
private const string ElemDbKeyChangeForce = "MasterKeyChangeForce"; private const string ElemDbKeyChangeForce = "MasterKeyChangeForce";
private const string ElemDbKeyChangeForceOnce = "MasterKeyChangeForceOnce";
private const string ElemRecycleBinEnabled = "RecycleBinEnabled"; private const string ElemRecycleBinEnabled = "RecycleBinEnabled";
private const string ElemRecycleBinUuid = "RecycleBinUUID"; private const string ElemRecycleBinUuid = "RecycleBinUUID";
private const string ElemRecycleBinChanged = "RecycleBinChanged"; private const string ElemRecycleBinChanged = "RecycleBinChanged";
@ -239,6 +242,7 @@ namespace KeePassLib.Serialization
private const string ElemStringDictExItem = "Item"; private const string ElemStringDictExItem = "Item";
private PwDatabase m_pwDatabase; // Not null, see constructor private PwDatabase m_pwDatabase; // Not null, see constructor
private bool m_bUsedOnce = false;
private XmlWriter m_xmlWriter = null; private XmlWriter m_xmlWriter = null;
private CryptoRandomStream m_randomStream = null; private CryptoRandomStream m_randomStream = null;
@ -249,20 +253,19 @@ namespace KeePassLib.Serialization
private byte[] m_pbMasterSeed = null; private byte[] m_pbMasterSeed = null;
// private byte[] m_pbTransformSeed = null; // private byte[] m_pbTransformSeed = null;
private byte[] m_pbEncryptionIV = null; private byte[] m_pbEncryptionIV = null;
private byte[] m_pbProtectedStreamKey = null;
private byte[] m_pbStreamStartBytes = null; private byte[] m_pbStreamStartBytes = null;
// ArcFourVariant only for backward compatibility; KeePass defaults // ArcFourVariant only for backward compatibility; KeePass defaults
// to a more secure algorithm when *writing* databases // to a more secure algorithm when *writing* databases
private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant; private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant;
private byte[] m_pbInnerRandomStreamKey = null;
private Dictionary<string, ProtectedBinary> m_dictBinPool = private ProtectedBinarySet m_pbsBinaries = new ProtectedBinarySet();
new Dictionary<string, ProtectedBinary>();
private byte[] m_pbHashOfHeader = null; private byte[] m_pbHashOfHeader = null;
private byte[] m_pbHashOfFileOnDisk = null; private byte[] m_pbHashOfFileOnDisk = null;
private readonly DateTime m_dtNow = DateTime.Now; // Cache current time private readonly DateTime m_dtNow = DateTime.UtcNow; // Cache current time
private const uint NeutralLanguageOffset = 0x100000; // 2^20, see 32-bit Unicode specs 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 NeutralLanguageIDSec = 0x7DC5C; // See 32-bit Unicode specs
@ -279,13 +282,29 @@ namespace KeePassLib.Serialization
TransformSeed = 5, // KDBX 3.1, for backward compatibility only TransformSeed = 5, // KDBX 3.1, for backward compatibility only
TransformRounds = 6, // KDBX 3.1, for backward compatibility only TransformRounds = 6, // KDBX 3.1, for backward compatibility only
EncryptionIV = 7, EncryptionIV = 7,
ProtectedStreamKey = 8, InnerRandomStreamKey = 8, // KDBX 3.1, for backward compatibility only
StreamStartBytes = 9, // KDBX 3.1, for backward compatibility only StreamStartBytes = 9, // KDBX 3.1, for backward compatibility only
InnerRandomStreamID = 10, InnerRandomStreamID = 10, // KDBX 3.1, for backward compatibility only
KdfParameters = 11, // KDBX 4 KdfParameters = 11, // KDBX 4, superseding Transform*
PublicCustomData = 12 // KDBX 4 PublicCustomData = 12 // KDBX 4
} }
// Inner header in KDBX >= 4 files
private enum KdbxInnerHeaderFieldID : byte
{
EndOfHeader = 0,
InnerRandomStreamID = 1, // Supersedes KdbxHeaderFieldID.InnerRandomStreamID
InnerRandomStreamKey = 2, // Supersedes KdbxHeaderFieldID.InnerRandomStreamKey
Binary = 3
}
[Flags]
private enum KdbxBinaryFlags : byte
{
None = 0,
Protected = 1
}
public byte[] HashOfFileOnDisk public byte[] HashOfFileOnDisk
{ {
get { return m_pbHashOfFileOnDisk; } get { return m_pbHashOfFileOnDisk; }
@ -298,6 +317,13 @@ namespace KeePassLib.Serialization
set { m_bRepairMode = value; } set { m_bRepairMode = value; }
} }
private uint m_uForceVersion = 0;
internal uint ForceVersion
{
get { return m_uForceVersion; }
set { m_uForceVersion = value; }
}
private string m_strDetachBins = null; private string m_strDetachBins = null;
/// <summary> /// <summary>
/// Detach binaries when opening a file. If this isn't <c>null</c>, /// Detach binaries when opening a file. If this isn't <c>null</c>,
@ -344,6 +370,10 @@ namespace KeePassLib.Serialization
private uint GetMinKdbxVersion() private uint GetMinKdbxVersion()
{ {
if(m_uForceVersion != 0) return m_uForceVersion;
// See also KeePassKdb2x3.Export (KDBX 3.1 export module)
AesKdf kdfAes = new AesKdf(); AesKdf kdfAes = new AesKdf();
if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid))
return FileVersion32; return FileVersion32;
@ -488,64 +518,12 @@ namespace KeePassLib.Serialization
// Do not clear the list // Do not clear the list
} }
private void BinPoolBuild(PwGroup pgDataSource) private void CleanUpInnerRandomStream()
{ {
m_dictBinPool = new Dictionary<string, ProtectedBinary>(); if(m_randomStream != null) m_randomStream.Dispose();
if(pgDataSource == null) { Debug.Assert(false); return; } if(m_pbInnerRandomStreamKey != null)
MemUtil.ZeroByteArray(m_pbInnerRandomStreamKey);
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(
NumberFormatInfo.InvariantInfo), 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, private static void SaveBinary(string strName, ProtectedBinary pb,

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll

View File

@ -1,8 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -21,15 +19,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
using System.Diagnostics;
using System.Reflection; #if !KeePassUAP
using System.Windows.Forms;
#endif
namespace KeePassLib.Translation namespace KeePassLib.Translation
{ {
public class Form
{}
public sealed class KPFormCustomization public sealed class KPFormCustomization
{ {
private string m_strFQName = string.Empty; private string m_strFQName = string.Empty;
@ -69,7 +68,7 @@ namespace KeePassLib.Translation
} }
} }
#if (!KeePassLibSD && !KeePassRT) #if (!KeePassLibSD && !KeePassUAP)
private Form m_formEnglish = null; private Form m_formEnglish = null;
[XmlIgnore] [XmlIgnore]
public Form FormEnglish public Form FormEnglish
@ -78,7 +77,7 @@ namespace KeePassLib.Translation
set { m_formEnglish = value; } set { m_formEnglish = value; }
} }
/*public void ApplyTo(Form form) public void ApplyTo(Form form)
{ {
Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form"); Debug.Assert(form != null); if(form == null) throw new ArgumentNullException("form");
@ -103,7 +102,7 @@ namespace KeePassLib.Translation
} }
foreach(Control cSub in c.Controls) ApplyToControl(cSub); foreach(Control cSub in c.Controls) ApplyToControl(cSub);
}*/ }
#endif #endif
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -57,7 +57,7 @@ namespace KeePassLib.Utility
string strPath = strTemp + strPrefix + "-"; string strPath = strTemp + strPrefix + "-";
Debug.Assert(strPath.IndexOf('/') < 0); Debug.Assert(strPath.IndexOf('/') < 0);
DateTime dtNow = DateTime.Now; DateTime dtNow = DateTime.UtcNow;
string strTime = dtNow.ToString("s"); string strTime = dtNow.ToString("s");
strTime = strTime.Replace('T', '-'); strTime = strTime.Replace('T', '-');
strTime = strTime.Replace(':', '-'); strTime = strTime.Replace(':', '-');

View File

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

View File

@ -1,8 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -22,45 +20,29 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Text; using System.Text;
using System.Diagnostics; #if !KeePassUAP
using System.Windows.Forms;
#endif
using KeePassLib.Resources; using KeePassLib.Resources;
using KeePassLib.Serialization; using KeePassLib.Serialization;
namespace KeePassLib.Utility namespace KeePassLib.Utility
{ {
public enum MessageBoxButtons
{
OK, OKCancel, AbortRetryIgnore, YesNoCancel, YesNo, RetryCancel
}
public enum MessageBoxIcon
{
Information, Warning, Error, Question
}
public enum MessageBoxDefaultButton
{
Button1, Button2, Button3
}
public enum DialogResult
{
Yes, No, Cancel, Retry, Abort
}
public sealed class MessageServiceEventArgs : EventArgs public sealed class MessageServiceEventArgs : EventArgs
{ {
private string m_strTitle = string.Empty; private string m_strTitle = string.Empty;
private string m_strText = string.Empty; private string m_strText = string.Empty;
//private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK; private MessageBoxButtons m_msgButtons = MessageBoxButtons.OK;
//private MessageBoxIcon m_msgIcon = MessageBoxIcon.None; private MessageBoxIcon m_msgIcon = MessageBoxIcon.None;
public string Title { get { return m_strTitle; } } public string Title { get { return m_strTitle; } }
public string Text { get { return m_strText; } } public string Text { get { return m_strText; } }
//public MessageBoxButtons Buttons { get { return m_msgButtons; } } public MessageBoxButtons Buttons { get { return m_msgButtons; } }
//public MessageBoxIcon Icon { get { return m_msgIcon; } } public MessageBoxIcon Icon { get { return m_msgIcon; } }
public MessageServiceEventArgs() { } public MessageServiceEventArgs() { }
@ -69,7 +51,8 @@ namespace KeePassLib.Utility
{ {
m_strTitle = (strTitle ?? string.Empty); m_strTitle = (strTitle ?? string.Empty);
m_strText = (strText ?? string.Empty); m_strText = (strText ?? string.Empty);
m_msgButtons = msgButtons;
m_msgIcon = msgIcon;
} }
} }
@ -82,12 +65,14 @@ namespace KeePassLib.Utility
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning; private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Warning;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error; private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Error;
private const MessageBoxOptions m_mboRtl = (MessageBoxOptions.RtlReading |
MessageBoxOptions.RightAlign);
#else #else
private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk; private const MessageBoxIcon m_mbiInfo = MessageBoxIcon.Asterisk;
private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation; private const MessageBoxIcon m_mbiWarning = MessageBoxIcon.Exclamation;
private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand; private const MessageBoxIcon m_mbiFatal = MessageBoxIcon.Hand;
#endif #endif
//private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question; private const MessageBoxIcon m_mbiQuestion = MessageBoxIcon.Question;
public static string NewLine public static string NewLine
{ {
@ -112,7 +97,9 @@ namespace KeePassLib.Utility
get { return m_uCurrentMessageCount; } get { return m_uCurrentMessageCount; }
} }
#if !KeePassUAP
public static event EventHandler<MessageServiceEventArgs> MessageShowing; public static event EventHandler<MessageServiceEventArgs> MessageShowing;
#endif
private static string ObjectsToMessage(object[] vLines) private static string ObjectsToMessage(object[] vLines)
{ {
@ -136,7 +123,7 @@ namespace KeePassLib.Utility
Exception exObj = (obj as Exception); Exception exObj = (obj as Exception);
string strObj = (obj as string); string strObj = (obj as string);
#if (!KeePassLibSD && !KeePassRT) #if !KeePassLibSD
StringCollection scObj = (obj as StringCollection); StringCollection scObj = (obj as StringCollection);
#endif #endif
@ -147,7 +134,7 @@ namespace KeePassLib.Utility
else if((exObj.Message != null) && (exObj.Message.Length > 0)) else if((exObj.Message != null) && (exObj.Message.Length > 0))
strAppend = exObj.Message; strAppend = exObj.Message;
} }
#if (!KeePassLibSD && !KeePassRT) #if !KeePassLibSD
else if(scObj != null) else if(scObj != null)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -176,30 +163,24 @@ namespace KeePassLib.Utility
return sbText.ToString(); return sbText.ToString();
} }
#if (!KeePassLibSD && !KeePassRT) #if (!KeePassLibSD && !KeePassUAP)
/*internal static Form GetTopForm() internal static Form GetTopForm()
{ {
FormCollection fc = Application.OpenForms; FormCollection fc = Application.OpenForms;
if((fc == null) || (fc.Count == 0)) return null; if((fc == null) || (fc.Count == 0)) return null;
return fc[fc.Count - 1]; return fc[fc.Count - 1];
}*/ }
#endif #endif
private static DialogResult SafeShowMessageBox(string strText, string strTitle, #if !KeePassUAP
internal static DialogResult SafeShowMessageBox(string strText, string strTitle,
MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb) MessageBoxButtons mb, MessageBoxIcon mi, MessageBoxDefaultButton mdb)
{ {
#if (KeePassLibSD || KeePassRT) #if KeePassLibSD
return MessageBox.Show(strText, strTitle, mb, mi, mdb); return MessageBox.Show(strText, strTitle, mb, mi, mdb);
#else #else
IWin32Window wnd = null;
if (mb == MessageBoxButtons.OK)
{
//Android.Widget.Toast toast = ..
}
//this might help: http://www.gregshackles.com/2011/04/using-background-threads-in-mono-for-android-applications/
throw new NotImplementedException();
/*IWin32Window wnd = null;
try try
{ {
Form f = GetTopForm(); Form f = GetTopForm();
@ -228,12 +209,11 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft) if(StrUtil.RightToLeft)
return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl); return MessageBox.Show(strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(strText, strTitle, mb, mi, mdb); return MessageBox.Show(strText, strTitle, mb, mi, mdb);
*/
#endif #endif
} }
#if (!KeePassLibSD && !KeePassRT) #if !KeePassLibSD
/* internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent, internal delegate DialogResult SafeShowMessageBoxInternalDelegate(IWin32Window iParent,
string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi, string strText, string strTitle, MessageBoxButtons mb, MessageBoxIcon mi,
MessageBoxDefaultButton mdb); MessageBoxDefaultButton mdb);
@ -244,7 +224,7 @@ namespace KeePassLib.Utility
if(StrUtil.RightToLeft) if(StrUtil.RightToLeft)
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl); return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb, m_mboRtl);
return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb); return MessageBox.Show(iParent, strText, strTitle, mb, mi, mdb);
}*/ }
#endif #endif
public static void ShowInfo(params object[] vLines) public static void ShowInfo(params object[] vLines)
@ -309,12 +289,13 @@ namespace KeePassLib.Utility
try try
{ {
#if !KeePassLibSD string strDetails = ObjectsToMessage(vLines, true);
/* nicht benoetigt - hoffentlich :-)
Clipboard.Clear(); #if KeePassLibSD
Clipboard.SetText(ObjectsToMessage(vLines, true));*/ Clipboard.SetDataObject(strDetails);
#else #else
Clipboard.SetDataObject(ObjectsToMessage(vLines, true)); Clipboard.Clear();
Clipboard.SetText(strDetails);
#endif #endif
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
@ -339,10 +320,10 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
if(MessageService.MessageShowing != null) if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, mbb, MessageBoxIcon.Question)); strTitleEx, strTextEx, mbb, m_mbiQuestion));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb, DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, mbb,
MessageBoxIcon.Question, MessageBoxDefaultButton.Button1); m_mbiQuestion, MessageBoxDefaultButton.Button1);
--m_uCurrentMessageCount; --m_uCurrentMessageCount;
return dr; return dr;
@ -358,10 +339,10 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
if(MessageService.MessageShowing != null) if(MessageService.MessageShowing != null)
MessageService.MessageShowing(null, new MessageServiceEventArgs( MessageService.MessageShowing(null, new MessageServiceEventArgs(
strTitleEx, strTextEx, MessageBoxButtons.YesNo, MessageBoxIcon.Question)); strTitleEx, strTextEx, MessageBoxButtons.YesNo, mbi));
DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx, DialogResult dr = SafeShowMessageBox(strTextEx, strTitleEx,
MessageBoxButtons.YesNo, MessageBoxIcon.Question, bDefaultToYes ? MessageBoxButtons.YesNo, mbi, bDefaultToYes ?
MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2); MessageBoxDefaultButton.Button1 : MessageBoxDefaultButton.Button2);
--m_uCurrentMessageCount; --m_uCurrentMessageCount;
@ -370,17 +351,17 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes) public static bool AskYesNo(string strText, string strTitle, bool bDefaultToYes)
{ {
return AskYesNo(strText, strTitle, bDefaultToYes, MessageBoxIcon.Question); return AskYesNo(strText, strTitle, bDefaultToYes, m_mbiQuestion);
} }
public static bool AskYesNo(string strText, string strTitle) public static bool AskYesNo(string strText, string strTitle)
{ {
return AskYesNo(strText, strTitle, true, MessageBoxIcon.Question); return AskYesNo(strText, strTitle, true, m_mbiQuestion);
} }
public static bool AskYesNo(string strText) public static bool AskYesNo(string strText)
{ {
return AskYesNo(strText, null, true, MessageBoxIcon.Question); return AskYesNo(strText, null, true, m_mbiQuestion);
} }
public static void ShowLoadWarning(string strFilePath, Exception ex) public static void ShowLoadWarning(string strFilePath, Exception ex)
@ -391,21 +372,7 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
public static void ShowLoadWarning(string strFilePath, Exception ex, public static void ShowLoadWarning(string strFilePath, Exception ex,
bool bFullException) bool bFullException)
{ {
string str = string.Empty; ShowWarning(GetLoadWarningMessage(strFilePath, ex, bFullException));
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileLoadFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
{
str += MessageService.NewParagraph;
if(!bFullException) str += ex.Message;
else str += ObjectsToMessage(new object[] { ex }, true);
}
ShowWarning(str);
} }
public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex) public static void ShowLoadWarning(IOConnectionInfo ioConnection, Exception ex)
@ -425,18 +392,7 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
return; return;
} }
string str = string.Empty; string str = GetSaveWarningMessage(strFilePath, ex, bCorruptionWarning);
if((strFilePath != null) && (strFilePath.Length > 0))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed;
if((ex != null) && (ex.Message != null) && (ex.Message.Length > 0))
str += MessageService.NewParagraph + ex.Message;
if(bCorruptionWarning)
str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
ShowWarning(str); ShowWarning(str);
} }
@ -447,6 +403,45 @@ Clipboard.SetText(ObjectsToMessage(vLines, true));*/
ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning); ShowSaveWarning(ioConnection.GetDisplayName(), ex, bCorruptionWarning);
else ShowWarning(ex); else ShowWarning(ex);
} }
#endif // !KeePassUAP
internal static string GetLoadWarningMessage(string strFilePath,
Exception ex, bool bFullException)
{
string str = string.Empty;
if(!string.IsNullOrEmpty(strFilePath))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileLoadFailed;
if((ex != null) && !string.IsNullOrEmpty(ex.Message))
{
str += MessageService.NewParagraph;
if(!bFullException) str += ex.Message;
else str += ObjectsToMessage(new object[] { ex }, true);
}
return str;
}
internal static string GetSaveWarningMessage(string strFilePath,
Exception ex, bool bCorruptionWarning)
{
string str = string.Empty;
if(!string.IsNullOrEmpty(strFilePath))
str += strFilePath + MessageService.NewParagraph;
str += KLRes.FileSaveFailed;
if((ex != null) && !string.IsNullOrEmpty(ex.Message))
str += MessageService.NewParagraph + ex.Message;
if(bCorruptionWarning)
str += MessageService.NewParagraph + KLRes.FileSaveCorruptionWarning;
return str;
}
public static void ExternalIncrementMessageCount() public static void ExternalIncrementMessageCount()
{ {

View File

@ -24,6 +24,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading;
using System.Xml; using System.Xml;
@ -34,6 +35,8 @@ namespace KeePassLib.Utility
public static class MonoWorkarounds public static class MonoWorkarounds
{ {
private static Dictionary<uint, bool> m_dForceReq = new Dictionary<uint, bool>(); private static Dictionary<uint, bool> m_dForceReq = new Dictionary<uint, bool>();
private static Thread m_thFixClip = null;
private static bool? m_bReq = null; private static bool? m_bReq = null;
public static bool IsRequired() public static bool IsRequired()
@ -114,6 +117,17 @@ namespace KeePassLib.Utility
// 3574233558: // 3574233558:
// Problems with minimizing windows, no content rendered. // Problems with minimizing windows, no content rendered.
// https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/ // https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/
// https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/801414
// 891029:
// Increase tab control height, otherwise Mono throws exceptions.
// https://sourceforge.net/projects/keepass/forums/forum/329221/topic/4519750
// https://bugs.launchpad.net/ubuntu/+source/keepass2/+bug/891029
// 836428016:
// ListView group header selection unsupported.
// https://sourceforge.net/p/keepass/discussion/329221/thread/31dae0f0/
// 3574233558:
// Problems with minimizing windows, no content rendered.
// https://sourceforge.net/p/keepass/discussion/329220/thread/d50a79d6/
public static bool IsRequired(uint uBugID) public static bool IsRequired(uint uBugID)
{ {
if(!MonoWorkarounds.IsRequired()) return false; if(!MonoWorkarounds.IsRequired()) return false;
@ -146,6 +160,118 @@ namespace KeePassLib.Utility
} }
} }
internal static void Initialize()
{
Terminate();
// m_fOwnWindow = fOwnWindow;
if(IsRequired(1530))
{
try
{
ThreadStart ts = new ThreadStart(MonoWorkarounds.FixClipThread);
m_thFixClip = new Thread(ts);
m_thFixClip.Start();
}
catch(Exception) { Debug.Assert(false); }
}
}
internal static void Terminate()
{
if(m_thFixClip != null)
{
try { m_thFixClip.Abort(); }
catch(Exception) { Debug.Assert(false); }
m_thFixClip = null;
}
}
private static void FixClipThread()
{
try
{
#if !KeePassUAP
const string strXSel = "xsel";
const AppRunFlags rfW = AppRunFlags.WaitForExit;
string strLast = null;
while(true)
{
string str = NativeLib.RunConsoleApp(strXSel,
"--output --clipboard");
if(str == null) return; // 'xsel' not installed
if(str != strLast)
{
if(NeedClipboardWorkaround())
NativeLib.RunConsoleApp(strXSel,
"--input --clipboard", str, rfW);
strLast = str;
}
Thread.Sleep(250);
}
#endif
}
catch(ThreadAbortException)
{
try { Thread.ResetAbort(); }
catch(Exception) { Debug.Assert(false); }
}
catch(Exception) { Debug.Assert(false); }
finally { m_thFixClip = null; }
}
private static bool NeedClipboardWorkaround()
{
const bool bDef = true;
try
{
string strHandle = (NativeLib.RunConsoleApp("xdotool",
"getactivewindow") ?? string.Empty).Trim();
if(strHandle.Length == 0) return bDef;
// IntPtr h = new IntPtr(long.Parse(strHandle));
long.Parse(strHandle); // Validate
// Detection of own windows based on Form.Handle
// comparisons doesn't work reliably (Mono's handles
// are usually off by 1)
// Predicate<IntPtr> fOwnWindow = m_fOwnWindow;
// if(fOwnWindow != null)
// {
// if(fOwnWindow(h)) return true;
// }
// else { Debug.Assert(false); }
string strWmClass = (NativeLib.RunConsoleApp("xprop",
"-id " + strHandle + " WM_CLASS") ?? string.Empty);
if(strWmClass.IndexOf("\"" + PwDefs.ResClass + "\"",
StrUtil.CaseIgnoreCmp) >= 0) return true;
// Workaround for Remmina
if(strWmClass.IndexOf("\"Remmina\"",
StrUtil.CaseIgnoreCmp) >= 0) return true;
return false;
}
catch(ThreadAbortException) { throw; }
catch(Exception) { Debug.Assert(false); }
return bDef;
}
#if !KeePassUAP
public static void ApplyTo(Form f)
{
if(!MonoWorkarounds.IsRequired()) return;
if(f == null) { Debug.Assert(false); return; }
/// <summary> /// <summary>
/// Ensure that the file ~/.recently-used is valid (in order to /// Ensure that the file ~/.recently-used is valid (in order to
/// prevent Mono's FileDialog from crashing). /// prevent Mono's FileDialog from crashing).

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -669,7 +669,8 @@ namespace KeePassLib.Utility
return DateTime.TryParse(str, out dt); return DateTime.TryParse(str, out dt);
#else #else
try { dt = DateTime.Parse(str); return true; } try { dt = DateTime.Parse(str); return true; }
catch(Exception) { dt = DateTime.MinValue; return false; } catch(Exception) { dt = DateTime.UtcNow; }
return false;
#endif #endif
} }
@ -1722,5 +1723,16 @@ namespace KeePassLib.Utility
return iCount; return iCount;
} }
internal static string ReplaceNulls(string str)
{
if(str == null) { Debug.Assert(false); return null; }
if(str.IndexOf('\0') < 0) return str;
// Replacing null characters by spaces is the
// behavior of Notepad (on Windows 10)
return str.Replace('\0', ' ');
}
} }
} }

View File

@ -38,11 +38,18 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
public const int PwTimeLength = 7; public const int PwTimeLength = 7;
public static readonly DateTime SafeMinValueUtc = new DateTime(
DateTime.MinValue.Ticks + TimeSpan.TicksPerDay, DateTimeKind.Utc);
public static readonly DateTime SafeMaxValueUtc = new DateTime(
DateTime.MaxValue.Ticks - TimeSpan.TicksPerDay, DateTimeKind.Utc);
#if !KeePassLibSD #if !KeePassLibSD
private static string m_strDtfStd = null; private static string m_strDtfStd = null;
private static string m_strDtfDate = null; private static string m_strDtfDate = null;
#endif #endif
/// <summary> /// <summary>
// private static long m_lTicks2PowLess1s = 0;
private static DateTime? m_odtUnixRoot = null; private static DateTime? m_odtUnixRoot = null;
public static DateTime UnixRoot public static DateTime UnixRoot
{ {
@ -50,8 +57,8 @@ namespace KeePassLib.Utility
{ {
if(m_odtUnixRoot.HasValue) return m_odtUnixRoot.Value; if(m_odtUnixRoot.HasValue) return m_odtUnixRoot.Value;
/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits, /// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits,
DateTime dtRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTime dtRoot = new DateTime(1970, 1, 1, 0, 0, 0, 0,
DateTimeKind.Utc)).ToLocalTime(); DateTimeKind.Utc);
/// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6 /// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6
m_odtUnixRoot = dtRoot; m_odtUnixRoot = dtRoot;
return dtRoot; return dtRoot;
@ -63,10 +70,11 @@ namespace KeePassLib.Utility
/// <returns></returns> /// <returns></returns>
/// bits, second 6 bits. /// bits, second 6 bits.
/// </summary> /// </summary>
/// <param name="dt"></param> [Obsolete]
/// <returns></returns>
public static byte[] PackTime(DateTime dt) public static byte[] PackTime(DateTime dt)
{ {
dt = ToLocal(dt, true);
byte[] pb = new byte[5]; byte[] pb = new byte[5];
// Pack time to 5 byte structure: // Pack time to 5 byte structure:
@ -88,6 +96,7 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
/// <param name="pb">Packed time, 5 bytes.</param> /// <param name="pb">Packed time, 5 bytes.</param>
/// <returns>Unpacked <c>DateTime</c> object.</returns> /// <returns>Unpacked <c>DateTime</c> object.</returns>
[Obsolete]
public static DateTime UnpackTime(byte[] pb) public static DateTime UnpackTime(byte[] pb)
{ {
Debug.Assert((pb != null) && (pb.Length == 5)); Debug.Assert((pb != null) && (pb.Length == 5));
@ -104,7 +113,8 @@ namespace KeePassLib.Utility
int nMinute = ((n4 & 0x0000000F) << 2) | (n5 >> 6); int nMinute = ((n4 & 0x0000000F) << 2) | (n5 >> 6);
int nSecond = n5 & 0x0000003F; int nSecond = n5 & 0x0000003F;
return new DateTime(nYear, nMonth, nDay, nHour, nMinute, nSecond); return (new DateTime(nYear, nMonth, nDay, nHour, nMinute,
nSecond, DateTimeKind.Local)).ToUniversalTime();
} }
/// <summary> /// <summary>
@ -112,10 +122,13 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
/// <param name="dt">Object to be encoded.</param> /// <param name="dt">Object to be encoded.</param>
/// <returns>Packed time, 7 bytes (<c>PW_TIME</c>).</returns> /// <returns>Packed time, 7 bytes (<c>PW_TIME</c>).</returns>
[Obsolete]
public static byte[] PackPwTime(DateTime dt) public static byte[] PackPwTime(DateTime dt)
{ {
Debug.Assert(PwTimeLength == 7); Debug.Assert(PwTimeLength == 7);
dt = ToLocal(dt, true);
byte[] pb = new byte[7]; byte[] pb = new byte[7];
pb[0] = (byte)(dt.Year & 0xFF); pb[0] = (byte)(dt.Year & 0xFF);
pb[1] = (byte)(dt.Year >> 8); pb[1] = (byte)(dt.Year >> 8);
@ -133,6 +146,7 @@ namespace KeePassLib.Utility
/// </summary> /// </summary>
/// <param name="pb">Packed time, 7 bytes.</param> /// <param name="pb">Packed time, 7 bytes.</param>
/// <returns>Unpacked <c>DateTime</c> object.</returns> /// <returns>Unpacked <c>DateTime</c> object.</returns>
[Obsolete]
public static DateTime UnpackPwTime(byte[] pb) public static DateTime UnpackPwTime(byte[] pb)
{ {
Debug.Assert(PwTimeLength == 7); Debug.Assert(PwTimeLength == 7);
@ -140,8 +154,8 @@ namespace KeePassLib.Utility
Debug.Assert(pb != null); if(pb == null) throw new ArgumentNullException("pb"); Debug.Assert(pb != null); if(pb == null) throw new ArgumentNullException("pb");
Debug.Assert(pb.Length == 7); if(pb.Length != 7) throw new ArgumentException(); 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], 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]); (int)pb[4], (int)pb[5], (int)pb[6], DateTimeKind.Local)).ToUniversalTime();
} }
/// <summary> /// <summary>
@ -151,23 +165,32 @@ namespace KeePassLib.Utility
/// <returns>String representing the specified <c>DateTime</c> object.</returns> /// <returns>String representing the specified <c>DateTime</c> object.</returns>
public static string ToDisplayString(DateTime dt) public static string ToDisplayString(DateTime dt)
{ {
return dt.ToString(); return ToLocal(dt, true).ToString();
} }
public static string ToDisplayStringDateOnly(DateTime dt) public static string ToDisplayStringDateOnly(DateTime dt)
{ {
return dt.ToString("d"); return ToLocal(dt, true).ToString("d");
} }
public static DateTime FromDisplayString(string strDisplay) public static DateTime FromDisplayString(string strDisplay)
{ {
DateTime dt; DateTime dt;
if(FromDisplayStringEx(strDisplay, out dt)) return dt;
return DateTime.Now;
}
public static bool FromDisplayStringEx(string strDisplay, out DateTime dt)
{
#if KeePassLibSD #if KeePassLibSD
try { dt = DateTime.Parse(strDisplay); return dt; } try { dt = ToLocal(DateTime.Parse(strDisplay), true); return true; }
catch(Exception) { } catch(Exception) { }
#else #else
if(DateTime.TryParse(strDisplay, out dt)) return dt; if(DateTime.TryParse(strDisplay, out dt))
{
dt = ToLocal(dt, true);
return true;
}
// For some custom formats specified using the Control Panel, // For some custom formats specified using the Control Panel,
// DateTime.ToString returns the correct string, but // DateTime.ToString returns the correct string, but
@ -175,19 +198,25 @@ namespace KeePassLib.Utility
// https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae // https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae
if((m_strDtfStd == null) || (m_strDtfDate == null)) if((m_strDtfStd == null) || (m_strDtfDate == null))
{ {
DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7); DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7, DateTimeKind.Local);
m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni); m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni);
m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni); m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni);
} }
const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces; const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces;
if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt)) if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt))
return dt; {
dt = ToLocal(dt, true);
return true;
}
if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt)) if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt))
return dt; {
dt = ToLocal(dt, true);
return true;
}
#endif #endif
Debug.Assert(false); Debug.Assert(false);
return DateTime.Now; return false;
} }
#if !KeePassLibSD #if !KeePassLibSD
@ -277,8 +306,10 @@ namespace KeePassLib.Utility
public static string SerializeUtc(DateTime dt) public static string SerializeUtc(DateTime dt)
{ {
string str = dt.ToUniversalTime().ToString("s"); Debug.Assert(dt.Kind != DateTimeKind.Unspecified);
if(str.EndsWith("Z") == false) str += "Z";
string str = ToUtc(dt, false).ToString("s");
if(!str.EndsWith("Z")) str += "Z";
return str; return str;
} }
@ -289,23 +320,13 @@ namespace KeePassLib.Utility
if(str.EndsWith("Z")) str = str.Substring(0, str.Length - 1); if(str.EndsWith("Z")) str = str.Substring(0, str.Length - 1);
bool bResult = StrUtil.TryParseDateTime(str, out dt); bool bResult = StrUtil.TryParseDateTime(str, out dt);
if(bResult) dt = dt.ToLocalTime(); if(bResult) dt = ToUtc(dt, true);
return bResult; return bResult;
} }
/// <summary> public static double SerializeUnix(DateTime dt)
/// Deserializes a UTC XML DateTime to a local time, or returns defaultValue if it could not be parsed
/// </summary>
public static DateTime DeserializeUtcOrDefault(string xmlDateTimeString, DateTime defaultValue)
{ {
try return (ToUtc(dt, false) - TimeUtil.UnixRoot).TotalSeconds;
{
return System.Xml.XmlConvert.ToDateTime(xmlDateTimeString, System.Xml.XmlDateTimeSerializationMode.Local);
}
catch(FormatException)
{
return defaultValue;
}
} }
@ -322,15 +343,21 @@ namespace KeePassLib.Utility
} }
catch(Exception) { Debug.Assert(false); } catch(Exception) { Debug.Assert(false); }
return DateTime.Now; return DateTime.UtcNow;
} }
#if !KeePassLibSD #if !KeePassLibSD
[Obsolete]
public static DateTime? ParseUSTextDate(string strDate)
{
return ParseUSTextDate(strDate, DateTimeKind.Unspecified);
}
private static string[] m_vUSMonths = null; private static string[] m_vUSMonths = null;
/// <summary> /// <summary>
/// Parse a US textual date string, like e.g. "January 02, 2012". /// Parse a US textual date string, like e.g. "January 02, 2012".
/// </summary> /// </summary>
public static DateTime? ParseUSTextDate(string strDate) public static DateTime? ParseUSTextDate(string strDate, DateTimeKind k)
{ {
if(strDate == null) { Debug.Assert(false); return null; } if(strDate == null) { Debug.Assert(false); return null; }
@ -352,7 +379,7 @@ namespace KeePassLib.Utility
int iDay, iYear; int iDay, iYear;
if(int.TryParse(strDay, out iDay) && if(int.TryParse(strDay, out iDay) &&
int.TryParse(v[1].Trim(), out iYear)) int.TryParse(v[1].Trim(), out iYear))
return new DateTime(iYear, i + 1, iDay); return new DateTime(iYear, i + 1, iDay, 0, 0, 0, k);
else { Debug.Assert(false); return null; } else { Debug.Assert(false); return null; }
} }
} }
@ -362,11 +389,13 @@ namespace KeePassLib.Utility
#endif #endif
private static readonly DateTime m_dtInvMin = private static readonly DateTime m_dtInvMin =
new DateTime(2999, 12, 27, 23, 59, 59); new DateTime(2999, 12, 27, 23, 59, 59, DateTimeKind.Utc);
private static readonly DateTime m_dtInvMax = private static readonly DateTime m_dtInvMax =
new DateTime(2999, 12, 29, 23, 59, 59); new DateTime(2999, 12, 29, 23, 59, 59, DateTimeKind.Utc);
public static int Compare(DateTime dtA, DateTime dtB, bool bUnkIsPast) public static int Compare(DateTime dtA, DateTime dtB, bool bUnkIsPast)
{ {
Debug.Assert(dtA.Kind == dtB.Kind);
if(bUnkIsPast) if(bUnkIsPast)
{ {
// 2999-12-28 23:59:59 in KeePass 1.x means 'unknown'; // 2999-12-28 23:59:59 in KeePass 1.x means 'unknown';
@ -399,5 +428,64 @@ namespace KeePassLib.Utility
return Compare(tlA.LastModificationTime, tlB.LastModificationTime, return Compare(tlA.LastModificationTime, tlB.LastModificationTime,
bUnkIsPast); bUnkIsPast);
} }
public static DateTime ToUtc(DateTime dt, bool bUnspecifiedIsUtc)
{
DateTimeKind k = dt.Kind;
if(k == DateTimeKind.Utc) return dt;
if(k == DateTimeKind.Local) return dt.ToUniversalTime();
Debug.Assert(k == DateTimeKind.Unspecified);
if(bUnspecifiedIsUtc)
return new DateTime(dt.Ticks, DateTimeKind.Utc);
return dt.ToUniversalTime(); // Unspecified = local
}
public static DateTime ToLocal(DateTime dt, bool bUnspecifiedIsLocal)
{
DateTimeKind k = dt.Kind;
if(k == DateTimeKind.Local) return dt;
if(k == DateTimeKind.Utc) return dt.ToLocalTime();
Debug.Assert(k == DateTimeKind.Unspecified);
if(bUnspecifiedIsLocal)
return new DateTime(dt.Ticks, DateTimeKind.Local);
return dt.ToLocalTime(); // Unspecified = UTC
}
/* internal static DateTime RoundToMultOf2PowLess1s(DateTime dt)
{
long l2Pow = m_lTicks2PowLess1s;
if(l2Pow == 0)
{
l2Pow = 1;
while(true)
{
l2Pow <<= 1;
if(l2Pow >= TimeSpan.TicksPerSecond) break;
}
l2Pow >>= 1;
m_lTicks2PowLess1s = l2Pow;
Debug.Assert(TimeSpan.TicksPerSecond == 10000000L); // .NET
Debug.Assert(l2Pow == (1L << 23)); // .NET
}
long l = dt.Ticks;
if((l % l2Pow) == 0L) return dt;
// Round down to full second
l /= TimeSpan.TicksPerSecond;
l *= TimeSpan.TicksPerSecond;
// Round up to multiple of l2Pow
long l2PowM1 = l2Pow - 1L;
l = (l + l2PowM1) & ~l2PowM1;
DateTime dtRnd = new DateTime(l, dt.Kind);
Debug.Assert((dtRnd.Ticks % l2Pow) == 0L);
Debug.Assert(dtRnd.ToString("u") == dt.ToString("u"));
return dtRnd;
} */
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
KeePass Password Safe - The Open-Source Password Manager KeePass Password Safe - The Open-Source Password Manager
Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> Copyright (C) 2003-2017 Dominik Reichl <dominik.reichl@t-online.de>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -285,7 +285,7 @@ namespace KeePassLib.Utility
else // Unhide else // Unhide
{ {
fa &= ~FileAttributes.Hidden; fa &= ~FileAttributes.Hidden;
if((long)fa == 0) fa |= FileAttributes.Normal; if((long)fa == 0) fa = FileAttributes.Normal;
} }
File.SetAttributes(strFile, fa); File.SetAttributes(strFile, fa);