Merge branch 'Keepass_Orig' + adapt to changes in KeePassLib. This introduced KDBX4 in Keepass2Android.
NOTE: seems like merging broke the capability to read KDBX<=3. Conflicts: src/KeePassLib2Android/Collections/AutoTypeConfig.cs src/KeePassLib2Android/Collections/ProtectedBinaryDictionary.cs src/KeePassLib2Android/Collections/ProtectedStringDictionary.cs src/KeePassLib2Android/Collections/PwObjectList.cs src/KeePassLib2Android/Collections/PwObjectPool.cs src/KeePassLib2Android/Collections/StringDictionaryEx.cs src/KeePassLib2Android/Cryptography/Cipher/CipherPool.cs src/KeePassLib2Android/Cryptography/Cipher/ICipherEngine.cs src/KeePassLib2Android/Cryptography/Cipher/Salsa20Cipher.cs src/KeePassLib2Android/Cryptography/Cipher/StandardAesEngine.cs src/KeePassLib2Android/Cryptography/CryptoRandom.cs src/KeePassLib2Android/Cryptography/CryptoRandomStream.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/CompositeKey.cs src/KeePassLib2Android/Keys/IUserKey.cs src/KeePassLib2Android/Keys/KcpCustomKey.cs src/KeePassLib2Android/Keys/KcpKeyFile.cs src/KeePassLib2Android/Keys/KcpPassword.cs src/KeePassLib2Android/Keys/KcpUserAccount.cs src/KeePassLib2Android/Keys/KeyProvider.cs src/KeePassLib2Android/Keys/KeyProviderPool.cs src/KeePassLib2Android/Keys/KeyValidator.cs src/KeePassLib2Android/Keys/KeyValidatorPool.cs src/KeePassLib2Android/Keys/UserKeyType.cs src/KeePassLib2Android/Native/NativeLib.cs src/KeePassLib2Android/Native/NativeMethods.cs src/KeePassLib2Android/Properties/AssemblyInfo.cs src/KeePassLib2Android/PwCustomIcon.cs src/KeePassLib2Android/PwDatabase.cs src/KeePassLib2Android/PwDefs.cs src/KeePassLib2Android/PwDeletedObject.cs src/KeePassLib2Android/PwEntry.cs src/KeePassLib2Android/PwEnums.cs src/KeePassLib2Android/PwGroup.cs src/KeePassLib2Android/PwUuid.cs src/KeePassLib2Android/Resources/KLRes.Generated.cs src/KeePassLib2Android/Security/ProtectedBinary.cs src/KeePassLib2Android/Security/ProtectedString.cs src/KeePassLib2Android/Security/XorredBuffer.cs src/KeePassLib2Android/Serialization/BinaryReaderEx.cs src/KeePassLib2Android/Serialization/FileLock.cs src/KeePassLib2Android/Serialization/FileTransactionEx.cs src/KeePassLib2Android/Serialization/HashedBlockStream.cs src/KeePassLib2Android/Serialization/IOConnection.cs src/KeePassLib2Android/Serialization/IOConnectionInfo.cs src/KeePassLib2Android/Serialization/KdbxFile.Read.Streamed.cs src/KeePassLib2Android/Serialization/KdbxFile.Read.cs src/KeePassLib2Android/Serialization/KdbxFile.Write.cs src/KeePassLib2Android/Serialization/KdbxFile.cs src/KeePassLib2Android/Serialization/OldFormatException.cs src/KeePassLib2Android/Translation/KPControlCustomization.cs src/KeePassLib2Android/Translation/KPFormCustomization.cs src/KeePassLib2Android/Translation/KPStringTable.cs src/KeePassLib2Android/Translation/KPStringTableItem.cs src/KeePassLib2Android/Translation/KPTranslation.cs src/KeePassLib2Android/Translation/KPTranslationProperties.cs src/KeePassLib2Android/Utility/AppLogEx.cs src/KeePassLib2Android/Utility/GfxUtil.cs src/KeePassLib2Android/Utility/MemUtil.cs src/KeePassLib2Android/Utility/MessageService.cs src/KeePassLib2Android/Utility/StrUtil.cs src/KeePassLib2Android/Utility/TimeUtil.cs src/KeePassLib2Android/Utility/UrlUtil.cs
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -194,13 +194,6 @@ namespace KeePassLib.Collections | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public void Add(AutoTypeAssociation a) | ||||
| 		{ | ||||
| 			Debug.Assert(a != null); if(a == null) throw new ArgumentNullException("a"); | ||||
|  | ||||
| 			m_lWindowAssocs.Add(a); | ||||
| 		} | ||||
|  | ||||
| 		public AutoTypeAssociation GetAt(int iIndex) | ||||
| 		{ | ||||
| 			if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) | ||||
| @@ -209,6 +202,22 @@ namespace KeePassLib.Collections | ||||
| 			return m_lWindowAssocs[iIndex]; | ||||
| 		} | ||||
|  | ||||
| 		public void Add(AutoTypeAssociation a) | ||||
| 		{ | ||||
| 			if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); } | ||||
|  | ||||
| 			m_lWindowAssocs.Add(a); | ||||
| 		} | ||||
|  | ||||
| 		public void Insert(int iIndex, AutoTypeAssociation a) | ||||
| 		{ | ||||
| 			if((iIndex < 0) || (iIndex > m_lWindowAssocs.Count)) | ||||
| 				throw new ArgumentOutOfRangeException("iIndex"); | ||||
| 			if(a == null) { Debug.Assert(false); throw new ArgumentNullException("a"); } | ||||
|  | ||||
| 			m_lWindowAssocs.Insert(iIndex, a); | ||||
| 		} | ||||
|  | ||||
| 		public void RemoveAt(int iIndex) | ||||
| 		{ | ||||
| 			if((iIndex < 0) || (iIndex >= m_lWindowAssocs.Count)) | ||||
| @@ -216,5 +225,20 @@ namespace KeePassLib.Collections | ||||
|  | ||||
| 			m_lWindowAssocs.RemoveAt(iIndex); | ||||
| 		} | ||||
|  | ||||
| 		// public void Sort() | ||||
| 		// { | ||||
| 		//	m_lWindowAssocs.Sort(AutoTypeConfig.AssocCompareFn); | ||||
| 		// } | ||||
|  | ||||
| 		// private static int AssocCompareFn(AutoTypeAssociation x, | ||||
| 		//	AutoTypeAssociation y) | ||||
| 		// { | ||||
| 		//	if(x == null) { Debug.Assert(false); return ((y == null) ? 0 : -1); } | ||||
| 		//	if(y == null) { Debug.Assert(false); return 1; } | ||||
| 		//	int cn = x.WindowName.CompareTo(y.WindowName); | ||||
| 		//	if(cn != 0) return cn; | ||||
| 		//	return x.Sequence.CompareTo(y.Sequence); | ||||
| 		// } | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -25,7 +25,6 @@ using System.Diagnostics; | ||||
|  | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| #if KeePassLibSD | ||||
| using KeePassLibSD; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -284,11 +284,7 @@ namespace KeePassLib.Collections | ||||
|  | ||||
| 		public List<string> GetKeys() | ||||
| 		{ | ||||
| 			List<string> v = new List<string>(); | ||||
|  | ||||
| 			foreach(string strKey in m_vStrings.Keys) v.Add(strKey); | ||||
|  | ||||
| 			return v; | ||||
| 			return new List<string>(m_vStrings.Keys); | ||||
| 		} | ||||
|  | ||||
| 		public void EnableProtection(string strField, bool bProtect) | ||||
| @@ -300,7 +296,8 @@ namespace KeePassLib.Collections | ||||
| 			{ | ||||
| 				byte[] pbData = ps.ReadUtf8(); | ||||
| 				Set(strField, new ProtectedString(bProtect, pbData)); | ||||
| 				MemUtil.ZeroByteArray(pbData); | ||||
|  | ||||
| 				if(bProtect) MemUtil.ZeroByteArray(pbData); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -233,7 +233,7 @@ namespace KeePassLib.Collections | ||||
| 			if(nCount <= 1) return; | ||||
|  | ||||
| 			int nIndex = m_vObjects.IndexOf(tObject); | ||||
| 			Debug.Assert(nIndex >= 0); | ||||
| 			if(nIndex < 0) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			if(bUp && (nIndex > 0)) // No assert for top item | ||||
| 			{ | ||||
| @@ -249,6 +249,68 @@ namespace KeePassLib.Collections | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public void MoveOne(T[] vObjects, bool bUp) | ||||
| 		{ | ||||
| 			Debug.Assert(vObjects != null); | ||||
| 			if(vObjects == null) throw new ArgumentNullException("vObjects"); | ||||
| 		/// <summary> | ||||
| 			List<int> lIndices = new List<int>(); | ||||
| 			foreach(T t in vObjects) | ||||
| 			{ | ||||
| 				if(t == null) { Debug.Assert(false); continue; } | ||||
| 		/// Move some of the objects in this list to the top/bottom. | ||||
| 				int p = IndexOf(t); | ||||
| 				if(p >= 0) lIndices.Add(p); | ||||
| 				else { Debug.Assert(false); } | ||||
| 			} | ||||
| 		/// </summary> | ||||
| 			MoveOne(lIndices.ToArray(), bUp); | ||||
| 		} | ||||
| 		/// <param name="vObjects">List of objects to be moved.</param> | ||||
| 		public void MoveOne(int[] vIndices, bool bUp) | ||||
| 		{ | ||||
| 			Debug.Assert(vIndices != null); | ||||
| 			if(vIndices == null) throw new ArgumentNullException("vIndices"); | ||||
| 		/// <param name="bTop">Move to top. If <c>false</c>, move to bottom.</param> | ||||
| 			int n = m_vObjects.Count; | ||||
| 			if(n <= 1) return; // No moving possible | ||||
|  | ||||
| 			int m = vIndices.Length; | ||||
| 			if(m == 0) return; // Nothing to move | ||||
|  | ||||
| 			int[] v = new int[m]; | ||||
| 			Array.Copy(vIndices, v, m); | ||||
| 			Array.Sort<int>(v); | ||||
|  | ||||
| 			if((bUp && (v[0] <= 0)) || (!bUp && (v[m - 1] >= (n - 1)))) | ||||
| 				return; // Moving as a block is not possible | ||||
|  | ||||
| 			int iStart = (bUp ? 0 : (m - 1)); | ||||
| 			int iExcl = (bUp ? m : -1); | ||||
| 			int iStep = (bUp ? 1 : -1); | ||||
|  | ||||
| 			for(int i = iStart; i != iExcl; i += iStep) | ||||
| 			{ | ||||
| 				int p = v[i]; | ||||
| 				if((p < 0) || (p >= n)) { Debug.Assert(false); continue; } | ||||
|  | ||||
| 				T t = m_vObjects[p]; | ||||
|  | ||||
| 				if(bUp) | ||||
| 				{ | ||||
| 					Debug.Assert(p > 0); | ||||
| 					m_vObjects.RemoveAt(p); | ||||
| 					m_vObjects.Insert(p - 1, t); | ||||
| 				} | ||||
| 				else // Down | ||||
| 				{ | ||||
| 					Debug.Assert(p < (n - 1)); | ||||
| 					m_vObjects.RemoveAt(p); | ||||
| 					m_vObjects.Insert(p + 1, t); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Move some of the objects in this list to the top/bottom. | ||||
| 		/// </summary> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,6 +18,7 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Diagnostics; | ||||
| @@ -77,4 +78,154 @@ namespace KeePassLib.Collections | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	internal sealed class PwObjectPoolEx | ||||
| 	{ | ||||
| 		private Dictionary<PwUuid, ulong> m_dUuidToId = | ||||
| 			new Dictionary<PwUuid, ulong>(); | ||||
| 		private Dictionary<ulong, IStructureItem> m_dIdToItem = | ||||
| 			new Dictionary<ulong, IStructureItem>(); | ||||
|  | ||||
| 		private PwObjectPoolEx() | ||||
| 		{ | ||||
| } | ||||
|  | ||||
| 		public static PwObjectPoolEx FromGroup(PwGroup pg) | ||||
| 		{ | ||||
| 			PwObjectPoolEx p = new PwObjectPoolEx(); | ||||
|  | ||||
| 			if(pg == null) { Debug.Assert(false); return p; } | ||||
|  | ||||
| 			ulong uFreeId = 2; // 0 = "not found", 1 is a hole | ||||
|  | ||||
| 			p.m_dUuidToId[pg.Uuid] = uFreeId; | ||||
| 			p.m_dIdToItem[uFreeId] = pg; | ||||
| 			uFreeId += 2; // Make hole | ||||
|  | ||||
| 			p.AddGroupRec(pg, ref uFreeId); | ||||
| 			return p; | ||||
| 		} | ||||
|  | ||||
| 		private void AddGroupRec(PwGroup pg, ref ulong uFreeId) | ||||
| 		{ | ||||
| 			if(pg == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			ulong uId = uFreeId; | ||||
|  | ||||
| 			// Consecutive entries must have consecutive IDs | ||||
| 			foreach(PwEntry pe in pg.Entries) | ||||
| 			{ | ||||
| 				Debug.Assert(!m_dUuidToId.ContainsKey(pe.Uuid)); | ||||
| 				Debug.Assert(!m_dIdToItem.ContainsValue(pe)); | ||||
|  | ||||
| 				m_dUuidToId[pe.Uuid] = uId; | ||||
| 				m_dIdToItem[uId] = pe; | ||||
| 				++uId; | ||||
| 			} | ||||
| 			++uId; // Make hole | ||||
|  | ||||
| 			// Consecutive groups must have consecutive IDs | ||||
| 			foreach(PwGroup pgSub in pg.Groups) | ||||
| 			{ | ||||
| 				Debug.Assert(!m_dUuidToId.ContainsKey(pgSub.Uuid)); | ||||
| 				Debug.Assert(!m_dIdToItem.ContainsValue(pgSub)); | ||||
|  | ||||
| 				m_dUuidToId[pgSub.Uuid] = uId; | ||||
| 				m_dIdToItem[uId] = pgSub; | ||||
| 				++uId; | ||||
| 			} | ||||
| 			++uId; // Make hole | ||||
|  | ||||
| 			foreach(PwGroup pgSub in pg.Groups) | ||||
| 			{ | ||||
| 				AddGroupRec(pgSub, ref uId); | ||||
| 			} | ||||
|  | ||||
| 			uFreeId = uId; | ||||
| 		} | ||||
|  | ||||
| 		public ulong GetIdByUuid(PwUuid pwUuid) | ||||
| 		{ | ||||
| 			if(pwUuid == null) { Debug.Assert(false); return 0; } | ||||
|  | ||||
| 			ulong uId; | ||||
| 			m_dUuidToId.TryGetValue(pwUuid, out uId); | ||||
| 			return uId; | ||||
| 		} | ||||
|  | ||||
| 		public IStructureItem GetItemByUuid(PwUuid pwUuid) | ||||
| 		{ | ||||
| 			if(pwUuid == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			ulong uId; | ||||
| 			if(!m_dUuidToId.TryGetValue(pwUuid, out uId)) return null; | ||||
| 			Debug.Assert(uId != 0); | ||||
|  | ||||
| 			return GetItemById(uId); | ||||
| 		} | ||||
|  | ||||
| 		public IStructureItem GetItemById(ulong uId) | ||||
| 		{ | ||||
| 			IStructureItem p; | ||||
| 			m_dIdToItem.TryGetValue(uId, out p); | ||||
| 			return p; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	internal sealed class PwObjectBlock<T> : IEnumerable<T> | ||||
| 		where T : class, ITimeLogger, IStructureItem, IDeepCloneable<T> | ||||
| 	{ | ||||
| 		private List<T> m_l = new List<T>(); | ||||
|  | ||||
| 		public T PrimaryItem | ||||
| 		{ | ||||
| 			get { return ((m_l.Count > 0) ? m_l[0] : null); } | ||||
| 		} | ||||
|  | ||||
| 		private DateTime m_dtLocationChanged = DateTime.MinValue; | ||||
| 		public DateTime LocationChanged | ||||
| 		{ | ||||
| 			get { return m_dtLocationChanged; } | ||||
| 		} | ||||
|  | ||||
| 		private PwObjectPoolEx m_poolAssoc = null; | ||||
| 		public PwObjectPoolEx PoolAssoc | ||||
| 		{ | ||||
| 			get { return m_poolAssoc; } | ||||
| 		} | ||||
|  | ||||
| 		public PwObjectBlock() | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| #if DEBUG | ||||
| 		public override string ToString() | ||||
| 		{ | ||||
| 			return ("PwObjectBlock, Count = " + m_l.Count.ToString()); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		IEnumerator IEnumerable.GetEnumerator() | ||||
| 		{ | ||||
| 			return m_l.GetEnumerator(); | ||||
| 		} | ||||
|  | ||||
| 		public IEnumerator<T> GetEnumerator() | ||||
| 		{ | ||||
| 			return m_l.GetEnumerator(); | ||||
| 		} | ||||
|  | ||||
| 		public void Add(T t, DateTime dtLoc, PwObjectPoolEx pool) | ||||
| 		{ | ||||
| 			if(t == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			m_l.Add(t); | ||||
|  | ||||
| 			if(dtLoc > m_dtLocationChanged) | ||||
| 			{ | ||||
| 				m_dtLocationChanged = dtLoc; | ||||
| 				m_poolAssoc = pool; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -32,14 +32,14 @@ using KeePassLibSD; | ||||
| namespace KeePassLib.Collections | ||||
| { | ||||
| 	public sealed class StringDictionaryEx : IDeepCloneable<StringDictionaryEx>, | ||||
| 		IEnumerable<KeyValuePair<string, string>> | ||||
| 		IEnumerable<KeyValuePair<string, string>>, IEquatable<StringDictionaryEx> | ||||
| 	{ | ||||
| 		private SortedDictionary<string, string> m_vDict = | ||||
| 		private SortedDictionary<string, string> m_dict = | ||||
| 			new SortedDictionary<string, string>(); | ||||
|  | ||||
| 		public int Count | ||||
| 		{ | ||||
| 			get { return m_vDict.Count; } | ||||
| 			get { return m_dict.Count; } | ||||
| 		} | ||||
|  | ||||
| 		public StringDictionaryEx() | ||||
| @@ -48,39 +48,53 @@ namespace KeePassLib.Collections | ||||
|  | ||||
| 		IEnumerator IEnumerable.GetEnumerator() | ||||
| 		{ | ||||
| 			return m_vDict.GetEnumerator(); | ||||
| 			return m_dict.GetEnumerator(); | ||||
| 		} | ||||
|  | ||||
| 		public IEnumerator<KeyValuePair<string, string>> GetEnumerator() | ||||
| 		{ | ||||
| 			return m_vDict.GetEnumerator(); | ||||
| 			return m_dict.GetEnumerator(); | ||||
| 		} | ||||
|  | ||||
| 		public StringDictionaryEx CloneDeep() | ||||
| 		{ | ||||
| 			StringDictionaryEx plNew = new StringDictionaryEx(); | ||||
| 			StringDictionaryEx sdNew = new StringDictionaryEx(); | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvpStr in m_vDict) | ||||
| 				plNew.Set(kvpStr.Key, kvpStr.Value); | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 				sdNew.m_dict[kvp.Key] = kvp.Value; // Strings are immutable | ||||
|  | ||||
| 			return plNew; | ||||
| 			return sdNew; | ||||
| 		} | ||||
|  | ||||
| 		public bool Equals(StringDictionaryEx sdOther) | ||||
| 		{ | ||||
| 			if(sdOther == null) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			if(m_dict.Count != sdOther.m_dict.Count) return false; | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in sdOther.m_dict) | ||||
| 			{ | ||||
| 				string str = Get(kvp.Key); | ||||
| 				if((str == null) || (str != kvp.Value)) return false; | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public string Get(string strName) | ||||
| 		{ | ||||
| 			Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); | ||||
| 			if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); } | ||||
|  | ||||
| 			string s; | ||||
| 			if(m_vDict.TryGetValue(strName, out s)) return s; | ||||
|  | ||||
| 			if(m_dict.TryGetValue(strName, out s)) return s; | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public bool Exists(string strName) | ||||
| 		{ | ||||
| 			Debug.Assert(strName != null); if(strName == null) throw new ArgumentNullException("strName"); | ||||
| 			if(strName == null) { Debug.Assert(false); throw new ArgumentNullException("strName"); } | ||||
|  | ||||
| 			return m_vDict.ContainsKey(strName); | ||||
| 			return m_dict.ContainsKey(strName); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -92,10 +106,10 @@ namespace KeePassLib.Collections | ||||
| 		/// parameters is <c>null</c>.</exception> | ||||
| 		public void Set(string strField, string strNewValue) | ||||
| 		{ | ||||
| 			Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); | ||||
| 			Debug.Assert(strNewValue != null); if(strNewValue == null) throw new ArgumentNullException("strNewValue"); | ||||
| 			if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); } | ||||
| 			if(strNewValue == null) { Debug.Assert(false); throw new ArgumentNullException("strNewValue"); } | ||||
|  | ||||
| 			m_vDict[strField] = strNewValue; | ||||
| 			m_dict[strField] = strNewValue; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -108,9 +122,9 @@ namespace KeePassLib.Collections | ||||
| 		/// parameter is <c>null</c>.</exception> | ||||
| 		public bool Remove(string strField) | ||||
| 		{ | ||||
| 			Debug.Assert(strField != null); if(strField == null) throw new ArgumentNullException("strField"); | ||||
| 			if(strField == null) { Debug.Assert(false); throw new ArgumentNullException("strField"); } | ||||
|  | ||||
| 			return m_vDict.Remove(strField); | ||||
| 			return m_dict.Remove(strField); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										415
									
								
								src/KeePassLib2Android/Collections/VariantDictionary.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										415
									
								
								src/KeePassLib2Android/Collections/VariantDictionary.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,415 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Collections | ||||
| { | ||||
| 	public class VariantDictionary : ICloneable | ||||
| 	{ | ||||
| 		private const ushort VdVersion = 0x0100; | ||||
| 		private const ushort VdmCritical = 0xFF00; | ||||
| 		private const ushort VdmInfo = 0x00FF; | ||||
|  | ||||
| 		private Dictionary<string, object> m_d = new Dictionary<string, object>(); | ||||
|  | ||||
| 		private enum VdType : byte | ||||
| 		{ | ||||
| 			None = 0, | ||||
|  | ||||
| 			// Byte = 0x02, | ||||
| 			// UInt16 = 0x03, | ||||
| 			UInt32 = 0x04, | ||||
| 			UInt64 = 0x05, | ||||
|  | ||||
| 			// Signed mask: 0x08 | ||||
| 			Bool = 0x08, | ||||
| 			// SByte = 0x0A, | ||||
| 			// Int16 = 0x0B, | ||||
| 			Int32 = 0x0C, | ||||
| 			Int64 = 0x0D, | ||||
|  | ||||
| 			// Float = 0x10, | ||||
| 			// Double = 0x11, | ||||
| 			// Decimal = 0x12, | ||||
|  | ||||
| 			// Char = 0x17, // 16-bit Unicode character | ||||
| 			String = 0x18, | ||||
|  | ||||
| 			// Array mask: 0x40 | ||||
| 			ByteArray = 0x42 | ||||
| 		} | ||||
|  | ||||
| 		public int Count | ||||
| 		{ | ||||
| 			get { return m_d.Count; } | ||||
| 		} | ||||
|  | ||||
| 		public VariantDictionary() | ||||
| 		{ | ||||
| 			Debug.Assert((VdmCritical & VdmInfo) == ushort.MinValue); | ||||
| 			Debug.Assert((VdmCritical | VdmInfo) == ushort.MaxValue); | ||||
| 		} | ||||
|  | ||||
| 		private bool Get<T>(string strName, out T t) | ||||
| 		{ | ||||
| 			t = default(T); | ||||
|  | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			object o; | ||||
| 			if(!m_d.TryGetValue(strName, out o)) return false; // No assert | ||||
|  | ||||
| 			if(o == null) { Debug.Assert(false); return false; } | ||||
| 			if(o.GetType() != typeof(T)) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			t = (T)o; | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		private void SetStruct<T>(string strName, T t) | ||||
| 			where T : struct | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } | ||||
|  | ||||
| #if DEBUG | ||||
| 			T tEx; | ||||
| 			Get<T>(strName, out tEx); // Assert same type | ||||
| #endif | ||||
|  | ||||
| 			m_d[strName] = t; | ||||
| 		} | ||||
|  | ||||
| 		private void SetRef<T>(string strName, T t) | ||||
| 			where T : class | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } | ||||
| 			if(t == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| #if DEBUG | ||||
| 			T tEx; | ||||
| 			Get<T>(strName, out tEx); // Assert same type | ||||
| #endif | ||||
|  | ||||
| 			m_d[strName] = t; | ||||
| 		} | ||||
|  | ||||
| 		public bool Remove(string strName) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			return m_d.Remove(strName); | ||||
| 		} | ||||
|  | ||||
| 		public void CopyTo(VariantDictionary d) | ||||
| 		{ | ||||
| 			if(d == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			// Do not clear the target | ||||
| 			foreach(KeyValuePair<string, object> kvp in m_d) | ||||
| 			{ | ||||
| 				d.m_d[kvp.Key] = kvp.Value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public Type GetTypeOf(string strName) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			object o; | ||||
| 			m_d.TryGetValue(strName, out o); | ||||
| 			if(o == null) return null; // No assert | ||||
|  | ||||
| 			return o.GetType(); | ||||
| 		} | ||||
|  | ||||
| 		public uint GetUInt32(string strName, uint uDefault) | ||||
| 		{ | ||||
| 			uint u; | ||||
| 			if(Get<uint>(strName, out u)) return u; | ||||
| 			return uDefault; | ||||
| 		} | ||||
|  | ||||
| 		public void SetUInt32(string strName, uint uValue) | ||||
| 		{ | ||||
| 			SetStruct<uint>(strName, uValue); | ||||
| 		} | ||||
|  | ||||
| 		public ulong GetUInt64(string strName, ulong uDefault) | ||||
| 		{ | ||||
| 			ulong u; | ||||
| 			if(Get<ulong>(strName, out u)) return u; | ||||
| 			return uDefault; | ||||
| 		} | ||||
|  | ||||
| 		public void SetUInt64(string strName, ulong uValue) | ||||
| 		{ | ||||
| 			SetStruct<ulong>(strName, uValue); | ||||
| 		} | ||||
|  | ||||
| 		public bool GetBool(string strName, bool bDefault) | ||||
| 		{ | ||||
| 			bool b; | ||||
| 			if(Get<bool>(strName, out b)) return b; | ||||
| 			return bDefault; | ||||
| 		} | ||||
|  | ||||
| 		public void SetBool(string strName, bool bValue) | ||||
| 		{ | ||||
| 			SetStruct<bool>(strName, bValue); | ||||
| 		} | ||||
|  | ||||
| 		public int GetInt32(string strName, int iDefault) | ||||
| 		{ | ||||
| 			int i; | ||||
| 			if(Get<int>(strName, out i)) return i; | ||||
| 			return iDefault; | ||||
| 		} | ||||
|  | ||||
| 		public void SetInt32(string strName, int iValue) | ||||
| 		{ | ||||
| 			SetStruct<int>(strName, iValue); | ||||
| 		} | ||||
|  | ||||
| 		public long GetInt64(string strName, long lDefault) | ||||
| 		{ | ||||
| 			long l; | ||||
| 			if(Get<long>(strName, out l)) return l; | ||||
| 			return lDefault; | ||||
| 		} | ||||
|  | ||||
| 		public void SetInt64(string strName, long lValue) | ||||
| 		{ | ||||
| 			SetStruct<long>(strName, lValue); | ||||
| 		} | ||||
|  | ||||
| 		public string GetString(string strName) | ||||
| 		{ | ||||
| 			string str; | ||||
| 			Get<string>(strName, out str); | ||||
| 			return str; | ||||
| 		} | ||||
|  | ||||
| 		public void SetString(string strName, string strValue) | ||||
| 		{ | ||||
| 			SetRef<string>(strName, strValue); | ||||
| 		} | ||||
|  | ||||
| 		public byte[] GetByteArray(string strName) | ||||
| 		{ | ||||
| 			byte[] pb; | ||||
| 			Get<byte[]>(strName, out pb); | ||||
| 			return pb; | ||||
| 		} | ||||
|  | ||||
| 		public void SetByteArray(string strName, byte[] pbValue) | ||||
| 		{ | ||||
| 			SetRef<byte[]>(strName, pbValue); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Create a deep copy. | ||||
| 		/// </summary> | ||||
| 		public virtual object Clone() | ||||
| 		{ | ||||
| 			VariantDictionary vdNew = new VariantDictionary(); | ||||
|  | ||||
| 			foreach(KeyValuePair<string, object> kvp in m_d) | ||||
| 			{ | ||||
| 				object o = kvp.Value; | ||||
| 				if(o == null) { Debug.Assert(false); continue; } | ||||
|  | ||||
| 				Type t = o.GetType(); | ||||
| 				if(t == typeof(byte[])) | ||||
| 				{ | ||||
| 					byte[] p = (byte[])o; | ||||
| 					byte[] pNew = new byte[p.Length]; | ||||
| 					if(p.Length > 0) Array.Copy(p, pNew, p.Length); | ||||
|  | ||||
| 					o = pNew; | ||||
| 				} | ||||
|  | ||||
| 				vdNew.m_d[kvp.Key] = o; | ||||
| 			} | ||||
|  | ||||
| 			return vdNew; | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] Serialize(VariantDictionary p) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			byte[] pbRet; | ||||
| 			using(MemoryStream ms = new MemoryStream()) | ||||
| 			{ | ||||
| 				MemUtil.Write(ms, MemUtil.UInt16ToBytes(VdVersion)); | ||||
|  | ||||
| 				foreach(KeyValuePair<string, object> kvp in p.m_d) | ||||
| 				{ | ||||
| 					string strName = kvp.Key; | ||||
| 					if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); continue; } | ||||
| 					byte[] pbName = StrUtil.Utf8.GetBytes(strName); | ||||
|  | ||||
| 					object o = kvp.Value; | ||||
| 					if(o == null) { Debug.Assert(false); continue; } | ||||
|  | ||||
| 					Type t = o.GetType(); | ||||
| 					VdType vt = VdType.None; | ||||
| 					byte[] pbValue = null; | ||||
| 					if(t == typeof(uint)) | ||||
| 					{ | ||||
| 						vt = VdType.UInt32; | ||||
| 						pbValue = MemUtil.UInt32ToBytes((uint)o); | ||||
| 					} | ||||
| 					else if(t == typeof(ulong)) | ||||
| 					{ | ||||
| 						vt = VdType.UInt64; | ||||
| 						pbValue = MemUtil.UInt64ToBytes((ulong)o); | ||||
| 					} | ||||
| 					else if(t == typeof(bool)) | ||||
| 					{ | ||||
| 						vt = VdType.Bool; | ||||
| 						pbValue = new byte[1]; | ||||
| 						pbValue[0] = ((bool)o ? (byte)1 : (byte)0); | ||||
| 					} | ||||
| 					else if(t == typeof(int)) | ||||
| 					{ | ||||
| 						vt = VdType.Int32; | ||||
| 						pbValue = MemUtil.Int32ToBytes((int)o); | ||||
| 					} | ||||
| 					else if(t == typeof(long)) | ||||
| 					{ | ||||
| 						vt = VdType.Int64; | ||||
| 						pbValue = MemUtil.Int64ToBytes((long)o); | ||||
| 					} | ||||
| 					else if(t == typeof(string)) | ||||
| 					{ | ||||
| 						vt = VdType.String; | ||||
| 						pbValue = StrUtil.Utf8.GetBytes((string)o); | ||||
| 					} | ||||
| 					else if(t == typeof(byte[])) | ||||
| 					{ | ||||
| 						vt = VdType.ByteArray; | ||||
| 						pbValue = (byte[])o; | ||||
| 					} | ||||
| 					else { Debug.Assert(false); continue; } // Unknown type | ||||
|  | ||||
| 					ms.WriteByte((byte)vt); | ||||
| 					MemUtil.Write(ms, MemUtil.Int32ToBytes(pbName.Length)); | ||||
| 					MemUtil.Write(ms, pbName); | ||||
| 					MemUtil.Write(ms, MemUtil.Int32ToBytes(pbValue.Length)); | ||||
| 					MemUtil.Write(ms, pbValue); | ||||
| 				} | ||||
|  | ||||
| 				ms.WriteByte((byte)VdType.None); | ||||
| 				pbRet = ms.ToArray(); | ||||
| 			} | ||||
|  | ||||
| 			return pbRet; | ||||
| 		} | ||||
|  | ||||
| 		public static VariantDictionary Deserialize(byte[] pb) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			VariantDictionary d = new VariantDictionary(); | ||||
| 			using(MemoryStream ms = new MemoryStream(pb, false)) | ||||
| 			{ | ||||
| 				ushort uVersion = MemUtil.BytesToUInt16(MemUtil.Read(ms, 2)); | ||||
| 				if((uVersion & VdmCritical) > (VdVersion & VdmCritical)) | ||||
| 					throw new FormatException(KLRes.FileNewVerReq); | ||||
|  | ||||
| 				while(true) | ||||
| 				{ | ||||
| 					int iType = ms.ReadByte(); | ||||
| 					if(iType < 0) throw new EndOfStreamException(KLRes.FileCorrupted); | ||||
| 					byte btType = (byte)iType; | ||||
| 					if(btType == (byte)VdType.None) break; | ||||
|  | ||||
| 					int cbName = MemUtil.BytesToInt32(MemUtil.Read(ms, 4)); | ||||
| 					byte[] pbName = MemUtil.Read(ms, cbName); | ||||
| 					if(pbName.Length != cbName) | ||||
| 						throw new EndOfStreamException(KLRes.FileCorrupted); | ||||
| 					string strName = StrUtil.Utf8.GetString(pbName); | ||||
|  | ||||
| 					int cbValue = MemUtil.BytesToInt32(MemUtil.Read(ms, 4)); | ||||
| 					byte[] pbValue = MemUtil.Read(ms, cbValue); | ||||
| 					if(pbValue.Length != cbValue) | ||||
| 						throw new EndOfStreamException(KLRes.FileCorrupted); | ||||
|  | ||||
| 					switch(btType) | ||||
| 					{ | ||||
| 						case (byte)VdType.UInt32: | ||||
| 							if(cbValue == 4) | ||||
| 								d.SetUInt32(strName, MemUtil.BytesToUInt32(pbValue)); | ||||
| 							else { Debug.Assert(false); } | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.UInt64: | ||||
| 							if(cbValue == 8) | ||||
| 								d.SetUInt64(strName, MemUtil.BytesToUInt64(pbValue)); | ||||
| 							else { Debug.Assert(false); } | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.Bool: | ||||
| 							if(cbValue == 1) | ||||
| 								d.SetBool(strName, (pbValue[0] != 0)); | ||||
| 							else { Debug.Assert(false); } | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.Int32: | ||||
| 							if(cbValue == 4) | ||||
| 								d.SetInt32(strName, MemUtil.BytesToInt32(pbValue)); | ||||
| 							else { Debug.Assert(false); } | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.Int64: | ||||
| 							if(cbValue == 8) | ||||
| 								d.SetInt64(strName, MemUtil.BytesToInt64(pbValue)); | ||||
| 							else { Debug.Assert(false); } | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.String: | ||||
| 							d.SetString(strName, StrUtil.Utf8.GetString(pbValue)); | ||||
| 							break; | ||||
|  | ||||
| 						case (byte)VdType.ByteArray: | ||||
| 							d.SetByteArray(strName, pbValue); | ||||
| 							break; | ||||
|  | ||||
| 						default: | ||||
| 							Debug.Assert(false); // Unknown type | ||||
| 							break; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				Debug.Assert(ms.ReadByte() < 0); | ||||
| 			} | ||||
|  | ||||
| 			return d; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										251
									
								
								src/KeePassLib2Android/Cryptography/Cipher/ChaCha20Cipher.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/KeePassLib2Android/Cryptography/Cipher/ChaCha20Cipher.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,251 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Cipher | ||||
| { | ||||
| 	/// <summary> | ||||
| 	/// Implementation of the ChaCha20 cipher with a 96-bit nonce, | ||||
| 	/// as specified in RFC 7539. | ||||
| 	/// https://tools.ietf.org/html/rfc7539 | ||||
| 	/// </summary> | ||||
| 	public sealed class ChaCha20Cipher : CtrBlockCipher | ||||
| 	{ | ||||
| 		private uint[] m_s = new uint[16]; // State | ||||
| 		private uint[] m_x = new uint[16]; // Working buffer | ||||
|  | ||||
| 		private bool m_bLargeCounter; // See constructor documentation | ||||
|  | ||||
| 		private static readonly uint[] g_sigma = new uint[4] { | ||||
| 			0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 | ||||
| 		}; | ||||
|  | ||||
| 		private const string StrNameRfc = "ChaCha20 (RFC 7539)"; | ||||
|  | ||||
| 		public override int BlockSize | ||||
| 		{ | ||||
| 			get { return 64; } | ||||
| 		} | ||||
|  | ||||
| 		public ChaCha20Cipher(byte[] pbKey32, byte[] pbIV12) : | ||||
| 			this(pbKey32, pbIV12, false) | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Constructor. | ||||
| 		/// </summary> | ||||
| 		/// <param name="pbKey32">Key (32 bytes).</param> | ||||
| 		/// <param name="pbIV12">Nonce (12 bytes).</param> | ||||
| 		/// <param name="bLargeCounter">If <c>false</c>, the RFC 7539 version | ||||
| 		/// of ChaCha20 is used. In this case, only 256 GB of data can be | ||||
| 		/// encrypted securely (because the block counter is a 32-bit variable); | ||||
| 		/// an attempt to encrypt more data throws an exception. | ||||
| 		/// If <paramref name="bLargeCounter" /> is <c>true</c>, the 32-bit | ||||
| 		/// counter overflows to another 32-bit variable (i.e. the counter | ||||
| 		/// effectively is a 64-bit variable), like in the original ChaCha20 | ||||
| 		/// specification by D. J. Bernstein (which has a 64-bit counter and a | ||||
| 		/// 64-bit nonce). To be compatible with this version, the 64-bit nonce | ||||
| 		/// must be stored in the last 8 bytes of <paramref name="pbIV12" /> | ||||
| 		/// and the first 4 bytes must be 0. | ||||
| 		/// If the IV was generated randomly, a 12-byte IV and a large counter | ||||
| 		/// can be used to securely encrypt more than 256 GB of data (but note | ||||
| 		/// this is incompatible with RFC 7539 and the original specification).</param> | ||||
| 		public ChaCha20Cipher(byte[] pbKey32, byte[] pbIV12, bool bLargeCounter) : | ||||
| 			base() | ||||
| 		{ | ||||
| 			if(pbKey32 == null) throw new ArgumentNullException("pbKey32"); | ||||
| 			if(pbKey32.Length != 32) throw new ArgumentOutOfRangeException("pbKey32"); | ||||
| 			if(pbIV12 == null) throw new ArgumentNullException("pbIV12"); | ||||
| 			if(pbIV12.Length != 12) throw new ArgumentOutOfRangeException("pbIV12"); | ||||
|  | ||||
| 			m_bLargeCounter = bLargeCounter; | ||||
|  | ||||
| 			// Key setup | ||||
| 			m_s[4] = MemUtil.BytesToUInt32(pbKey32, 0); | ||||
| 			m_s[5] = MemUtil.BytesToUInt32(pbKey32, 4); | ||||
| 			m_s[6] = MemUtil.BytesToUInt32(pbKey32, 8); | ||||
| 			m_s[7] = MemUtil.BytesToUInt32(pbKey32, 12); | ||||
| 			m_s[8] = MemUtil.BytesToUInt32(pbKey32, 16); | ||||
| 			m_s[9] = MemUtil.BytesToUInt32(pbKey32, 20); | ||||
| 			m_s[10] = MemUtil.BytesToUInt32(pbKey32, 24); | ||||
| 			m_s[11] = MemUtil.BytesToUInt32(pbKey32, 28); | ||||
| 			m_s[0] = g_sigma[0]; | ||||
| 			m_s[1] = g_sigma[1]; | ||||
| 			m_s[2] = g_sigma[2]; | ||||
| 			m_s[3] = g_sigma[3]; | ||||
|  | ||||
| 			// IV setup | ||||
| 			m_s[12] = 0; // Counter | ||||
| 			m_s[13] = MemUtil.BytesToUInt32(pbIV12, 0); | ||||
| 			m_s[14] = MemUtil.BytesToUInt32(pbIV12, 4); | ||||
| 			m_s[15] = MemUtil.BytesToUInt32(pbIV12, 8); | ||||
| 		} | ||||
|  | ||||
| 		protected override void Dispose(bool bDisposing) | ||||
| 		{ | ||||
| 			MemUtil.ZeroArray<uint>(m_s); | ||||
| 			MemUtil.ZeroArray<uint>(m_x); | ||||
|  | ||||
| 			base.Dispose(bDisposing); | ||||
| 		} | ||||
|  | ||||
| 		protected override void NextBlock(byte[] pBlock) | ||||
| 		{ | ||||
| 			if(pBlock == null) throw new ArgumentNullException("pBlock"); | ||||
| 			if(pBlock.Length != 64) throw new ArgumentOutOfRangeException("pBlock"); | ||||
|  | ||||
| 			// x is a local alias for the working buffer; with this, | ||||
| 			// the compiler/runtime might remove some checks | ||||
| 			uint[] x = m_x; | ||||
| 			if(x == null) throw new InvalidOperationException(); | ||||
| 			if(x.Length < 16) throw new InvalidOperationException(); | ||||
|  | ||||
| 			uint[] s = m_s; | ||||
| 			if(s == null) throw new InvalidOperationException(); | ||||
| 			if(s.Length < 16) throw new InvalidOperationException(); | ||||
|  | ||||
| 			Array.Copy(s, x, 16); | ||||
|  | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				// 10 * 8 quarter rounds = 20 rounds | ||||
| 				for(int i = 0; i < 10; ++i) | ||||
| 				{ | ||||
| 					// Column quarter rounds | ||||
| 					x[ 0] += x[ 4]; | ||||
| 					x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 0], 16); | ||||
| 					x[ 8] += x[12]; | ||||
| 					x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 8], 12); | ||||
| 					x[ 0] += x[ 4]; | ||||
| 					x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 0], 8); | ||||
| 					x[ 8] += x[12]; | ||||
| 					x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 8], 7); | ||||
|  | ||||
| 					x[ 1] += x[ 5]; | ||||
| 					x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 1], 16); | ||||
| 					x[ 9] += x[13]; | ||||
| 					x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[ 9], 12); | ||||
| 					x[ 1] += x[ 5]; | ||||
| 					x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 1], 8); | ||||
| 					x[ 9] += x[13]; | ||||
| 					x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[ 9], 7); | ||||
|  | ||||
| 					x[ 2] += x[ 6]; | ||||
| 					x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 2], 16); | ||||
| 					x[10] += x[14]; | ||||
| 					x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[10], 12); | ||||
| 					x[ 2] += x[ 6]; | ||||
| 					x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 2], 8); | ||||
| 					x[10] += x[14]; | ||||
| 					x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[10], 7); | ||||
|  | ||||
| 					x[ 3] += x[ 7]; | ||||
| 					x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 3], 16); | ||||
| 					x[11] += x[15]; | ||||
| 					x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[11], 12); | ||||
| 					x[ 3] += x[ 7]; | ||||
| 					x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 3], 8); | ||||
| 					x[11] += x[15]; | ||||
| 					x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[11], 7); | ||||
|  | ||||
| 					// Diagonal quarter rounds | ||||
| 					x[ 0] += x[ 5]; | ||||
| 					x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 0], 16); | ||||
| 					x[10] += x[15]; | ||||
| 					x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[10], 12); | ||||
| 					x[ 0] += x[ 5]; | ||||
| 					x[15] = MemUtil.RotateLeft32(x[15] ^ x[ 0],  8); | ||||
| 					x[10] += x[15]; | ||||
| 					x[ 5] = MemUtil.RotateLeft32(x[ 5] ^ x[10],  7); | ||||
|  | ||||
| 					x[ 1] += x[ 6]; | ||||
| 					x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 1], 16); | ||||
| 					x[11] += x[12]; | ||||
| 					x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[11], 12); | ||||
| 					x[ 1] += x[ 6]; | ||||
| 					x[12] = MemUtil.RotateLeft32(x[12] ^ x[ 1],  8); | ||||
| 					x[11] += x[12]; | ||||
| 					x[ 6] = MemUtil.RotateLeft32(x[ 6] ^ x[11],  7); | ||||
|  | ||||
| 					x[ 2] += x[ 7]; | ||||
| 					x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 2], 16); | ||||
| 					x[ 8] += x[13]; | ||||
| 					x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[ 8], 12); | ||||
| 					x[ 2] += x[ 7]; | ||||
| 					x[13] = MemUtil.RotateLeft32(x[13] ^ x[ 2],  8); | ||||
| 					x[ 8] += x[13]; | ||||
| 					x[ 7] = MemUtil.RotateLeft32(x[ 7] ^ x[ 8],  7); | ||||
|  | ||||
| 					x[ 3] += x[ 4]; | ||||
| 					x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 3], 16); | ||||
| 					x[ 9] += x[14]; | ||||
| 					x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 9], 12); | ||||
| 					x[ 3] += x[ 4]; | ||||
| 					x[14] = MemUtil.RotateLeft32(x[14] ^ x[ 3],  8); | ||||
| 					x[ 9] += x[14]; | ||||
| 					x[ 4] = MemUtil.RotateLeft32(x[ 4] ^ x[ 9],  7); | ||||
| 				} | ||||
|  | ||||
| 				for(int i = 0; i < 16; ++i) x[i] += s[i]; | ||||
|  | ||||
| 				for(int i = 0; i < 16; ++i) | ||||
| 				{ | ||||
| 					int i4 = i << 2; | ||||
| 					uint xi = x[i]; | ||||
|  | ||||
| 					pBlock[i4] = (byte)xi; | ||||
| 					pBlock[i4 + 1] = (byte)(xi >> 8); | ||||
| 					pBlock[i4 + 2] = (byte)(xi >> 16); | ||||
| 					pBlock[i4 + 3] = (byte)(xi >> 24); | ||||
| 				} | ||||
|  | ||||
| 				++s[12]; | ||||
| 				if(s[12] == 0) | ||||
| 				{ | ||||
| 					if(!m_bLargeCounter) | ||||
| 						throw new InvalidOperationException( | ||||
| 							KLRes.EncDataTooLarge.Replace(@"{PARAM}", StrNameRfc)); | ||||
| 					++s[13]; // Increment high half of large counter | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public long Seek(long lOffset, SeekOrigin so) | ||||
| 		{ | ||||
| 			if(so != SeekOrigin.Begin) throw new NotSupportedException(); | ||||
|  | ||||
| 			if((lOffset < 0) || ((lOffset & 63) != 0) || | ||||
| 				((lOffset >> 6) > (long)uint.MaxValue)) | ||||
| 				throw new ArgumentOutOfRangeException("lOffset"); | ||||
|  | ||||
| 			m_s[12] = (uint)(lOffset >> 6); | ||||
| 			InvalidateBlock(); | ||||
|  | ||||
| 			return lOffset; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										174
									
								
								src/KeePassLib2Android/Cryptography/Cipher/ChaCha20Engine.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								src/KeePassLib2Android/Cryptography/Cipher/ChaCha20Engine.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Cipher | ||||
| { | ||||
| 	public sealed class ChaCha20Engine : ICipherEngine2 | ||||
| 	{ | ||||
| 		private PwUuid m_uuid = new PwUuid(new byte[] { | ||||
| 			0xD6, 0x03, 0x8A, 0x2B, 0x8B, 0x6F, 0x4C, 0xB5, | ||||
| 			0xA5, 0x24, 0x33, 0x9A, 0x31, 0xDB, 0xB5, 0x9A | ||||
| 		}); | ||||
|  | ||||
| 		public PwUuid CipherUuid | ||||
| 		{ | ||||
| 			get { return m_uuid; } | ||||
| 		} | ||||
|  | ||||
| 		public string DisplayName | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				return ("ChaCha20 (" + KLRes.KeyBits.Replace(@"{PARAM}", | ||||
| 					"256") + ", RFC 7539)"); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public int KeyLength | ||||
| 		{ | ||||
| 			get { return 32; } | ||||
| 		} | ||||
|  | ||||
| 		public int IVLength | ||||
| 		{ | ||||
| 			get { return 12; } // 96 bits | ||||
| 		} | ||||
|  | ||||
| 		public Stream EncryptStream(Stream sPlainText, byte[] pbKey, byte[] pbIV) | ||||
| 		{ | ||||
| 			return new ChaCha20Stream(sPlainText, true, pbKey, pbIV); | ||||
| 		} | ||||
|  | ||||
| 		public Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV) | ||||
| 		{ | ||||
| 			return new ChaCha20Stream(sEncrypted, false, pbKey, pbIV); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	internal sealed class ChaCha20Stream : Stream | ||||
| 	{ | ||||
| 		private Stream m_sBase; | ||||
| 		private readonly bool m_bWriting; | ||||
| 		private ChaCha20Cipher m_c; | ||||
|  | ||||
| 		private byte[] m_pbBuffer = null; | ||||
|  | ||||
| 		public override bool CanRead | ||||
| 		{ | ||||
| 			get { return !m_bWriting; } | ||||
| 		} | ||||
|  | ||||
| 		public override bool CanSeek | ||||
| 		{ | ||||
| 			get { return false; } | ||||
| 		} | ||||
|  | ||||
| 		public override bool CanWrite | ||||
| 		{ | ||||
| 			get { return m_bWriting; } | ||||
| 		} | ||||
|  | ||||
| 		public override long Length | ||||
| 		{ | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public override long Position | ||||
| 		{ | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 			set { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public ChaCha20Stream(Stream sBase, bool bWriting, byte[] pbKey32, | ||||
| 			byte[] pbIV12) | ||||
| 		{ | ||||
| 			if(sBase == null) throw new ArgumentNullException("sBase"); | ||||
|  | ||||
| 			m_sBase = sBase; | ||||
| 			m_bWriting = bWriting; | ||||
| 			m_c = new ChaCha20Cipher(pbKey32, pbIV12); | ||||
| 		} | ||||
|  | ||||
| 		protected override void Dispose(bool bDisposing) | ||||
| 		{ | ||||
| 			if(!bDisposing) return; | ||||
|  | ||||
| 			if(m_sBase != null) | ||||
| 			{ | ||||
| 				m_c.Dispose(); | ||||
| 				m_c = null; | ||||
|  | ||||
| 				m_sBase.Close(); | ||||
| 				m_sBase = null; | ||||
| 			} | ||||
|  | ||||
| 			m_pbBuffer = null; | ||||
| 		} | ||||
|  | ||||
| 		public override void Flush() | ||||
| 		{ | ||||
| 			Debug.Assert(m_sBase != null); | ||||
| 			if(m_bWriting && (m_sBase != null)) m_sBase.Flush(); | ||||
| 		} | ||||
|  | ||||
| 		public override long Seek(long lOffset, SeekOrigin soOrigin) | ||||
| 		{ | ||||
| 			Debug.Assert(false); | ||||
| 			throw new NotImplementedException(); | ||||
| 		} | ||||
|  | ||||
| 		public override void SetLength(long lValue) | ||||
| 		{ | ||||
| 			Debug.Assert(false); | ||||
| 			throw new NotImplementedException(); | ||||
| 		} | ||||
|  | ||||
| 		public override int Read(byte[] pbBuffer, int iOffset, int nCount) | ||||
| 		{ | ||||
| 			if(m_bWriting) throw new InvalidOperationException(); | ||||
|  | ||||
| 			int cbRead = m_sBase.Read(pbBuffer, iOffset, nCount); | ||||
| 			m_c.Decrypt(pbBuffer, iOffset, cbRead); | ||||
| 			return cbRead; | ||||
| 		} | ||||
|  | ||||
| 		public override void Write(byte[] pbBuffer, int iOffset, int nCount) | ||||
| 		{ | ||||
| 			if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); | ||||
| 			if(nCount == 0) return; | ||||
|  | ||||
| 			if(!m_bWriting) throw new InvalidOperationException(); | ||||
|  | ||||
| 			if((m_pbBuffer == null) || (m_pbBuffer.Length < nCount)) | ||||
| 				m_pbBuffer = new byte[nCount]; | ||||
| 			Array.Copy(pbBuffer, iOffset, m_pbBuffer, 0, nCount); | ||||
|  | ||||
| 			m_c.Encrypt(m_pbBuffer, 0, nCount); | ||||
| 			m_sBase.Write(m_pbBuffer, 0, nCount); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -22,7 +22,6 @@ using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.Security; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Cipher | ||||
| { | ||||
| @@ -41,12 +40,17 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_poolGlobal != null) return m_poolGlobal; | ||||
| 				CipherPool cp = m_poolGlobal; | ||||
| 				if(cp == null) | ||||
| 				{ | ||||
| 					cp = new CipherPool(); | ||||
| 					cp.AddCipher(new StandardAesEngine()); | ||||
| 					cp.AddCipher(new ChaCha20Engine()); | ||||
|  | ||||
| 				m_poolGlobal = new CipherPool(); | ||||
| 				m_poolGlobal.AddCipher(new StandardAesEngine()); | ||||
| 					m_poolGlobal = cp; | ||||
| 				} | ||||
|  | ||||
| 				return m_poolGlobal; | ||||
| 				return cp; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										101
									
								
								src/KeePassLib2Android/Cryptography/Cipher/CtrBlockCipher.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/KeePassLib2Android/Cryptography/Cipher/CtrBlockCipher.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Cipher | ||||
| { | ||||
| 	public abstract class CtrBlockCipher : IDisposable | ||||
| 	{ | ||||
| 		private byte[] m_pBlock; | ||||
| 		private int m_iBlockPos; | ||||
|  | ||||
| 		public abstract int BlockSize | ||||
| 		{ | ||||
| 			get; | ||||
| 		} | ||||
|  | ||||
| 		public CtrBlockCipher() | ||||
| 		{ | ||||
| 			int cb = this.BlockSize; | ||||
| 			if(cb <= 0) throw new InvalidOperationException("this.BlockSize"); | ||||
|  | ||||
| 			m_pBlock = new byte[cb]; | ||||
| 			m_iBlockPos = cb; | ||||
| 		} | ||||
|  | ||||
| 		public void Dispose() | ||||
| 		{ | ||||
| 			Dispose(true); | ||||
| 			GC.SuppressFinalize(this); | ||||
| 		} | ||||
|  | ||||
| 		protected virtual void Dispose(bool bDisposing) | ||||
| 		{ | ||||
| 			MemUtil.ZeroByteArray(m_pBlock); | ||||
| 			m_iBlockPos = m_pBlock.Length; | ||||
| 		} | ||||
|  | ||||
| 		protected void InvalidateBlock() | ||||
| 		{ | ||||
| 			m_iBlockPos = m_pBlock.Length; | ||||
| 		} | ||||
|  | ||||
| 		protected abstract void NextBlock(byte[] pBlock); | ||||
|  | ||||
| 		public void Encrypt(byte[] m, int iOffset, int cb) | ||||
| 		{ | ||||
| 			if(m == null) throw new ArgumentNullException("m"); | ||||
| 			if(iOffset < 0) throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			if(cb < 0) throw new ArgumentOutOfRangeException("cb"); | ||||
| 			if(iOffset > (m.Length - cb)) throw new ArgumentOutOfRangeException("cb"); | ||||
|  | ||||
| 			int cbBlock = m_pBlock.Length; | ||||
|  | ||||
| 			while(cb > 0) | ||||
| 			{ | ||||
| 				Debug.Assert(m_iBlockPos <= cbBlock); | ||||
| 				if(m_iBlockPos == cbBlock) | ||||
| 				{ | ||||
| 					NextBlock(m_pBlock); | ||||
| 					m_iBlockPos = 0; | ||||
| 				} | ||||
|  | ||||
| 				int cbCopy = Math.Min(cbBlock - m_iBlockPos, cb); | ||||
| 				Debug.Assert(cbCopy > 0); | ||||
|  | ||||
| 				MemUtil.XorArray(m_pBlock, m_iBlockPos, m, iOffset, cbCopy); | ||||
|  | ||||
| 				m_iBlockPos += cbCopy; | ||||
| 				iOffset += cbCopy; | ||||
| 				cb -= cbCopy; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public void Decrypt(byte[] m, int iOffset, int cb) | ||||
| 		{ | ||||
| 			Encrypt(m, iOffset, cb); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -63,4 +63,25 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 		/// <returns>Stream, from which the decrypted data can be read.</returns> | ||||
| 		Stream DecryptStream(Stream sEncrypted, byte[] pbKey, byte[] pbIV); | ||||
| 	} | ||||
|  | ||||
| 	public interface ICipherEngine2 : ICipherEngine | ||||
| 	{ | ||||
| 		/// <summary> | ||||
| 		/// Length of an encryption key in bytes. | ||||
| 		/// The base <c>ICipherEngine</c> assumes 32. | ||||
| 		/// </summary> | ||||
| 		int KeyLength | ||||
| 		{ | ||||
| 			get; | ||||
| } | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Length of the initialization vector in bytes. | ||||
| 		/// The base <c>ICipherEngine</c> assumes 16. | ||||
| 		/// </summary> | ||||
| 		int IVLength | ||||
| 		{ | ||||
| 			get; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,169 +19,143 @@ | ||||
|  | ||||
| // Implementation of the Salsa20 cipher, based on the eSTREAM submission. | ||||
|  | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Cipher | ||||
| { | ||||
| 	public sealed class Salsa20Cipher | ||||
| 	public sealed class Salsa20Cipher : CtrBlockCipher | ||||
| 	{ | ||||
| 		private uint[] m_state = new uint[16]; | ||||
| 		private uint[] m_s = new uint[16]; // State | ||||
| 		private uint[] m_x = new uint[16]; // Working buffer | ||||
|  | ||||
| 		private byte[] m_output = new byte[64]; | ||||
| 		private int m_outputPos = 64; | ||||
|  | ||||
| 		private static readonly uint[] m_sigma = new uint[4]{ | ||||
| 		private static readonly uint[] g_sigma = new uint[4] { | ||||
| 			0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 | ||||
| 		}; | ||||
|  | ||||
| 		public Salsa20Cipher(byte[] pbKey32, byte[] pbIV8) | ||||
| 		public override int BlockSize | ||||
| 		{ | ||||
| 			KeySetup(pbKey32); | ||||
| 			IvSetup(pbIV8); | ||||
| 			get { return 64; } | ||||
| 		} | ||||
|  | ||||
| 		~Salsa20Cipher() | ||||
| 		public Salsa20Cipher(byte[] pbKey32, byte[] pbIV8) : base() | ||||
| 		{ | ||||
| 			if(pbKey32 == null) throw new ArgumentNullException("pbKey32"); | ||||
| 			if(pbKey32.Length != 32) throw new ArgumentOutOfRangeException("pbKey32"); | ||||
| 			if(pbIV8 == null) throw new ArgumentNullException("pbIV8"); | ||||
| 			if(pbIV8.Length != 8) throw new ArgumentOutOfRangeException("pbIV8"); | ||||
| 			// Clear sensitive data | ||||
| 			Array.Clear(m_state, 0, m_state.Length); | ||||
| 			Array.Clear(m_x, 0, m_x.Length); | ||||
| 			// Key setup | ||||
| 			m_s[1] = MemUtil.BytesToUInt32(pbKey32, 0); | ||||
| 			m_s[2] = MemUtil.BytesToUInt32(pbKey32, 4); | ||||
| 			m_s[3] = MemUtil.BytesToUInt32(pbKey32, 8); | ||||
| 			m_s[4] = MemUtil.BytesToUInt32(pbKey32, 12); | ||||
| 			m_s[11] = MemUtil.BytesToUInt32(pbKey32, 16); | ||||
| 			m_s[12] = MemUtil.BytesToUInt32(pbKey32, 20); | ||||
| 			m_s[13] = MemUtil.BytesToUInt32(pbKey32, 24); | ||||
| 			m_s[14] = MemUtil.BytesToUInt32(pbKey32, 28); | ||||
| 			m_s[0] = g_sigma[0]; | ||||
| 			m_s[5] = g_sigma[1]; | ||||
| 			m_s[10] = g_sigma[2]; | ||||
| 			m_s[15] = g_sigma[3]; | ||||
|  | ||||
| 			// IV setup | ||||
| 			m_s[6] = MemUtil.BytesToUInt32(pbIV8, 0); | ||||
| 			m_s[7] = MemUtil.BytesToUInt32(pbIV8, 4); | ||||
| 			m_s[8] = 0; // Counter, low | ||||
| 			m_s[9] = 0; // Counter, high | ||||
| 		} | ||||
|  | ||||
| 		private void NextOutput() | ||||
| 		protected override void Dispose(bool bDisposing) | ||||
| 		{ | ||||
| 			uint[] x = m_x; // Local alias for working buffer | ||||
| 			MemUtil.ZeroArray<uint>(m_s); | ||||
| 			MemUtil.ZeroArray<uint>(m_x); | ||||
|  | ||||
| 			base.Dispose(bDisposing); | ||||
| 		} | ||||
| 			// Compiler/runtime might remove array bound checks after this | ||||
| 		protected override void NextBlock(byte[] pBlock) | ||||
| 		{ | ||||
| 			if(pBlock == null) throw new ArgumentNullException("pBlock"); | ||||
| 			if(pBlock.Length != 64) throw new ArgumentOutOfRangeException("pBlock"); | ||||
|  | ||||
| 			// x is a local alias for the working buffer; with this, | ||||
| 			// the compiler/runtime might remove some checks | ||||
| 			uint[] x = m_x; | ||||
| 			if(x == null) throw new InvalidOperationException(); | ||||
| 			if(x.Length < 16) throw new InvalidOperationException(); | ||||
|  | ||||
| 			Array.Copy(m_state, x, 16); | ||||
| 			uint[] s = m_s; | ||||
| 			if(s == null) throw new InvalidOperationException(); | ||||
| 			if(s.Length < 16) throw new InvalidOperationException(); | ||||
|  | ||||
| 			Array.Copy(s, x, 16); | ||||
|  | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				// 10 * 8 quarter rounds = 20 rounds | ||||
| 				for(int i = 0; i < 10; ++i) // (int i = 20; i > 0; i -= 2) | ||||
| 				{ | ||||
| 					x[ 4] ^= Rotl32(x[ 0] + x[12],  7); | ||||
| 					x[ 8] ^= Rotl32(x[ 4] + x[ 0],  9); | ||||
| 					x[12] ^= Rotl32(x[ 8] + x[ 4], 13); | ||||
| 					x[ 0] ^= Rotl32(x[12] + x[ 8], 18); | ||||
| 					x[ 9] ^= Rotl32(x[ 5] + x[ 1],  7); | ||||
| 					x[13] ^= Rotl32(x[ 9] + x[ 5],  9); | ||||
| 					x[ 1] ^= Rotl32(x[13] + x[ 9], 13); | ||||
| 					x[ 5] ^= Rotl32(x[ 1] + x[13], 18); | ||||
| 					x[14] ^= Rotl32(x[10] + x[ 6],  7); | ||||
| 					x[ 2] ^= Rotl32(x[14] + x[10],  9); | ||||
| 					x[ 6] ^= Rotl32(x[ 2] + x[14], 13); | ||||
| 					x[10] ^= Rotl32(x[ 6] + x[ 2], 18); | ||||
| 					x[ 3] ^= Rotl32(x[15] + x[11],  7); | ||||
| 					x[ 7] ^= Rotl32(x[ 3] + x[15],  9); | ||||
| 					x[11] ^= Rotl32(x[ 7] + x[ 3], 13); | ||||
| 					x[15] ^= Rotl32(x[11] + x[ 7], 18); | ||||
| 					x[ 1] ^= Rotl32(x[ 0] + x[ 3],  7); | ||||
| 					x[ 2] ^= Rotl32(x[ 1] + x[ 0],  9); | ||||
| 					x[ 3] ^= Rotl32(x[ 2] + x[ 1], 13); | ||||
| 					x[ 0] ^= Rotl32(x[ 3] + x[ 2], 18); | ||||
| 					x[ 6] ^= Rotl32(x[ 5] + x[ 4],  7); | ||||
| 					x[ 7] ^= Rotl32(x[ 6] + x[ 5],  9); | ||||
| 					x[ 4] ^= Rotl32(x[ 7] + x[ 6], 13); | ||||
| 					x[ 5] ^= Rotl32(x[ 4] + x[ 7], 18); | ||||
| 					x[11] ^= Rotl32(x[10] + x[ 9],  7); | ||||
| 					x[ 8] ^= Rotl32(x[11] + x[10],  9); | ||||
| 					x[ 9] ^= Rotl32(x[ 8] + x[11], 13); | ||||
| 					x[10] ^= Rotl32(x[ 9] + x[ 8], 18); | ||||
| 					x[12] ^= Rotl32(x[15] + x[14],  7); | ||||
| 					x[13] ^= Rotl32(x[12] + x[15],  9); | ||||
| 					x[14] ^= Rotl32(x[13] + x[12], 13); | ||||
| 					x[15] ^= Rotl32(x[14] + x[13], 18); | ||||
| 				} | ||||
| 					x[ 4] ^= MemUtil.RotateLeft32(x[ 0] + x[12],  7); | ||||
| 					x[ 8] ^= MemUtil.RotateLeft32(x[ 4] + x[ 0],  9); | ||||
| 					x[12] ^= MemUtil.RotateLeft32(x[ 8] + x[ 4], 13); | ||||
| 					x[ 0] ^= MemUtil.RotateLeft32(x[12] + x[ 8], 18); | ||||
|  | ||||
| 					x[ 9] ^= MemUtil.RotateLeft32(x[ 5] + x[ 1],  7); | ||||
| 					x[13] ^= MemUtil.RotateLeft32(x[ 9] + x[ 5],  9); | ||||
| 					x[ 1] ^= MemUtil.RotateLeft32(x[13] + x[ 9], 13); | ||||
| 					x[ 5] ^= MemUtil.RotateLeft32(x[ 1] + x[13], 18); | ||||
|  | ||||
| 					x[14] ^= MemUtil.RotateLeft32(x[10] + x[ 6],  7); | ||||
| 					x[ 2] ^= MemUtil.RotateLeft32(x[14] + x[10],  9); | ||||
| 					x[ 6] ^= MemUtil.RotateLeft32(x[ 2] + x[14], 13); | ||||
| 					x[10] ^= MemUtil.RotateLeft32(x[ 6] + x[ 2], 18); | ||||
|  | ||||
| 					x[ 3] ^= MemUtil.RotateLeft32(x[15] + x[11],  7); | ||||
| 					x[ 7] ^= MemUtil.RotateLeft32(x[ 3] + x[15],  9); | ||||
| 					x[11] ^= MemUtil.RotateLeft32(x[ 7] + x[ 3], 13); | ||||
| 					x[15] ^= MemUtil.RotateLeft32(x[11] + x[ 7], 18); | ||||
|  | ||||
| 					x[ 1] ^= MemUtil.RotateLeft32(x[ 0] + x[ 3],  7); | ||||
| 					x[ 2] ^= MemUtil.RotateLeft32(x[ 1] + x[ 0],  9); | ||||
| 					x[ 3] ^= MemUtil.RotateLeft32(x[ 2] + x[ 1], 13); | ||||
| 					x[ 0] ^= MemUtil.RotateLeft32(x[ 3] + x[ 2], 18); | ||||
|  | ||||
| 					x[ 6] ^= MemUtil.RotateLeft32(x[ 5] + x[ 4],  7); | ||||
| 					x[ 7] ^= MemUtil.RotateLeft32(x[ 6] + x[ 5],  9); | ||||
| 					x[ 4] ^= MemUtil.RotateLeft32(x[ 7] + x[ 6], 13); | ||||
| 					x[ 5] ^= MemUtil.RotateLeft32(x[ 4] + x[ 7], 18); | ||||
|  | ||||
| 					x[11] ^= MemUtil.RotateLeft32(x[10] + x[ 9],  7); | ||||
| 					x[ 8] ^= MemUtil.RotateLeft32(x[11] + x[10],  9); | ||||
| 					x[ 9] ^= MemUtil.RotateLeft32(x[ 8] + x[11], 13); | ||||
| 					x[10] ^= MemUtil.RotateLeft32(x[ 9] + x[ 8], 18); | ||||
|  | ||||
| 					x[12] ^= MemUtil.RotateLeft32(x[15] + x[14],  7); | ||||
| 					x[13] ^= MemUtil.RotateLeft32(x[12] + x[15],  9); | ||||
| 					x[14] ^= MemUtil.RotateLeft32(x[13] + x[12], 13); | ||||
| 					x[15] ^= MemUtil.RotateLeft32(x[14] + x[13], 18); | ||||
| 		} | ||||
|  | ||||
| 				for(int i = 0; i < 16; ++i) x[i] += s[i]; | ||||
|  | ||||
| 				for(int i = 0; i < 16; ++i) | ||||
| 					x[i] += m_state[i]; | ||||
| 		{ | ||||
| 					int i4 = i << 2; | ||||
| 					uint xi = x[i]; | ||||
|  | ||||
| 				for(int i = 0; i < 16; ++i) | ||||
| 				{ | ||||
| 					m_output[i << 2] = (byte)x[i]; | ||||
| 					m_output[(i << 2) + 1] = (byte)(x[i] >> 8); | ||||
| 					m_output[(i << 2) + 2] = (byte)(x[i] >> 16); | ||||
| 					m_output[(i << 2) + 3] = (byte)(x[i] >> 24); | ||||
| 				} | ||||
|  | ||||
| 				m_outputPos = 0; | ||||
| 				++m_state[8]; | ||||
| 				if(m_state[8] == 0) ++m_state[9]; | ||||
| 			} | ||||
| 					pBlock[i4] = (byte)xi; | ||||
| 					pBlock[i4 + 1] = (byte)(xi >> 8); | ||||
| 					pBlock[i4 + 2] = (byte)(xi >> 16); | ||||
| 					pBlock[i4 + 3] = (byte)(xi >> 24); | ||||
| 		} | ||||
|  | ||||
| 		private static uint Rotl32(uint x, int b) | ||||
| 		{ | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				return ((x << b) | (x >> (32 - b))); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static uint U8To32Little(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) | | ||||
| 					((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24)); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private void KeySetup(byte[] k) | ||||
| 		{ | ||||
| 			if(k == null) throw new ArgumentNullException("k"); | ||||
| 			if(k.Length != 32) throw new ArgumentException(); | ||||
|  | ||||
| 			m_state[1] = U8To32Little(k, 0); | ||||
| 			m_state[2] = U8To32Little(k, 4); | ||||
| 			m_state[3] = U8To32Little(k, 8); | ||||
| 			m_state[4] = U8To32Little(k, 12); | ||||
| 			m_state[11] = U8To32Little(k, 16); | ||||
| 			m_state[12] = U8To32Little(k, 20); | ||||
| 			m_state[13] = U8To32Little(k, 24); | ||||
| 			m_state[14] = U8To32Little(k, 28); | ||||
| 			m_state[0] = m_sigma[0]; | ||||
| 			m_state[5] = m_sigma[1]; | ||||
| 			m_state[10] = m_sigma[2]; | ||||
| 			m_state[15] = m_sigma[3]; | ||||
| 		} | ||||
|  | ||||
| 		private void IvSetup(byte[] pbIV) | ||||
| 		{ | ||||
| 			if(pbIV == null) throw new ArgumentNullException("pbIV"); | ||||
| 			if(pbIV.Length != 8) throw new ArgumentException(); | ||||
|  | ||||
| 			m_state[6] = U8To32Little(pbIV, 0); | ||||
| 			m_state[7] = U8To32Little(pbIV, 4); | ||||
| 			m_state[8] = 0; | ||||
| 			m_state[9] = 0; | ||||
| 		} | ||||
|  | ||||
| 		public void Encrypt(byte[] m, int nByteCount, bool bXor) | ||||
| 		{ | ||||
| 			if(m == null) throw new ArgumentNullException("m"); | ||||
| 			if(nByteCount > m.Length) throw new ArgumentException(); | ||||
|  | ||||
| 			int nBytesRem = nByteCount, nOffset = 0; | ||||
| 			while(nBytesRem > 0) | ||||
| 			{ | ||||
| 				Debug.Assert((m_outputPos >= 0) && (m_outputPos <= 64)); | ||||
| 				if(m_outputPos == 64) NextOutput(); | ||||
| 				Debug.Assert(m_outputPos < 64); | ||||
|  | ||||
| 				int nCopy = Math.Min(64 - m_outputPos, nBytesRem); | ||||
|  | ||||
| 				if(bXor) MemUtil.XorArray(m_output, m_outputPos, m, nOffset, nCopy); | ||||
| 				else Array.Copy(m_output, m_outputPos, m, nOffset, nCopy); | ||||
|  | ||||
| 				m_outputPos += nCopy; | ||||
| 				nBytesRem -= nCopy; | ||||
| 				nOffset += nCopy; | ||||
| 				++s[8]; | ||||
| 				if(s[8] == 0) ++s[9]; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -24,15 +24,8 @@ using System.IO; | ||||
| using System.Security; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| #if !KeePassRT | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #else | ||||
| using Org.BouncyCastle.Crypto; | ||||
| using Org.BouncyCastle.Crypto.Engines; | ||||
| using Org.BouncyCastle.Crypto.IO; | ||||
| using Org.BouncyCastle.Crypto.Modes; | ||||
| using Org.BouncyCastle.Crypto.Paddings; | ||||
| using Org.BouncyCastle.Crypto.Parameters; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
| @@ -44,12 +37,12 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 	/// </summary> | ||||
| 	public sealed class StandardAesEngine : ICipherEngine | ||||
| 	{ | ||||
| #if !KeePassRT | ||||
| #if !KeePassUAP | ||||
| 		private const CipherMode m_rCipherMode = CipherMode.CBC; | ||||
| 		private const PaddingMode m_rCipherPadding = PaddingMode.PKCS7; | ||||
| #endif | ||||
|  | ||||
| 		private static PwUuid m_uuidAes = null; | ||||
| 		private static PwUuid g_uuidAes = null; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// UUID of the cipher engine. This ID uniquely identifies the | ||||
| @@ -59,14 +52,16 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_uuidAes == null) | ||||
| 				PwUuid pu = g_uuidAes; | ||||
| 				if(pu == null) | ||||
| 				{ | ||||
| 					m_uuidAes = new PwUuid(new byte[]{ | ||||
| 					pu = new PwUuid(new byte[] { | ||||
| 						0x31, 0xC1, 0xF2, 0xE6, 0xBF, 0x71, 0x43, 0x50, | ||||
| 						0xBE, 0x58, 0x05, 0x21, 0x6A, 0xFC, 0x5A, 0xFF }); | ||||
| 					g_uuidAes = pu; | ||||
| 				} | ||||
|  | ||||
| 				return m_uuidAes; | ||||
| 				return pu; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -81,7 +76,14 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 		/// <summary> | ||||
| 		/// Get a displayable name describing this cipher engine. | ||||
| 		/// </summary> | ||||
| 		public string DisplayName { get { return KLRes.EncAlgorithmAes; } } | ||||
| 		public string DisplayName | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				return ("AES/Rijndael (" + KLRes.KeyBits.Replace(@"{PARAM}", | ||||
| 					"256") + ", FIPS 197)"); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static void ValidateArguments(Stream stream, bool bEncrypt, byte[] pbKey, byte[] pbIV) | ||||
| 		{ | ||||
| @@ -98,12 +100,12 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 			if(bEncrypt) | ||||
| 			{ | ||||
| 				Debug.Assert(stream.CanWrite); | ||||
| 				if(stream.CanWrite == false) throw new ArgumentException("Stream must be writable!"); | ||||
| 				if(!stream.CanWrite) throw new ArgumentException("Stream must be writable!"); | ||||
| 			} | ||||
| 			else // Decrypt | ||||
| 			{ | ||||
| 				Debug.Assert(stream.CanRead); | ||||
| 				if(stream.CanRead == false) throw new ArgumentException("Encrypted stream must be readable!"); | ||||
| 				if(!stream.CanRead) throw new ArgumentException("Encrypted stream must be readable!"); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -117,7 +119,9 @@ namespace KeePassLib.Cryptography.Cipher | ||||
| 			byte[] pbLocalKey = new byte[32]; | ||||
| 			Array.Copy(pbKey, pbLocalKey, 32); | ||||
|  | ||||
| #if !KeePassRT | ||||
| #if KeePassUAP | ||||
| 			return StandardAesEngineExt.CreateStream(s, bEncrypt, pbLocalKey, pbLocalIV); | ||||
| #else | ||||
| 			RijndaelManaged r = new RijndaelManaged(); | ||||
| 			if(r.BlockSize != 128) // AES block size | ||||
| 			{ | ||||
| @@ -137,18 +141,6 @@ namespace KeePassLib.Cryptography.Cipher | ||||
|  | ||||
| 			return new CryptoStream(s, iTransform, bEncrypt ? CryptoStreamMode.Write : | ||||
| 				CryptoStreamMode.Read); | ||||
| #else | ||||
| 			AesEngine aes = new AesEngine(); | ||||
| 			CbcBlockCipher cbc = new CbcBlockCipher(aes); | ||||
| 			PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(cbc, | ||||
| 				new Pkcs7Padding()); | ||||
| 			KeyParameter kp = new KeyParameter(pbLocalKey); | ||||
| 			ParametersWithIV prmIV = new ParametersWithIV(kp, pbLocalIV); | ||||
| 			bc.Init(bEncrypt, prmIV); | ||||
|  | ||||
| 			IBufferedCipher cpRead = (bEncrypt ? null : bc); | ||||
| 			IBufferedCipher cpWrite = (bEncrypt ? bc : null); | ||||
| 			return new CipherStream(s, cpRead, cpWrite); | ||||
| #endif | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|  | ||||
| @@ -20,11 +20,13 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Drawing; | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Utility; | ||||
| @@ -39,21 +41,30 @@ namespace KeePassLib.Cryptography | ||||
| 	public sealed class CryptoRandom | ||||
| 	{ | ||||
| 		private byte[] m_pbEntropyPool = new byte[64]; | ||||
| 		private uint m_uCounter; | ||||
| 		private ulong m_uCounter; | ||||
| 		private RNGCryptoServiceProvider m_rng = new RNGCryptoServiceProvider(); | ||||
| 		private ulong m_uGeneratedBytesCount = 0; | ||||
|  | ||||
| 		private static object g_oSyncRoot = new object(); | ||||
| 		private object m_oSyncRoot = new object(); | ||||
|  | ||||
| 		private static CryptoRandom m_pInstance = null; | ||||
| 		private static CryptoRandom g_pInstance = null; | ||||
| 		public static CryptoRandom Instance | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_pInstance != null) return m_pInstance; | ||||
| 				CryptoRandom cr; | ||||
| 				lock(g_oSyncRoot) | ||||
| 				{ | ||||
| 					cr = g_pInstance; | ||||
| 					if(cr == null) | ||||
| 					{ | ||||
| 						cr = new CryptoRandom(); | ||||
| 						g_pInstance = cr; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				m_pInstance = new CryptoRandom(); | ||||
| 				return m_pInstance; | ||||
| 				return cr; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -80,10 +91,12 @@ namespace KeePassLib.Cryptography | ||||
|  | ||||
| 		private CryptoRandom() | ||||
| 		{ | ||||
| 			Random r = new Random(); | ||||
| 			m_uCounter = (uint)r.Next(); | ||||
| 			Random rWeak = new Random(); | ||||
| 			byte[] pb = new byte[8]; | ||||
| 			rWeak.NextBytes(pb); | ||||
| 			m_uCounter = MemUtil.BytesToUInt64(pb); | ||||
|  | ||||
| 			AddEntropy(GetSystemData(r)); | ||||
| 			AddEntropy(GetSystemData(rWeak)); | ||||
| 			AddEntropy(GetCspData()); | ||||
| 		} | ||||
|  | ||||
| @@ -99,32 +112,40 @@ namespace KeePassLib.Cryptography | ||||
| 			if(pbEntropy.Length == 0) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			byte[] pbNewData = pbEntropy; | ||||
| 			if(pbEntropy.Length >= 64) | ||||
| 			if(pbEntropy.Length > 64) | ||||
| 			{ | ||||
| #if !KeePassLibSD | ||||
| 				SHA512Managed shaNew = new SHA512Managed(); | ||||
| #if KeePassLibSD | ||||
| 				using(SHA256Managed shaNew = new SHA256Managed()) | ||||
| #else | ||||
| 				SHA256Managed shaNew = new SHA256Managed(); | ||||
| 				using(SHA512Managed shaNew = new SHA512Managed()) | ||||
| #endif | ||||
| 				{ | ||||
| 				pbNewData = shaNew.ComputeHash(pbEntropy); | ||||
| 			} | ||||
| 			} | ||||
|  | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
| 			lock(m_oSyncRoot) | ||||
| 			{ | ||||
| 				ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length); | ||||
| 				ms.Write(pbNewData, 0, pbNewData.Length); | ||||
| 				int cbPool = m_pbEntropyPool.Length; | ||||
| 				int cbNew = pbNewData.Length; | ||||
|  | ||||
| 				byte[] pbFinal = ms.ToArray(); | ||||
| #if !KeePassLibSD | ||||
| 				Debug.Assert(pbFinal.Length == (64 + pbNewData.Length)); | ||||
| 				SHA512Managed shaPool = new SHA512Managed(); | ||||
| 				byte[] pbCmp = new byte[cbPool + cbNew]; | ||||
| 				Array.Copy(m_pbEntropyPool, pbCmp, cbPool); | ||||
| 				Array.Copy(pbNewData, 0, pbCmp, cbPool, cbNew); | ||||
|  | ||||
| 				MemUtil.ZeroByteArray(m_pbEntropyPool); | ||||
|  | ||||
| #if KeePassLibSD | ||||
| 				using(SHA256Managed shaPool = new SHA256Managed()) | ||||
| #else | ||||
| 				SHA256Managed shaPool = new SHA256Managed(); | ||||
| 				using(SHA512Managed shaPool = new SHA512Managed()) | ||||
| #endif | ||||
| 				m_pbEntropyPool = shaPool.ComputeHash(pbFinal); | ||||
| 				{ | ||||
| 					m_pbEntropyPool = shaPool.ComputeHash(pbCmp); | ||||
| 			} | ||||
| 			ms.Close(); | ||||
|  | ||||
| 				MemUtil.ZeroByteArray(pbCmp); | ||||
| 		} | ||||
| 		} | ||||
|  | ||||
| 		private static byte[] GetSystemData(Random rWeak) | ||||
| @@ -132,71 +153,104 @@ namespace KeePassLib.Cryptography | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
| 			byte[] pb; | ||||
|  | ||||
| 			pb = MemUtil.UInt32ToBytes((uint)Environment.TickCount); | ||||
| 			ms.Write(pb, 0, pb.Length); | ||||
| 			pb = MemUtil.Int32ToBytes(Environment.TickCount); | ||||
| 			MemUtil.Write(ms, pb); | ||||
|  | ||||
| 			pb = TimeUtil.PackTime(DateTime.Now); | ||||
| 			ms.Write(pb, 0, pb.Length); | ||||
| 			pb = MemUtil.Int64ToBytes(DateTime.UtcNow.ToBinary()); | ||||
| 			MemUtil.Write(ms, pb); | ||||
|  | ||||
|  | ||||
| 			pb = MemUtil.UInt32ToBytes((uint)rWeak.Next()); | ||||
| 			ms.Write(pb, 0, pb.Length); | ||||
|  | ||||
| 			pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); | ||||
| 			ms.Write(pb, 0, pb.Length); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if !KeePassLibSD | ||||
| 			/*Not supported on Android | ||||
| 			// In try-catch for systems without GUI; | ||||
| 			// https://sourceforge.net/p/keepass/discussion/329221/thread/20335b73/ | ||||
| 			try | ||||
| 			{ | ||||
| 				pb = MemUtil.UInt32ToBytes((uint)Environment.ProcessorCount); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)Environment.WorkingSet); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
|  | ||||
| 				Version v = Environment.OSVersion.Version; | ||||
| 				int nv = (v.Major << 28) + (v.MajorRevision << 24) + | ||||
| 					(v.Minor << 20) + (v.MinorRevision << 16) + | ||||
| 					(v.Revision << 12) + v.Build; | ||||
| 				pb = MemUtil.UInt32ToBytes((uint)nv); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
|  | ||||
| 				Process p = Process.GetCurrentProcess(); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.Handle.ToInt64()); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt32ToBytes((uint)p.HandleCount); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt32ToBytes((uint)p.Id); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.NonpagedSystemMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PagedMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PagedSystemMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PeakPagedMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PeakVirtualMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PeakWorkingSet64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.PrivateMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.StartTime.ToBinary()); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.VirtualMemorySize64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
| 				pb = MemUtil.UInt64ToBytes((ulong)p.WorkingSet64); | ||||
| 				ms.Write(pb, 0, pb.Length); | ||||
|  | ||||
| 				// Not supported in Mono 1.2.6: | ||||
| 				// pb = MemUtil.UInt32ToBytes((uint)p.SessionId); | ||||
| 				// ms.Write(pb, 0, pb.Length); | ||||
| 				Point pt = Cursor.Position; | ||||
| 				pb = MemUtil.Int32ToBytes(pt.X); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int32ToBytes(pt.Y); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 			} | ||||
| 			catch(Exception) { } | ||||
| 			 */ | ||||
| #endif | ||||
|  | ||||
| 			pb = MemUtil.Int32ToBytes(rWeak.Next()); | ||||
| 			MemUtil.Write(ms, pb); | ||||
|  | ||||
| 			pb = MemUtil.UInt32ToBytes((uint)NativeLib.GetPlatformID()); | ||||
| 			MemUtil.Write(ms, pb); | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				pb = MemUtil.Int32ToBytes(Environment.ProcessorCount); | ||||
| 				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 | ||||
| 				pb = MemUtil.Int64ToBytes(Environment.WorkingSet); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| #endif | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| #if KeePassUAP | ||||
| 			pb = DiagnosticsExt.GetProcessEntropy(); | ||||
| 			MemUtil.Write(ms, pb); | ||||
| #elif !KeePassLibSD | ||||
| 			Process p = null; | ||||
| 			try | ||||
| 			{ | ||||
| 				p = Process.GetCurrentProcess(); | ||||
| 				// Not supported in Mono 1.2.6: | ||||
| 				pb = MemUtil.Int64ToBytes(p.Handle.ToInt64()); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int32ToBytes(p.HandleCount); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int32ToBytes(p.Id); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.NonpagedSystemMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PagedMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PagedSystemMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PeakPagedMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PeakVirtualMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PeakWorkingSet64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.PrivateMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.StartTime.ToBinary()); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.VirtualMemorySize64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				pb = MemUtil.Int64ToBytes(p.WorkingSet64); | ||||
| 				MemUtil.Write(ms, pb); | ||||
| 				// pb = MemUtil.UInt32ToBytes((uint)p.SessionId); | ||||
| 				// ms.Write(pb, 0, pb.Length); | ||||
| 				// pb = MemUtil.UInt32ToBytes((uint)p.SessionId); | ||||
| 				// MemUtil.Write(ms, pb); | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(NativeLib.IsUnix()); } | ||||
| 			finally | ||||
| 			{ | ||||
| 				try { if(p != null) p.Dispose(); } | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			pb = Guid.NewGuid().ToByteArray(); | ||||
| 			ms.Write(pb, 0, pb.Length); | ||||
| 			MemUtil.Write(ms, pb); | ||||
|  | ||||
| 			byte[] pbAll = ms.ToArray(); | ||||
| 			ms.Close(); | ||||
| @@ -215,28 +269,31 @@ namespace KeePassLib.Cryptography | ||||
| 			if(this.GenerateRandom256Pre != null) | ||||
| 				this.GenerateRandom256Pre(this, EventArgs.Empty); | ||||
|  | ||||
| 			byte[] pbFinal; | ||||
| 			byte[] pbCmp; | ||||
| 			lock(m_oSyncRoot) | ||||
| 			{ | ||||
| 				unchecked { m_uCounter += 386047; } // Prime number | ||||
| 				byte[] pbCounter = MemUtil.UInt32ToBytes(m_uCounter); | ||||
| 				m_uCounter += 0x74D8B29E4D38E161UL; // Prime number | ||||
| 				byte[] pbCounter = MemUtil.UInt64ToBytes(m_uCounter); | ||||
|  | ||||
| 				byte[] pbCspRandom = GetCspData(); | ||||
|  | ||||
| 				MemoryStream ms = new MemoryStream(); | ||||
| 				ms.Write(m_pbEntropyPool, 0, m_pbEntropyPool.Length); | ||||
| 				ms.Write(pbCounter, 0, pbCounter.Length); | ||||
| 				ms.Write(pbCspRandom, 0, pbCspRandom.Length); | ||||
| 				pbFinal = ms.ToArray(); | ||||
| 				Debug.Assert(pbFinal.Length == (m_pbEntropyPool.Length + | ||||
| 					pbCounter.Length + pbCspRandom.Length)); | ||||
| 				ms.Close(); | ||||
| 				int cbPool = m_pbEntropyPool.Length; | ||||
| 				int cbCtr = pbCounter.Length; | ||||
| 				int cbCsp = pbCspRandom.Length; | ||||
|  | ||||
| 				pbCmp = new byte[cbPool + cbCtr + cbCsp]; | ||||
| 				Array.Copy(m_pbEntropyPool, pbCmp, cbPool); | ||||
| 				Array.Copy(pbCounter, 0, pbCmp, cbPool, cbCtr); | ||||
| 				Array.Copy(pbCspRandom, 0, pbCmp, cbPool + cbCtr, cbCsp); | ||||
|  | ||||
| 				MemUtil.ZeroByteArray(pbCspRandom); | ||||
|  | ||||
| 				m_uGeneratedBytesCount += 32; | ||||
| 			} | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			return sha256.ComputeHash(pbFinal); | ||||
| 			byte[] pbRet = CryptoUtil.HashSha256(pbCmp); | ||||
| 			MemUtil.ZeroByteArray(pbCmp); | ||||
| 			return pbRet; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -248,29 +305,32 @@ namespace KeePassLib.Cryptography | ||||
| 		/// random bytes.</returns> | ||||
| 		public byte[] GetRandomBytes(uint uRequestedBytes) | ||||
| 		{ | ||||
| 			if(uRequestedBytes == 0) return new byte[0]; // Allow zero-length array | ||||
| 			if(uRequestedBytes == 0) return MemUtil.EmptyByteArray; | ||||
| 			if(uRequestedBytes > (uint)int.MaxValue) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("uRequestedBytes"); | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbRes = new byte[uRequestedBytes]; | ||||
| 			long lPos = 0; | ||||
| 			int cbRem = (int)uRequestedBytes; | ||||
| 			byte[] pbRes = new byte[cbRem]; | ||||
| 			int iPos = 0; | ||||
|  | ||||
| 			while(uRequestedBytes != 0) | ||||
| 			while(cbRem != 0) | ||||
| 			{ | ||||
| 				byte[] pbRandom256 = GenerateRandom256(); | ||||
| 				Debug.Assert(pbRandom256.Length == 32); | ||||
|  | ||||
| 				long lCopy = (long)((uRequestedBytes < 32) ? uRequestedBytes : 32); | ||||
| 				int cbCopy = Math.Min(cbRem, 32); | ||||
| 				Array.Copy(pbRandom256, 0, pbRes, iPos, cbCopy); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 				Array.Copy(pbRandom256, 0, pbRes, lPos, lCopy); | ||||
| #else | ||||
| 				Array.Copy(pbRandom256, 0, pbRes, (int)lPos, (int)lCopy); | ||||
| #endif | ||||
| 				MemUtil.ZeroByteArray(pbRandom256); | ||||
|  | ||||
| 				lPos += lCopy; | ||||
| 				uRequestedBytes -= (uint)lCopy; | ||||
| 				iPos += cbCopy; | ||||
| 				cbRem -= cbCopy; | ||||
| 			} | ||||
|  | ||||
| 			Debug.Assert((int)lPos == pbRes.Length); | ||||
| 			Debug.Assert(iPos == pbRes.Length); | ||||
| 			return pbRes; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,9 +19,13 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Diagnostics; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography | ||||
| { | ||||
| @@ -38,6 +42,7 @@ namespace KeePassLib.Cryptography | ||||
| 		/// <summary> | ||||
| 		/// A variant of the ARCFour algorithm (RC4 incompatible). | ||||
| 		/// </summary> | ||||
| 		/// </summary> | ||||
| 		ArcFourVariant = 1, | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -45,7 +50,12 @@ namespace KeePassLib.Cryptography | ||||
| 		/// </summary> | ||||
| 		Salsa20 = 2, | ||||
|  | ||||
| 		Count = 3 | ||||
| 		/// <summary> | ||||
| 		/// ChaCha20 stream cipher algorithm. | ||||
| 		/// </summary> | ||||
| 		ChaCha20 = 3, | ||||
|  | ||||
| 		Count = 4 | ||||
| 	} | ||||
|  | ||||
| 	/// <summary> | ||||
| @@ -56,13 +66,14 @@ namespace KeePassLib.Cryptography | ||||
| 	/// </summary> | ||||
| 	public sealed class CryptoRandomStream | ||||
| 	{ | ||||
| 		private CrsAlgorithm m_crsAlgorithm; | ||||
| 		private readonly CrsAlgorithm m_crsAlgorithm; | ||||
|  | ||||
| 		private byte[] m_pbState = null; | ||||
| 		private byte m_i = 0; | ||||
| 		private byte m_j = 0; | ||||
|  | ||||
| 		private Salsa20Cipher m_salsa20 = null; | ||||
| 		private ChaCha20Cipher m_chacha20 = null; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Construct a new cryptographically secure random stream object. | ||||
| @@ -70,31 +81,53 @@ namespace KeePassLib.Cryptography | ||||
| 		/// <param name="genAlgorithm">Algorithm to use.</param> | ||||
| 		/// <param name="pbKey">Initialization key. Must not be <c>null</c> and | ||||
| 		/// must contain at least 1 byte.</param> | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the | ||||
| 		/// <paramref name="pbKey" /> parameter is <c>null</c>.</exception> | ||||
| 		/// <exception cref="System.ArgumentException">Thrown if the | ||||
| 		/// <paramref name="pbKey" /> parameter contains no bytes or the | ||||
| 		/// algorithm is unknown.</exception> | ||||
| 		public CryptoRandomStream(CrsAlgorithm genAlgorithm, byte[] pbKey) | ||||
| 		public CryptoRandomStream(CrsAlgorithm a, byte[] pbKey) | ||||
| 		{ | ||||
| 			m_crsAlgorithm = genAlgorithm; | ||||
| 			if(pbKey == null) { Debug.Assert(false); throw new ArgumentNullException("pbKey"); } | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the | ||||
| 			int cbKey = pbKey.Length; | ||||
| 			if(cbKey <= 0) | ||||
| 			{ | ||||
| 				Debug.Assert(false); // Need at least one byte | ||||
| 				throw new ArgumentOutOfRangeException("pbKey"); | ||||
| 			} | ||||
| 		/// <paramref name="pbKey" /> parameter is <c>null</c>.</exception> | ||||
| 			m_crsAlgorithm = a; | ||||
| 		/// <exception cref="System.ArgumentException">Thrown if the | ||||
| 			if(a == CrsAlgorithm.ChaCha20) | ||||
| 			{ | ||||
| 				byte[] pbKey32 = new byte[32]; | ||||
| 				byte[] pbIV12 = new byte[12]; | ||||
| 		/// <paramref name="pbKey" /> parameter contains no bytes or the | ||||
| 				using(SHA512Managed h = new SHA512Managed()) | ||||
| 				{ | ||||
| 					byte[] pbHash = h.ComputeHash(pbKey); | ||||
| 					Array.Copy(pbHash, pbKey32, 32); | ||||
| 					Array.Copy(pbHash, 32, pbIV12, 0, 12); | ||||
| 					MemUtil.ZeroByteArray(pbHash); | ||||
| 				} | ||||
| 		/// algorithm is unknown.</exception> | ||||
| 				m_chacha20 = new ChaCha20Cipher(pbKey32, pbIV12, true); | ||||
| 			} | ||||
| 			else if(a == CrsAlgorithm.Salsa20) | ||||
| 		{ | ||||
| 				byte[] pbKey32 = CryptoUtil.HashSha256(pbKey); | ||||
| 				byte[] pbIV8 = new byte[8] { 0xE8, 0x30, 0x09, 0x4B, | ||||
| 					0x97, 0x20, 0x5D, 0x2A }; // Unique constant | ||||
|  | ||||
| 			Debug.Assert(pbKey != null); if(pbKey == null) throw new ArgumentNullException("pbKey"); | ||||
|  | ||||
| 			uint uKeyLen = (uint)pbKey.Length; | ||||
| 			Debug.Assert(uKeyLen != 0); if(uKeyLen == 0) throw new ArgumentException(); | ||||
|  | ||||
| 			if(genAlgorithm == CrsAlgorithm.ArcFourVariant) | ||||
| 				m_salsa20 = new Salsa20Cipher(pbKey32, pbIV8); | ||||
| 			} | ||||
| 			else if(a == CrsAlgorithm.ArcFourVariant) | ||||
| 			{ | ||||
| 				// Fill the state linearly | ||||
| 				m_pbState = new byte[256]; | ||||
| 				for(uint w = 0; w < 256; ++w) m_pbState[w] = (byte)w; | ||||
| 				for(int w = 0; w < 256; ++w) m_pbState[w] = (byte)w; | ||||
|  | ||||
| 				unchecked | ||||
| 				{ | ||||
| 					byte j = 0, t; | ||||
| 					uint inxKey = 0; | ||||
| 					for(uint w = 0; w < 256; ++w) // Key setup | ||||
| 					int inxKey = 0; | ||||
| 					for(int w = 0; w < 256; ++w) // Key setup | ||||
| 					{ | ||||
| 						j += (byte)(m_pbState[w] + pbKey[inxKey]); | ||||
|  | ||||
| @@ -103,25 +136,16 @@ namespace KeePassLib.Cryptography | ||||
| 						m_pbState[j] = t; | ||||
|  | ||||
| 						++inxKey; | ||||
| 						if(inxKey >= uKeyLen) inxKey = 0; | ||||
| 						if(inxKey >= cbKey) inxKey = 0; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				GetRandomBytes(512); // Increases security, see cryptanalysis | ||||
| 			} | ||||
| 			else if(genAlgorithm == CrsAlgorithm.Salsa20) | ||||
| 			{ | ||||
| 				SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				byte[] pbKey32 = sha256.ComputeHash(pbKey); | ||||
| 				byte[] pbIV = new byte[]{ 0xE8, 0x30, 0x09, 0x4B, | ||||
| 					0x97, 0x20, 0x5D, 0x2A }; // Unique constant | ||||
|  | ||||
| 				m_salsa20 = new Salsa20Cipher(pbKey32, pbIV); | ||||
| 			} | ||||
| 			else // Unknown algorithm | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentException(); | ||||
| 				throw new ArgumentOutOfRangeException("a"); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -132,15 +156,23 @@ namespace KeePassLib.Cryptography | ||||
| 		/// <returns>Returns <paramref name="uRequestedCount" /> random bytes.</returns> | ||||
| 		public byte[] GetRandomBytes(uint uRequestedCount) | ||||
| 		{ | ||||
| 			if(uRequestedCount == 0) return new byte[0]; | ||||
| 			if(uRequestedCount == 0) return MemUtil.EmptyByteArray; | ||||
|  | ||||
| 			byte[] pbRet = new byte[uRequestedCount]; | ||||
| 			if(uRequestedCount > (uint)int.MaxValue) | ||||
| 				throw new ArgumentOutOfRangeException("uRequestedCount"); | ||||
| 			int cb = (int)uRequestedCount; | ||||
|  | ||||
| 			if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) | ||||
| 			byte[] pbRet = new byte[cb]; | ||||
|  | ||||
| 			if(m_crsAlgorithm == CrsAlgorithm.ChaCha20) | ||||
| 				m_chacha20.Encrypt(pbRet, 0, cb); | ||||
| 			else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) | ||||
| 				m_salsa20.Encrypt(pbRet, 0, cb); | ||||
| 			else if(m_crsAlgorithm == CrsAlgorithm.ArcFourVariant) | ||||
| 			{ | ||||
| 				unchecked | ||||
| 				{ | ||||
| 					for(uint w = 0; w < uRequestedCount; ++w) | ||||
| 					for(int w = 0; w < cb; ++w) | ||||
| 					{ | ||||
| 						++m_i; | ||||
| 						m_j += m_pbState[m_i]; | ||||
| @@ -154,8 +186,6 @@ namespace KeePassLib.Cryptography | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if(m_crsAlgorithm == CrsAlgorithm.Salsa20) | ||||
| 				m_salsa20.Encrypt(pbRet, pbRet.Length, false); | ||||
| 			else { Debug.Assert(false); } | ||||
|  | ||||
| 			return pbRet; | ||||
| @@ -164,15 +194,8 @@ namespace KeePassLib.Cryptography | ||||
| 		public ulong GetRandomUInt64() | ||||
| 		{ | ||||
| 			byte[] pb = GetRandomBytes(8); | ||||
|  | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				return ((ulong)pb[0]) | ((ulong)pb[1] << 8) | | ||||
| 					((ulong)pb[2] << 16) | ((ulong)pb[3] << 24) | | ||||
| 					((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) | | ||||
| 					((ulong)pb[6] << 48) | ((ulong)pb[7] << 56); | ||||
| 			return MemUtil.BytesToUInt64(pb); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| #if CRSBENCHMARK | ||||
| 		public static string Benchmark() | ||||
|   | ||||
							
								
								
									
										126
									
								
								src/KeePassLib2Android/Cryptography/CryptoUtil.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/KeePassLib2Android/Cryptography/CryptoUtil.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography | ||||
| { | ||||
| 	public static class CryptoUtil | ||||
| 	{ | ||||
| 		public static byte[] HashSha256(byte[] pbData) | ||||
| 		{ | ||||
| 			if(pbData == null) throw new ArgumentNullException("pbData"); | ||||
|  | ||||
| 			return HashSha256(pbData, 0, pbData.Length); | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] HashSha256(byte[] pbData, int iOffset, int cbCount) | ||||
| 		{ | ||||
| 			if(pbData == null) throw new ArgumentNullException("pbData"); | ||||
|  | ||||
| #if DEBUG | ||||
| 			byte[] pbCopy = new byte[pbData.Length]; | ||||
| 			Array.Copy(pbData, pbCopy, pbData.Length); | ||||
| #endif | ||||
|  | ||||
| 			byte[] pbHash; | ||||
| 			using(SHA256Managed h = new SHA256Managed()) | ||||
| 			{ | ||||
| 				pbHash = h.ComputeHash(pbData, iOffset, cbCount); | ||||
| 			} | ||||
|  | ||||
| #if DEBUG | ||||
| 			// Ensure the data has not been modified | ||||
| 			Debug.Assert(MemUtil.ArraysEqual(pbData, pbCopy)); | ||||
|  | ||||
| 			Debug.Assert((pbHash != null) && (pbHash.Length == 32)); | ||||
| 			byte[] pbZero = new byte[32]; | ||||
| 			Debug.Assert(!MemUtil.ArraysEqual(pbHash, pbZero)); | ||||
| #endif | ||||
|  | ||||
| 			return pbHash; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Create a cryptographic key of length <paramref name="cbOut" /> | ||||
| 		/// (in bytes) from <paramref name="pbIn" />. | ||||
| 		/// </summary> | ||||
| 		public static byte[] ResizeKey(byte[] pbIn, int iInOffset, | ||||
| 			int cbIn, int cbOut) | ||||
| 		{ | ||||
| 			if(pbIn == null) throw new ArgumentNullException("pbIn"); | ||||
| 			if(cbOut < 0) throw new ArgumentOutOfRangeException("cbOut"); | ||||
|  | ||||
| 			if(cbOut == 0) return MemUtil.EmptyByteArray; | ||||
|  | ||||
| 			byte[] pbHash; | ||||
| 			if(cbOut <= 32) pbHash = HashSha256(pbIn, iInOffset, cbIn); | ||||
| 			else | ||||
| 			{ | ||||
| 				using(SHA512Managed h = new SHA512Managed()) | ||||
| 				{ | ||||
| 					pbHash = h.ComputeHash(pbIn, iInOffset, cbIn); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(cbOut == pbHash.Length) return pbHash; | ||||
|  | ||||
| 			byte[] pbRet = new byte[cbOut]; | ||||
| 			if(cbOut < pbHash.Length) | ||||
| 				Array.Copy(pbHash, pbRet, cbOut); | ||||
| 			else | ||||
| 			{ | ||||
| 				int iPos = 0; | ||||
| 				ulong r = 0; | ||||
| 				while(iPos < cbOut) | ||||
| 				{ | ||||
| 					Debug.Assert(pbHash.Length == 64); | ||||
| 					using(HMACSHA256 h = new HMACSHA256(pbHash)) | ||||
| 					{ | ||||
| 						byte[] pbR = MemUtil.UInt64ToBytes(r); | ||||
| 						byte[] pbPart = h.ComputeHash(pbR); | ||||
|  | ||||
| 						int cbCopy = Math.Min(cbOut - iPos, pbPart.Length); | ||||
| 						Debug.Assert(cbCopy > 0); | ||||
|  | ||||
| 						Array.Copy(pbPart, 0, pbRet, iPos, cbCopy); | ||||
| 						iPos += cbCopy; | ||||
| 						++r; | ||||
|  | ||||
| 						MemUtil.ZeroByteArray(pbPart); | ||||
| 					} | ||||
| 				} | ||||
| 				Debug.Assert(iPos == cbOut); | ||||
| 			} | ||||
|  | ||||
| #if DEBUG | ||||
| 			byte[] pbZero = new byte[pbHash.Length]; | ||||
| 			Debug.Assert(!MemUtil.ArraysEqual(pbHash, pbZero)); | ||||
| #endif | ||||
| 			MemUtil.ZeroByteArray(pbHash); | ||||
| 			return pbRet; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										229
									
								
								src/KeePassLib2Android/Cryptography/Hash/Blake2b.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								src/KeePassLib2Android/Cryptography/Hash/Blake2b.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,229 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| // This implementation is based on the official reference C | ||||
| // implementation by Samuel Neves (CC0 1.0 Universal). | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.Hash | ||||
| { | ||||
| 	public sealed class Blake2b : HashAlgorithm | ||||
| 	{ | ||||
| 		private const int NbRounds = 12; | ||||
| 		private const int NbBlockBytes = 128; | ||||
| 		private const int NbMaxOutBytes = 64; | ||||
|  | ||||
| 		private static readonly ulong[] g_vIV = new ulong[8] { | ||||
| 			0x6A09E667F3BCC908UL, 0xBB67AE8584CAA73BUL, | ||||
| 			0x3C6EF372FE94F82BUL, 0xA54FF53A5F1D36F1UL, | ||||
| 			0x510E527FADE682D1UL, 0x9B05688C2B3E6C1FUL, | ||||
| 			0x1F83D9ABFB41BD6BUL, 0x5BE0CD19137E2179UL | ||||
| 		}; | ||||
|  | ||||
| 		private static readonly int[] g_vSigma = new int[NbRounds * 16] { | ||||
| 			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 			14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3, | ||||
| 			11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4, | ||||
| 			7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8, | ||||
| 			9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13, | ||||
| 			2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9, | ||||
| 			12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11, | ||||
| 			13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10, | ||||
| 			6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5, | ||||
| 			10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0, | ||||
| 			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, | ||||
| 			14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 | ||||
| 		}; | ||||
|  | ||||
| 		private readonly int m_cbHashLength; | ||||
|  | ||||
| 		private ulong[] m_h = new ulong[8]; | ||||
| 		private ulong[] m_t = new ulong[2]; | ||||
| 		private ulong[] m_f = new ulong[2]; | ||||
| 		private byte[] m_buf = new byte[NbBlockBytes]; | ||||
| 		private int m_cbBuf = 0; | ||||
|  | ||||
| 		private ulong[] m_m = new ulong[16]; | ||||
| 		private ulong[] m_v = new ulong[16]; | ||||
|  | ||||
| 		public Blake2b() | ||||
| 		{ | ||||
| 			m_cbHashLength = NbMaxOutBytes; | ||||
| 			this.HashSizeValue = NbMaxOutBytes * 8; // Bits | ||||
|  | ||||
| 			Initialize(); | ||||
| 		} | ||||
|  | ||||
| 		public Blake2b(int cbHashLength) | ||||
| 		{ | ||||
| 			if((cbHashLength < 0) || (cbHashLength > NbMaxOutBytes)) | ||||
| 				throw new ArgumentOutOfRangeException("cbHashLength"); | ||||
|  | ||||
| 			m_cbHashLength = cbHashLength; | ||||
| 			this.HashSizeValue = cbHashLength * 8; // Bits | ||||
|  | ||||
| 			Initialize(); | ||||
| 		} | ||||
|  | ||||
| 		public override void Initialize() | ||||
| 		{ | ||||
| 			Debug.Assert(m_h.Length == g_vIV.Length); | ||||
| 			Array.Copy(g_vIV, m_h, m_h.Length); | ||||
|  | ||||
| 			// Fan-out = 1, depth = 1 | ||||
| 			m_h[0] ^= 0x0000000001010000UL ^ (ulong)m_cbHashLength; | ||||
|  | ||||
| 			Array.Clear(m_t, 0, m_t.Length); | ||||
| 			Array.Clear(m_f, 0, m_f.Length); | ||||
| 			Array.Clear(m_buf, 0, m_buf.Length); | ||||
| 			m_cbBuf = 0; | ||||
|  | ||||
| 			Array.Clear(m_m, 0, m_m.Length); | ||||
| 			Array.Clear(m_v, 0, m_v.Length); | ||||
| 		} | ||||
|  | ||||
| 		private static void G(ulong[] v, ulong[] m, int r16, int i, | ||||
| 			int a, int b, int c, int d) | ||||
| 		{ | ||||
| 			int p = r16 + i; | ||||
|  | ||||
| 			v[a] += v[b] + m[g_vSigma[p]]; | ||||
| 			v[d] = MemUtil.RotateRight64(v[d] ^ v[a], 32); | ||||
| 			v[c] += v[d]; | ||||
| 			v[b] = MemUtil.RotateRight64(v[b] ^ v[c], 24); | ||||
| 			v[a] += v[b] + m[g_vSigma[p + 1]]; | ||||
| 			v[d] = MemUtil.RotateRight64(v[d] ^ v[a], 16); | ||||
| 			v[c] += v[d]; | ||||
| 			v[b] = MemUtil.RotateRight64(v[b] ^ v[c], 63); | ||||
| 		} | ||||
|  | ||||
| 		private void Compress(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			ulong[] v = m_v; | ||||
| 			ulong[] m = m_m; | ||||
| 			ulong[] h = m_h; | ||||
|  | ||||
| 			for(int i = 0; i < 16; ++i) | ||||
| 				m[i] = MemUtil.BytesToUInt64(pb, iOffset + (i << 3)); | ||||
|  | ||||
| 			Array.Copy(h, v, 8); | ||||
| 			v[8] = g_vIV[0]; | ||||
| 			v[9] = g_vIV[1]; | ||||
| 			v[10] = g_vIV[2]; | ||||
| 			v[11] = g_vIV[3]; | ||||
| 			v[12] = g_vIV[4] ^ m_t[0]; | ||||
| 			v[13] = g_vIV[5] ^ m_t[1]; | ||||
| 			v[14] = g_vIV[6] ^ m_f[0]; | ||||
| 			v[15] = g_vIV[7] ^ m_f[1]; | ||||
|  | ||||
| 			for(int r = 0; r < NbRounds; ++r) | ||||
| 			{ | ||||
| 				int r16 = r << 4; | ||||
|  | ||||
| 				G(v, m, r16, 0, 0, 4, 8, 12); | ||||
| 				G(v, m, r16, 2, 1, 5, 9, 13); | ||||
| 				G(v, m, r16, 4, 2, 6, 10, 14); | ||||
| 				G(v, m, r16, 6, 3, 7, 11, 15); | ||||
| 				G(v, m, r16, 8, 0, 5, 10, 15); | ||||
| 				G(v, m, r16, 10, 1, 6, 11, 12); | ||||
| 				G(v, m, r16, 12, 2, 7, 8, 13); | ||||
| 				G(v, m, r16, 14, 3, 4, 9, 14); | ||||
| 			} | ||||
|  | ||||
| 			for(int i = 0; i < 8; ++i) | ||||
| 				h[i] ^= v[i] ^ v[i + 8]; | ||||
| 		} | ||||
|  | ||||
| 		private void IncrementCounter(ulong cb) | ||||
| 		{ | ||||
| 			m_t[0] += cb; | ||||
| 			if(m_t[0] < cb) ++m_t[1]; | ||||
| 		} | ||||
|  | ||||
| 		protected override void HashCore(byte[] array, int ibStart, int cbSize) | ||||
| 		{ | ||||
| 			Debug.Assert(m_f[0] == 0); | ||||
|  | ||||
| 			if((m_cbBuf + cbSize) > NbBlockBytes) // Not '>=' (buffer must not be empty) | ||||
| 			{ | ||||
| 				int cbFill = NbBlockBytes - m_cbBuf; | ||||
| 				if(cbFill > 0) Array.Copy(array, ibStart, m_buf, m_cbBuf, cbFill); | ||||
|  | ||||
| 				IncrementCounter((ulong)NbBlockBytes); | ||||
| 				Compress(m_buf, 0); | ||||
|  | ||||
| 				m_cbBuf = 0; | ||||
| 				cbSize -= cbFill; | ||||
| 				ibStart += cbFill; | ||||
|  | ||||
| 				while(cbSize > NbBlockBytes) // Not '>=' (buffer must not be empty) | ||||
| 				{ | ||||
| 					IncrementCounter((ulong)NbBlockBytes); | ||||
| 					Compress(array, ibStart); | ||||
|  | ||||
| 					cbSize -= NbBlockBytes; | ||||
| 					ibStart += NbBlockBytes; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(cbSize > 0) | ||||
| 			{ | ||||
| 				Debug.Assert((m_cbBuf + cbSize) <= NbBlockBytes); | ||||
|  | ||||
| 				Array.Copy(array, ibStart, m_buf, m_cbBuf, cbSize); | ||||
| 				m_cbBuf += cbSize; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		protected override byte[] HashFinal() | ||||
| 		{ | ||||
| 			if(m_f[0] != 0) { Debug.Assert(false); throw new InvalidOperationException(); } | ||||
| 			Debug.Assert(((m_t[1] == 0) && (m_t[0] == 0)) || | ||||
| 				(m_cbBuf > 0)); // Buffer must not be empty for last block processing | ||||
|  | ||||
| 			m_f[0] = ulong.MaxValue; // Indicate last block | ||||
|  | ||||
| 			int cbFill = NbBlockBytes - m_cbBuf; | ||||
| 			if(cbFill > 0) Array.Clear(m_buf, m_cbBuf, cbFill); | ||||
|  | ||||
| 			IncrementCounter((ulong)m_cbBuf); | ||||
| 			Compress(m_buf, 0); | ||||
|  | ||||
| 			byte[] pbHash = new byte[NbMaxOutBytes]; | ||||
| 			for(int i = 0; i < m_h.Length; ++i) | ||||
| 				MemUtil.UInt64ToBytesEx(m_h[i], pbHash, i << 3); | ||||
|  | ||||
| 			if(m_cbHashLength == NbMaxOutBytes) return pbHash; | ||||
| 			Debug.Assert(m_cbHashLength < NbMaxOutBytes); | ||||
|  | ||||
| 			byte[] pbShort = new byte[m_cbHashLength]; | ||||
| 			if(m_cbHashLength > 0) | ||||
| 				Array.Copy(pbHash, pbShort, m_cbHashLength); | ||||
| 			MemUtil.ZeroByteArray(pbHash); | ||||
| 			return pbShort; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										270
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/AesKdf.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/AesKdf.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,270 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| #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; | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public sealed class AesKdf : KdfEngine | ||||
| 	{ | ||||
| 		private static readonly PwUuid g_uuid = new PwUuid(new byte[] { | ||||
| 			0xC9, 0xD9, 0xF3, 0x9A, 0x62, 0x8A, 0x44, 0x60, | ||||
| 			0xBF, 0x74, 0x0D, 0x08, 0xC1, 0x8A, 0x4F, 0xEA }); | ||||
|  | ||||
| 		public const string ParamRounds = "R"; // UInt64 | ||||
| 		public const string ParamSeed = "S"; // Byte[32] | ||||
|  | ||||
| 		public override PwUuid Uuid | ||||
| 		{ | ||||
| 			get { return g_uuid; } | ||||
| 		} | ||||
|  | ||||
| 		public override string Name | ||||
| 		{ | ||||
| 			get { return "AES-KDF"; } | ||||
| 		} | ||||
|  | ||||
| 		public AesKdf() | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| 		public override KdfParameters GetDefaultParameters() | ||||
| 		{ | ||||
| 			KdfParameters p = base.GetDefaultParameters(); | ||||
| 			p.SetUInt64(ParamRounds, PwDefs.DefaultKeyEncryptionRounds); | ||||
| 			return p; | ||||
| 		} | ||||
|  | ||||
| 		public override void Randomize(KdfParameters p) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); return; } | ||||
| 			Debug.Assert(g_uuid.Equals(p.KdfUuid)); | ||||
|  | ||||
| 			byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32); | ||||
| 			p.SetByteArray(ParamSeed, pbSeed); | ||||
| 		} | ||||
|  | ||||
| 		public override byte[] Transform(byte[] pbMsg, KdfParameters p) | ||||
| 		{ | ||||
| 			if(pbMsg == null) throw new ArgumentNullException("pbMsg"); | ||||
| 			if(p == null) throw new ArgumentNullException("p"); | ||||
|  | ||||
| 			Type tRounds = p.GetTypeOf(ParamRounds); | ||||
| 			if(tRounds == null) throw new ArgumentNullException("p.Rounds"); | ||||
| 			if(tRounds != typeof(ulong)) throw new ArgumentOutOfRangeException("p.Rounds"); | ||||
| 			ulong uRounds = p.GetUInt64(ParamRounds, 0); | ||||
|  | ||||
| 			byte[] pbSeed = p.GetByteArray(ParamSeed); | ||||
| 			if(pbSeed == null) throw new ArgumentNullException("p.Seed"); | ||||
|  | ||||
| 			if(pbMsg.Length != 32) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				pbMsg = CryptoUtil.HashSha256(pbMsg); | ||||
| 			} | ||||
|  | ||||
| 			if(pbSeed.Length != 32) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				pbSeed = CryptoUtil.HashSha256(pbSeed); | ||||
| 			} | ||||
|  | ||||
| 			return TransformKey(pbMsg, pbSeed, uRounds); | ||||
| 		} | ||||
|  | ||||
| 		private static byte[] TransformKey(byte[] pbOriginalKey32, byte[] pbKeySeed32, | ||||
| 			ulong uNumRounds) | ||||
| 		{ | ||||
| 			Debug.Assert((pbOriginalKey32 != null) && (pbOriginalKey32.Length == 32)); | ||||
| 			if(pbOriginalKey32 == null) throw new ArgumentNullException("pbOriginalKey32"); | ||||
| 			if(pbOriginalKey32.Length != 32) throw new ArgumentException(); | ||||
|  | ||||
| 			Debug.Assert((pbKeySeed32 != null) && (pbKeySeed32.Length == 32)); | ||||
| 			if(pbKeySeed32 == null) throw new ArgumentNullException("pbKeySeed32"); | ||||
| 			if(pbKeySeed32.Length != 32) throw new ArgumentException(); | ||||
|  | ||||
| 			byte[] pbNewKey = new byte[32]; | ||||
| 			Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length); | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				// Try to use the native library first | ||||
| 				if(NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds)) | ||||
| 					return CryptoUtil.HashSha256(pbNewKey); | ||||
|  | ||||
| 				if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds)) | ||||
| 					return CryptoUtil.HashSha256(pbNewKey); | ||||
| 			} | ||||
| 			finally { MemUtil.ZeroByteArray(pbNewKey); } | ||||
|  | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, | ||||
| 			ulong uNumRounds) | ||||
| 		{ | ||||
| #if KeePassUAP | ||||
| 			KeyParameter kp = new KeyParameter(pbKeySeed32); | ||||
| 			AesEngine aes = new AesEngine(); | ||||
| 			aes.Init(true, kp); | ||||
|  | ||||
| 			for(ulong i = 0; i < uNumRounds; ++i) | ||||
| 			{ | ||||
| 				aes.ProcessBlock(pbNewKey32, 0, pbNewKey32, 0); | ||||
| 				aes.ProcessBlock(pbNewKey32, 16, pbNewKey32, 16); | ||||
| 			} | ||||
| #else | ||||
| 			byte[] pbIV = new byte[16]; | ||||
| 			Array.Clear(pbIV, 0, pbIV.Length); | ||||
|  | ||||
| 			RijndaelManaged r = new RijndaelManaged(); | ||||
| 			if(r.BlockSize != 128) // AES block size | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				r.BlockSize = 128; | ||||
| 			} | ||||
|  | ||||
| 			r.IV = pbIV; | ||||
| 			r.Mode = CipherMode.ECB; | ||||
| 			r.KeySize = 256; | ||||
| 			r.Key = pbKeySeed32; | ||||
| 			ICryptoTransform iCrypt = r.CreateEncryptor(); | ||||
|  | ||||
| 			// !iCrypt.CanReuseTransform -- doesn't work with Mono | ||||
| 			if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || | ||||
| 				(iCrypt.OutputBlockSize != 16)) | ||||
| 			{ | ||||
| 				Debug.Assert(false, "Invalid ICryptoTransform."); | ||||
| 				Debug.Assert((iCrypt.InputBlockSize == 16), "Invalid input block size!"); | ||||
| 				Debug.Assert((iCrypt.OutputBlockSize == 16), "Invalid output block size!"); | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			for(ulong i = 0; i < uNumRounds; ++i) | ||||
| 			{ | ||||
| 				iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0); | ||||
| 				iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16); | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public override KdfParameters GetBestParameters(uint uMilliseconds) | ||||
| 		{ | ||||
| 			const ulong uStep = 3001; | ||||
| 			ulong uRounds; | ||||
|  | ||||
| 			KdfParameters p = GetDefaultParameters(); | ||||
|  | ||||
| 			// Try native method | ||||
| 			if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds)) | ||||
| 			{ | ||||
| 				p.SetUInt64(ParamRounds, uRounds); | ||||
| 				return p; | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbKey = new byte[32]; | ||||
| 			byte[] pbNewKey = new byte[32]; | ||||
| 			for(int i = 0; i < pbKey.Length; ++i) | ||||
| 			{ | ||||
| 				pbKey[i] = (byte)i; | ||||
| 				pbNewKey[i] = (byte)i; | ||||
| 			} | ||||
|  | ||||
| #if KeePassUAP | ||||
| 			KeyParameter kp = new KeyParameter(pbKey); | ||||
| 			AesEngine aes = new AesEngine(); | ||||
| 			aes.Init(true, kp); | ||||
| #else | ||||
| 			byte[] pbIV = new byte[16]; | ||||
| 			Array.Clear(pbIV, 0, pbIV.Length); | ||||
|  | ||||
| 			RijndaelManaged r = new RijndaelManaged(); | ||||
| 			if(r.BlockSize != 128) // AES block size | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				r.BlockSize = 128; | ||||
| 			} | ||||
|  | ||||
| 			r.IV = pbIV; | ||||
| 			r.Mode = CipherMode.ECB; | ||||
| 			r.KeySize = 256; | ||||
| 			r.Key = pbKey; | ||||
| 			ICryptoTransform iCrypt = r.CreateEncryptor(); | ||||
|  | ||||
| 			// !iCrypt.CanReuseTransform -- doesn't work with Mono | ||||
| 			if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || | ||||
| 				(iCrypt.OutputBlockSize != 16)) | ||||
| 			{ | ||||
| 				Debug.Assert(false, "Invalid ICryptoTransform."); | ||||
| 				Debug.Assert(iCrypt.InputBlockSize == 16, "Invalid input block size!"); | ||||
| 				Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!"); | ||||
|  | ||||
| 				p.SetUInt64(ParamRounds, PwDefs.DefaultKeyEncryptionRounds); | ||||
| 				return p; | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			uRounds = 0; | ||||
| 			int tStart = Environment.TickCount; | ||||
| 			while(true) | ||||
| 			{ | ||||
| 				for(ulong j = 0; j < uStep; ++j) | ||||
| 				{ | ||||
| #if KeePassUAP | ||||
| 					aes.ProcessBlock(pbNewKey, 0, pbNewKey, 0); | ||||
| 					aes.ProcessBlock(pbNewKey, 16, pbNewKey, 16); | ||||
| #else | ||||
| 					iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0); | ||||
| 					iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16); | ||||
| #endif | ||||
| 				} | ||||
|  | ||||
| 				uRounds += uStep; | ||||
| 				if(uRounds < uStep) // Overflow check | ||||
| 				{ | ||||
| 					uRounds = ulong.MaxValue; | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				uint tElapsed = (uint)(Environment.TickCount - tStart); | ||||
| 				if(tElapsed > uMilliseconds) break; | ||||
| 			} | ||||
|  | ||||
| 			p.SetUInt64(ParamRounds, uRounds); | ||||
| 			return p; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,610 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| // This implementation is based on the official reference C | ||||
| // implementation by Daniel Dinu and Dmitry Khovratovich (CC0 1.0). | ||||
|  | ||||
| // Relative iterations (* = B2ROUND_ARRAYS \\ G_INLINED): | ||||
| //     * | false true | ||||
| // ------+----------- | ||||
| // false |  8885 9618 | ||||
| //  true |  9009 9636 | ||||
| #define ARGON2_B2ROUND_ARRAYS | ||||
| #define ARGON2_G_INLINED | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
|  | ||||
| using KeePassLib.Cryptography.Hash; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public sealed partial class Argon2Kdf : KdfEngine | ||||
| 	{ | ||||
| 		private const ulong NbBlockSize = 1024; | ||||
| 		private const ulong NbBlockSizeInQW = NbBlockSize / 8UL; | ||||
| 		private const ulong NbSyncPoints = 4; | ||||
|  | ||||
| 		private const int NbPreHashDigestLength = 64; | ||||
| 		private const int NbPreHashSeedLength = NbPreHashDigestLength + 8; | ||||
|  | ||||
| #if ARGON2_B2ROUND_ARRAYS | ||||
| 		private static int[][] g_vFBCols = null; | ||||
| 		private static int[][] g_vFBRows = null; | ||||
| #endif | ||||
|  | ||||
| 		private sealed class Argon2Ctx | ||||
| 		{ | ||||
| 			public uint Version = 0; | ||||
|  | ||||
| 			public ulong Lanes = 0; | ||||
| 			public ulong TCost = 0; | ||||
| 			public ulong MCost = 0; | ||||
| 			public ulong MemoryBlocks = 0; | ||||
| 			public ulong SegmentLength = 0; | ||||
| 			public ulong LaneLength = 0; | ||||
|  | ||||
| 			public ulong[] Mem = null; | ||||
| 		} | ||||
|  | ||||
| 		private sealed class Argon2ThreadInfo | ||||
| 		{ | ||||
| 			public Argon2Ctx Context = null; | ||||
| 			public ManualResetEvent Finished = new ManualResetEvent(false); | ||||
|  | ||||
| 			public ulong Pass = 0; | ||||
| 			public ulong Lane = 0; | ||||
| 			public ulong Slice = 0; | ||||
| 			public ulong Index = 0; | ||||
| 		} | ||||
|  | ||||
| 		private static byte[] Argon2d(byte[] pbMsg, byte[] pbSalt, uint uParallel, | ||||
| 			ulong uMem, ulong uIt, int cbOut, uint uVersion, byte[] pbSecretKey, | ||||
| 			byte[] pbAssocData) | ||||
| 		{ | ||||
| 			pbSecretKey = (pbSecretKey ?? MemUtil.EmptyByteArray); | ||||
| 			pbAssocData = (pbAssocData ?? MemUtil.EmptyByteArray); | ||||
|  | ||||
| #if ARGON2_B2ROUND_ARRAYS | ||||
| 			InitB2RoundIndexArrays(); | ||||
| #endif | ||||
|  | ||||
| 			Argon2Ctx ctx = new Argon2Ctx(); | ||||
| 			ctx.Version = uVersion; | ||||
|  | ||||
| 			ctx.Lanes = uParallel; | ||||
| 			ctx.TCost = uIt; | ||||
| 			ctx.MCost = uMem / NbBlockSize; | ||||
| 			ctx.MemoryBlocks = Math.Max(ctx.MCost, 2UL * NbSyncPoints * ctx.Lanes); | ||||
|  | ||||
| 			ctx.SegmentLength = ctx.MemoryBlocks / (ctx.Lanes * NbSyncPoints); | ||||
| 			ctx.MemoryBlocks = ctx.SegmentLength * ctx.Lanes * NbSyncPoints; | ||||
|  | ||||
| 			ctx.LaneLength = ctx.SegmentLength * NbSyncPoints; | ||||
|  | ||||
| 			Debug.Assert(NbBlockSize == (NbBlockSizeInQW * | ||||
| 				(ulong)Marshal.SizeOf(typeof(ulong)))); | ||||
| 			ctx.Mem = new ulong[ctx.MemoryBlocks * NbBlockSizeInQW]; | ||||
|  | ||||
| 			Blake2b h = new Blake2b(); | ||||
|  | ||||
| 			// Initial hash | ||||
| 			Debug.Assert(h.HashSize == (NbPreHashDigestLength * 8)); | ||||
| 			byte[] pbBuf = new byte[4]; | ||||
| 			MemUtil.UInt32ToBytesEx(uParallel, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)cbOut, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)ctx.MCost, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)uIt, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx(uVersion, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx(0, pbBuf, 0); // Argon2d type = 0 | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)pbMsg.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)pbSalt.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbSalt, 0, pbSalt.Length, pbSalt, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)pbSecretKey.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbSecretKey, 0, pbSecretKey.Length, pbSecretKey, 0); | ||||
| 			MemUtil.UInt32ToBytesEx((uint)pbAssocData.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbBuf, 0, pbBuf.Length, pbBuf, 0); | ||||
| 			h.TransformBlock(pbAssocData, 0, pbAssocData.Length, pbAssocData, 0); | ||||
| 			h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
| 			byte[] pbH0 = h.Hash; | ||||
| 			Debug.Assert(pbH0.Length == 64); | ||||
|  | ||||
| 			byte[] pbBlockHash = new byte[NbPreHashSeedLength]; | ||||
| 			Array.Copy(pbH0, pbBlockHash, pbH0.Length); | ||||
| 			MemUtil.ZeroByteArray(pbH0); | ||||
|  | ||||
| 			FillFirstBlocks(ctx, pbBlockHash, h); | ||||
| 			MemUtil.ZeroByteArray(pbBlockHash); | ||||
|  | ||||
| 			FillMemoryBlocks(ctx); | ||||
|  | ||||
| 			byte[] pbOut = FinalHash(ctx, cbOut, h); | ||||
|  | ||||
| 			h.Clear(); | ||||
| 			MemUtil.ZeroArray<ulong>(ctx.Mem); | ||||
| 			return pbOut; | ||||
| 		} | ||||
|  | ||||
| 		private static void LoadBlock(ulong[] pqDst, ulong uDstOffset, byte[] pbIn) | ||||
| 		{ | ||||
| 			// for(ulong i = 0; i < NbBlockSizeInQW; ++i) | ||||
| 			//	pqDst[uDstOffset + i] = MemUtil.BytesToUInt64(pbIn, (int)(i << 3)); | ||||
|  | ||||
| 			Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); | ||||
| 			int iDstOffset = (int)uDstOffset; | ||||
| 			for(int i = 0; i < (int)NbBlockSizeInQW; ++i) | ||||
| 				pqDst[iDstOffset + i] = MemUtil.BytesToUInt64(pbIn, i << 3); | ||||
| 		} | ||||
|  | ||||
| 		private static void StoreBlock(byte[] pbDst, ulong[] pqSrc) | ||||
| 		{ | ||||
| 			for(int i = 0; i < (int)NbBlockSizeInQW; ++i) | ||||
| 				MemUtil.UInt64ToBytesEx(pqSrc[i], pbDst, i << 3); | ||||
| 		} | ||||
|  | ||||
| 		private static void CopyBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc, | ||||
| 			ulong uSrcOffset) | ||||
| 		{ | ||||
| 			// for(ulong i = 0; i < NbBlockSizeInQW; ++i) | ||||
| 			//	vDst[uDstOffset + i] = vSrc[uSrcOffset + i]; | ||||
|  | ||||
| 			// Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); | ||||
| 			// Debug.Assert((uSrcOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); | ||||
| 			// int iDstOffset = (int)uDstOffset; | ||||
| 			// int iSrcOffset = (int)uSrcOffset; | ||||
| 			// for(int i = 0; i < (int)NbBlockSizeInQW; ++i) | ||||
| 			//	vDst[iDstOffset + i] = vSrc[iSrcOffset + i]; | ||||
|  | ||||
| 			Array.Copy(vSrc, (long)uSrcOffset, vDst, (long)uDstOffset, | ||||
| 				(long)NbBlockSizeInQW); | ||||
| 		} | ||||
|  | ||||
| 		private static void XorBlock(ulong[] vDst, ulong uDstOffset, ulong[] vSrc, | ||||
| 			ulong uSrcOffset) | ||||
| 		{ | ||||
| 			// for(ulong i = 0; i < NbBlockSizeInQW; ++i) | ||||
| 			//	vDst[uDstOffset + i] ^= vSrc[uSrcOffset + i]; | ||||
|  | ||||
| 			Debug.Assert((uDstOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); | ||||
| 			Debug.Assert((uSrcOffset + NbBlockSizeInQW - 1UL) <= (ulong)int.MaxValue); | ||||
| 			int iDstOffset = (int)uDstOffset; | ||||
| 			int iSrcOffset = (int)uSrcOffset; | ||||
| 			for(int i = 0; i < (int)NbBlockSizeInQW; ++i) | ||||
| 				vDst[iDstOffset + i] ^= vSrc[iSrcOffset + i]; | ||||
| 		} | ||||
|  | ||||
| 		private static void Blake2bLong(byte[] pbOut, int cbOut, | ||||
| 			byte[] pbIn, int cbIn, Blake2b h) | ||||
| 		{ | ||||
| 			Debug.Assert((h != null) && (h.HashSize == (64 * 8))); | ||||
|  | ||||
| 			byte[] pbOutLen = new byte[4]; | ||||
| 			MemUtil.UInt32ToBytesEx((uint)cbOut, pbOutLen, 0); | ||||
|  | ||||
| 			if(cbOut <= 64) | ||||
| 			{ | ||||
| 				Blake2b hOut = ((cbOut == 64) ? h : new Blake2b(cbOut)); | ||||
| 				if(cbOut == 64) hOut.Initialize(); | ||||
|  | ||||
| 				hOut.TransformBlock(pbOutLen, 0, pbOutLen.Length, pbOutLen, 0); | ||||
| 				hOut.TransformBlock(pbIn, 0, cbIn, pbIn, 0); | ||||
| 				hOut.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
|  | ||||
| 				Array.Copy(hOut.Hash, pbOut, cbOut); | ||||
|  | ||||
| 				if(cbOut < 64) hOut.Clear(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			h.Initialize(); | ||||
| 			h.TransformBlock(pbOutLen, 0, pbOutLen.Length, pbOutLen, 0); | ||||
| 			h.TransformBlock(pbIn, 0, cbIn, pbIn, 0); | ||||
| 			h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
|  | ||||
| 			byte[] pbOutBuffer = new byte[64]; | ||||
| 			Array.Copy(h.Hash, pbOutBuffer, pbOutBuffer.Length); | ||||
|  | ||||
| 			int ibOut = 64 / 2; | ||||
| 			Array.Copy(pbOutBuffer, pbOut, ibOut); | ||||
| 			int cbToProduce = cbOut - ibOut; | ||||
|  | ||||
| 			h.Initialize(); | ||||
| 			while(cbToProduce > 64) | ||||
| 			{ | ||||
| 				byte[] pbHash = h.ComputeHash(pbOutBuffer); | ||||
| 				Array.Copy(pbHash, pbOutBuffer, 64); | ||||
|  | ||||
| 				Array.Copy(pbHash, 0, pbOut, ibOut, 64 / 2); | ||||
| 				ibOut += 64 / 2; | ||||
| 				cbToProduce -= 64 / 2; | ||||
|  | ||||
| 				MemUtil.ZeroByteArray(pbHash); | ||||
| 			} | ||||
|  | ||||
| 			using(Blake2b hOut = new Blake2b(cbToProduce)) | ||||
| 			{ | ||||
| 				byte[] pbHash = hOut.ComputeHash(pbOutBuffer); | ||||
| 				Array.Copy(pbHash, 0, pbOut, ibOut, cbToProduce); | ||||
|  | ||||
| 				MemUtil.ZeroByteArray(pbHash); | ||||
| 			} | ||||
|  | ||||
| 			MemUtil.ZeroByteArray(pbOutBuffer); | ||||
| 		} | ||||
|  | ||||
| #if !ARGON2_G_INLINED | ||||
| 		private static ulong BlaMka(ulong x, ulong y) | ||||
| 		{ | ||||
| 			ulong xy = (x & 0xFFFFFFFFUL) * (y & 0xFFFFFFFFUL); | ||||
| 			return (x + y + (xy << 1)); | ||||
| 		} | ||||
|  | ||||
| 		private static void G(ulong[] v, int a, int b, int c, int d) | ||||
| 		{ | ||||
| 			ulong va = v[a], vb = v[b], vc = v[c], vd = v[d]; | ||||
|  | ||||
| 			va = BlaMka(va, vb); | ||||
| 			vd = MemUtil.RotateRight64(vd ^ va, 32); | ||||
| 			vc = BlaMka(vc, vd); | ||||
| 			vb = MemUtil.RotateRight64(vb ^ vc, 24); | ||||
| 			va = BlaMka(va, vb); | ||||
| 			vd = MemUtil.RotateRight64(vd ^ va, 16); | ||||
| 			vc = BlaMka(vc, vd); | ||||
| 			vb = MemUtil.RotateRight64(vb ^ vc, 63); | ||||
|  | ||||
| 			v[a] = va; | ||||
| 			v[b] = vb; | ||||
| 			v[c] = vc; | ||||
| 			v[d] = vd; | ||||
| 		} | ||||
| #else | ||||
| 		private static void G(ulong[] v, int a, int b, int c, int d) | ||||
| 		{ | ||||
| 			ulong va = v[a], vb = v[b], vc = v[c], vd = v[d]; | ||||
|  | ||||
| 			ulong xy = (va & 0xFFFFFFFFUL) * (vb & 0xFFFFFFFFUL); | ||||
| 			va += vb + (xy << 1); | ||||
|  | ||||
| 			vd = MemUtil.RotateRight64(vd ^ va, 32); | ||||
|  | ||||
| 			xy = (vc & 0xFFFFFFFFUL) * (vd & 0xFFFFFFFFUL); | ||||
| 			vc += vd + (xy << 1); | ||||
|  | ||||
| 			vb = MemUtil.RotateRight64(vb ^ vc, 24); | ||||
|  | ||||
| 			xy = (va & 0xFFFFFFFFUL) * (vb & 0xFFFFFFFFUL); | ||||
| 			va += vb + (xy << 1); | ||||
|  | ||||
| 			vd = MemUtil.RotateRight64(vd ^ va, 16); | ||||
|  | ||||
| 			xy = (vc & 0xFFFFFFFFUL) * (vd & 0xFFFFFFFFUL); | ||||
| 			vc += vd + (xy << 1); | ||||
|  | ||||
| 			vb = MemUtil.RotateRight64(vb ^ vc, 63); | ||||
|  | ||||
| 			v[a] = va; | ||||
| 			v[b] = vb; | ||||
| 			v[c] = vc; | ||||
| 			v[d] = vd; | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| #if ARGON2_B2ROUND_ARRAYS | ||||
| 		private static void Blake2RoundNoMsg(ulong[] pbR, int[] v) | ||||
| 		{ | ||||
| 			G(pbR, v[0], v[4], v[8], v[12]); | ||||
| 			G(pbR, v[1], v[5], v[9], v[13]); | ||||
| 			G(pbR, v[2], v[6], v[10], v[14]); | ||||
| 			G(pbR, v[3], v[7], v[11], v[15]); | ||||
| 			G(pbR, v[0], v[5], v[10], v[15]); | ||||
| 			G(pbR, v[1], v[6], v[11], v[12]); | ||||
| 			G(pbR, v[2], v[7], v[8], v[13]); | ||||
| 			G(pbR, v[3], v[4], v[9], v[14]); | ||||
| 		} | ||||
| #else | ||||
| 		private static void Blake2RoundNoMsgCols16i(ulong[] pbR, int i) | ||||
| 		{ | ||||
| 			G(pbR, i,     i + 4, i +  8, i + 12); | ||||
| 			G(pbR, i + 1, i + 5, i +  9, i + 13); | ||||
| 			G(pbR, i + 2, i + 6, i + 10, i + 14); | ||||
| 			G(pbR, i + 3, i + 7, i + 11, i + 15); | ||||
| 			G(pbR, i,     i + 5, i + 10, i + 15); | ||||
| 			G(pbR, i + 1, i + 6, i + 11, i + 12); | ||||
| 			G(pbR, i + 2, i + 7, i +  8, i + 13); | ||||
| 			G(pbR, i + 3, i + 4, i +  9, i + 14); | ||||
| 		} | ||||
|  | ||||
| 		private static void Blake2RoundNoMsgRows2i(ulong[] pbR, int i) | ||||
| 		{ | ||||
| 			G(pbR, i,      i + 32, i + 64, i +  96); | ||||
| 			G(pbR, i +  1, i + 33, i + 65, i +  97); | ||||
| 			G(pbR, i + 16, i + 48, i + 80, i + 112); | ||||
| 			G(pbR, i + 17, i + 49, i + 81, i + 113); | ||||
| 			G(pbR, i,      i + 33, i + 80, i + 113); | ||||
| 			G(pbR, i +  1, i + 48, i + 81, i +  96); | ||||
| 			G(pbR, i + 16, i + 49, i + 64, i +  97); | ||||
| 			G(pbR, i + 17, i + 32, i + 65, i + 112); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		private static void FillFirstBlocks(Argon2Ctx ctx, byte[] pbBlockHash, | ||||
| 			Blake2b h) | ||||
| 		{ | ||||
| 			byte[] pbBlock = new byte[NbBlockSize]; | ||||
|  | ||||
| 			for(ulong l = 0; l < ctx.Lanes; ++l) | ||||
| 			{ | ||||
| 				MemUtil.UInt32ToBytesEx(0, pbBlockHash, NbPreHashDigestLength); | ||||
| 				MemUtil.UInt32ToBytesEx((uint)l, pbBlockHash, NbPreHashDigestLength + 4); | ||||
|  | ||||
| 				Blake2bLong(pbBlock, (int)NbBlockSize, pbBlockHash, | ||||
| 					NbPreHashSeedLength, h); | ||||
| 				LoadBlock(ctx.Mem, l * ctx.LaneLength * NbBlockSizeInQW, pbBlock); | ||||
|  | ||||
| 				MemUtil.UInt32ToBytesEx(1, pbBlockHash, NbPreHashDigestLength); | ||||
|  | ||||
| 				Blake2bLong(pbBlock, (int)NbBlockSize, pbBlockHash, | ||||
| 					NbPreHashSeedLength, h); | ||||
| 				LoadBlock(ctx.Mem, (l * ctx.LaneLength + 1UL) * NbBlockSizeInQW, pbBlock); | ||||
| 			} | ||||
|  | ||||
| 			MemUtil.ZeroByteArray(pbBlock); | ||||
| 		} | ||||
|  | ||||
| 		private static ulong IndexAlpha(Argon2Ctx ctx, Argon2ThreadInfo ti, | ||||
| 			uint uPseudoRand, bool bSameLane) | ||||
| 		{ | ||||
| 			ulong uRefAreaSize; | ||||
| 			if(ti.Pass == 0) | ||||
| 			{ | ||||
| 				if(ti.Slice == 0) | ||||
| 				{ | ||||
| 					Debug.Assert(ti.Index > 0); | ||||
| 					uRefAreaSize = ti.Index - 1UL; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					if(bSameLane) | ||||
| 						uRefAreaSize = ti.Slice * ctx.SegmentLength + | ||||
| 							ti.Index - 1UL; | ||||
| 					else | ||||
| 						uRefAreaSize = ti.Slice * ctx.SegmentLength - | ||||
| 							((ti.Index == 0UL) ? 1UL : 0UL); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if(bSameLane) | ||||
| 					uRefAreaSize = ctx.LaneLength - ctx.SegmentLength + | ||||
| 						ti.Index - 1UL; | ||||
| 				else | ||||
| 					uRefAreaSize = ctx.LaneLength - ctx.SegmentLength - | ||||
| 						((ti.Index == 0) ? 1UL : 0UL); | ||||
| 			} | ||||
| 			Debug.Assert(uRefAreaSize <= (ulong)uint.MaxValue); | ||||
|  | ||||
| 			ulong uRelPos = uPseudoRand; | ||||
| 			uRelPos = (uRelPos * uRelPos) >> 32; | ||||
| 			uRelPos = uRefAreaSize - 1UL - ((uRefAreaSize * uRelPos) >> 32); | ||||
|  | ||||
| 			ulong uStart = 0; | ||||
| 			if(ti.Pass != 0) | ||||
| 				uStart = (((ti.Slice + 1UL) == NbSyncPoints) ? 0UL : | ||||
| 					((ti.Slice + 1UL) * ctx.SegmentLength)); | ||||
| 			Debug.Assert(uStart <= (ulong)uint.MaxValue); | ||||
|  | ||||
| 			Debug.Assert(ctx.LaneLength <= (ulong)uint.MaxValue); | ||||
| 			return ((uStart + uRelPos) % ctx.LaneLength); | ||||
| 		} | ||||
|  | ||||
| 		private static void FillMemoryBlocks(Argon2Ctx ctx) | ||||
| 		{ | ||||
| 			int np = (int)ctx.Lanes; | ||||
| 			Argon2ThreadInfo[] v = new Argon2ThreadInfo[np]; | ||||
|  | ||||
| 			for(ulong r = 0; r < ctx.TCost; ++r) | ||||
| 			{ | ||||
| 				for(ulong s = 0; s < NbSyncPoints; ++s) | ||||
| 				{ | ||||
| 					for(int l = 0; l < np; ++l) | ||||
| 					{ | ||||
| 						Argon2ThreadInfo ti = new Argon2ThreadInfo(); | ||||
| 						ti.Context = ctx; | ||||
|  | ||||
| 						ti.Pass = r; | ||||
| 						ti.Lane = (ulong)l; | ||||
| 						ti.Slice = s; | ||||
|  | ||||
| 						if(!ThreadPool.QueueUserWorkItem(FillSegmentThr, ti)) | ||||
| 						{ | ||||
| 							Debug.Assert(false); | ||||
| 							throw new OutOfMemoryException(); | ||||
| 						} | ||||
|  | ||||
| 						v[l] = ti; | ||||
| 					} | ||||
|  | ||||
| 					for(int l = 0; l < np; ++l) | ||||
| 						v[l].Finished.WaitOne(); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static void FillSegmentThr(object o) | ||||
| 		{ | ||||
| 			Argon2ThreadInfo ti = (o as Argon2ThreadInfo); | ||||
| 			if(ti == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				Argon2Ctx ctx = ti.Context; | ||||
| 				if(ctx == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 				Debug.Assert(ctx.Version >= MinVersion); | ||||
| 				bool bCanXor = (ctx.Version >= 0x13U); | ||||
|  | ||||
| 				ulong uStart = 0; | ||||
| 				if((ti.Pass == 0) && (ti.Slice == 0)) uStart = 2; | ||||
|  | ||||
| 				ulong uCur = (ti.Lane * ctx.LaneLength) + (ti.Slice * | ||||
| 					ctx.SegmentLength) + uStart; | ||||
|  | ||||
| 				ulong uPrev = (((uCur % ctx.LaneLength) == 0) ? | ||||
| 					(uCur + ctx.LaneLength - 1UL) : (uCur - 1UL)); | ||||
|  | ||||
| 				ulong[] pbR = new ulong[NbBlockSizeInQW]; | ||||
| 				ulong[] pbTmp = new ulong[NbBlockSizeInQW]; | ||||
|  | ||||
| 				for(ulong i = uStart; i < ctx.SegmentLength; ++i) | ||||
| 				{ | ||||
| 					if((uCur % ctx.LaneLength) == 1) | ||||
| 						uPrev = uCur - 1UL; | ||||
|  | ||||
| 					ulong uPseudoRand = ctx.Mem[uPrev * NbBlockSizeInQW]; | ||||
| 					ulong uRefLane = (uPseudoRand >> 32) % ctx.Lanes; | ||||
| 					if((ti.Pass == 0) && (ti.Slice == 0)) | ||||
| 						uRefLane = ti.Lane; | ||||
|  | ||||
| 					ti.Index = i; | ||||
| 					ulong uRefIndex = IndexAlpha(ctx, ti, (uint)uPseudoRand, | ||||
| 						(uRefLane == ti.Lane)); | ||||
|  | ||||
| 					ulong uRefBlockIndex = (ctx.LaneLength * uRefLane + | ||||
| 						uRefIndex) * NbBlockSizeInQW; | ||||
| 					ulong uCurBlockIndex = uCur * NbBlockSizeInQW; | ||||
|  | ||||
| 					FillBlock(ctx.Mem, uPrev * NbBlockSizeInQW, uRefBlockIndex, | ||||
| 						uCurBlockIndex, ((ti.Pass != 0) && bCanXor), pbR, pbTmp); | ||||
|  | ||||
| 					++uCur; | ||||
| 					++uPrev; | ||||
| 				} | ||||
|  | ||||
| 				MemUtil.ZeroArray<ulong>(pbR); | ||||
| 				MemUtil.ZeroArray<ulong>(pbTmp); | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| 			try { ti.Finished.Set(); } | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
| 		} | ||||
|  | ||||
| #if ARGON2_B2ROUND_ARRAYS | ||||
| 		private static void InitB2RoundIndexArrays() | ||||
| 		{ | ||||
| 			int[][] vCols = g_vFBCols; | ||||
| 			if(vCols == null) | ||||
| 			{ | ||||
| 				vCols = new int[8][]; | ||||
| 				Debug.Assert(vCols.Length == 8); | ||||
| 				int e = 0; | ||||
| 				for(int i = 0; i < 8; ++i) | ||||
| 				{ | ||||
| 					vCols[i] = new int[16]; | ||||
| 					for(int j = 0; j < 16; ++j) | ||||
| 					{ | ||||
| 						vCols[i][j] = e; | ||||
| 						++e; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				g_vFBCols = vCols; | ||||
| 			} | ||||
|  | ||||
| 			int[][] vRows = g_vFBRows; | ||||
| 			if(vRows == null) | ||||
| 			{ | ||||
| 				vRows = new int[8][]; | ||||
| 				for(int i = 0; i < 8; ++i) | ||||
| 				{ | ||||
| 					vRows[i] = new int[16]; | ||||
| 					for(int j = 0; j < 16; ++j) | ||||
| 					{ | ||||
| 						int jh = j / 2; | ||||
| 						vRows[i][j] = (2 * i) + (16 * jh) + (j & 1); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				g_vFBRows = vRows; | ||||
| 			} | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		private static void FillBlock(ulong[] pMem, ulong uPrev, ulong uRef, | ||||
| 			ulong uNext, bool bXor, ulong[] pbR, ulong[] pbTmp) | ||||
| 		{ | ||||
| 			CopyBlock(pbR, 0, pMem, uRef); | ||||
| 			XorBlock(pbR, 0, pMem, uPrev); | ||||
| 			CopyBlock(pbTmp, 0, pbR, 0); | ||||
| 			if(bXor) XorBlock(pbTmp, 0, pMem, uNext); | ||||
|  | ||||
| #if ARGON2_B2ROUND_ARRAYS | ||||
| 			int[][] vCols = g_vFBCols; | ||||
| 			int[][] vRows = g_vFBRows; | ||||
| 			for(int i = 0; i < 8; ++i) | ||||
| 				Blake2RoundNoMsg(pbR, vCols[i]); | ||||
| 			for(int i = 0; i < 8; ++i) | ||||
| 				Blake2RoundNoMsg(pbR, vRows[i]); | ||||
| #else | ||||
| 			for(int i = 0; i < (8 * 16); i += 16) | ||||
| 				Blake2RoundNoMsgCols16i(pbR, i); | ||||
| 			for(int i = 0; i < (8 * 2); i += 2) | ||||
| 				Blake2RoundNoMsgRows2i(pbR, i); | ||||
| #endif | ||||
|  | ||||
| 			CopyBlock(pMem, uNext, pbTmp, 0); | ||||
| 			XorBlock(pMem, uNext, pbR, 0); | ||||
| 		} | ||||
|  | ||||
| 		private static byte[] FinalHash(Argon2Ctx ctx, int cbOut, Blake2b h) | ||||
| 		{ | ||||
| 			ulong[] pqBlockHash = new ulong[NbBlockSizeInQW]; | ||||
| 			CopyBlock(pqBlockHash, 0, ctx.Mem, (ctx.LaneLength - 1UL) * | ||||
| 				NbBlockSizeInQW); | ||||
| 			for(ulong l = 1; l < ctx.Lanes; ++l) | ||||
| 				XorBlock(pqBlockHash, 0, ctx.Mem, (l * ctx.LaneLength + | ||||
| 					ctx.LaneLength - 1UL) * NbBlockSizeInQW); | ||||
|  | ||||
| 			byte[] pbBlockHashBytes = new byte[NbBlockSize]; | ||||
| 			StoreBlock(pbBlockHashBytes, pqBlockHash); | ||||
|  | ||||
| 			byte[] pbOut = new byte[cbOut]; | ||||
| 			Blake2bLong(pbOut, cbOut, pbBlockHashBytes, (int)NbBlockSize, h); | ||||
|  | ||||
| 			MemUtil.ZeroArray<ulong>(pqBlockHash); | ||||
| 			MemUtil.ZeroByteArray(pbBlockHashBytes); | ||||
| 			return pbOut; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										144
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/Argon2Kdf.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/Argon2Kdf.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public sealed partial class Argon2Kdf : KdfEngine | ||||
| 	{ | ||||
| 		private static readonly PwUuid g_uuid = new PwUuid(new byte[] { | ||||
| 			0xEF, 0x63, 0x6D, 0xDF, 0x8C, 0x29, 0x44, 0x4B, | ||||
| 			0x91, 0xF7, 0xA9, 0xA4, 0x03, 0xE3, 0x0A, 0x0C }); | ||||
|  | ||||
| 		public const string ParamSalt = "S"; // Byte[] | ||||
| 		public const string ParamParallelism = "P"; // UInt32 | ||||
| 		public const string ParamMemory = "M"; // UInt64 | ||||
| 		public const string ParamIterations = "I"; // UInt64 | ||||
| 		public const string ParamVersion = "V"; // UInt32 | ||||
| 		public const string ParamSecretKey = "K"; // Byte[] | ||||
| 		public const string ParamAssocData = "A"; // Byte[] | ||||
|  | ||||
| 		private const uint MinVersion = 0x10; | ||||
| 		private const uint MaxVersion = 0x13; | ||||
|  | ||||
| 		private const int MinSalt = 8; | ||||
| 		private const int MaxSalt = int.MaxValue; // .NET limit; 2^32 - 1 in spec | ||||
|  | ||||
| 		internal const ulong MinIterations = 1; | ||||
| 		internal const ulong MaxIterations = uint.MaxValue; | ||||
|  | ||||
| 		internal const ulong MinMemory = 1024 * 8; // For parallelism = 1 | ||||
| 		// internal const ulong MaxMemory = (ulong)uint.MaxValue * 1024UL; // Spec | ||||
| 		internal const ulong MaxMemory = int.MaxValue; // .NET limit | ||||
|  | ||||
| 		internal const uint MinParallelism = 1; | ||||
| 		internal const uint MaxParallelism = (1 << 24) - 1; | ||||
|  | ||||
| 		internal const ulong DefaultIterations = 2; | ||||
| 		internal const ulong DefaultMemory = 1024 * 1024; // 1 MB | ||||
| 		internal const uint DefaultParallelism = 2; | ||||
|  | ||||
| 		public override PwUuid Uuid | ||||
| 		{ | ||||
| 			get { return g_uuid; } | ||||
| 		} | ||||
|  | ||||
| 		public override string Name | ||||
| 		{ | ||||
| 			get { return "Argon2"; } | ||||
| 		} | ||||
|  | ||||
| 		public Argon2Kdf() | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| 		public override KdfParameters GetDefaultParameters() | ||||
| 		{ | ||||
| 			KdfParameters p = base.GetDefaultParameters(); | ||||
|  | ||||
| 			p.SetUInt32(ParamVersion, MaxVersion); | ||||
|  | ||||
| 			p.SetUInt64(ParamIterations, DefaultIterations); | ||||
| 			p.SetUInt64(ParamMemory, DefaultMemory); | ||||
| 			p.SetUInt32(ParamParallelism, DefaultParallelism); | ||||
|  | ||||
| 			return p; | ||||
| 		} | ||||
|  | ||||
| 		public override void Randomize(KdfParameters p) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); return; } | ||||
| 			Debug.Assert(g_uuid.Equals(p.KdfUuid)); | ||||
|  | ||||
| 			byte[] pb = CryptoRandom.Instance.GetRandomBytes(32); | ||||
| 			p.SetByteArray(ParamSalt, pb); | ||||
| 		} | ||||
|  | ||||
| 		public override byte[] Transform(byte[] pbMsg, KdfParameters p) | ||||
| 		{ | ||||
| 			if(pbMsg == null) throw new ArgumentNullException("pbMsg"); | ||||
| 			if(p == null) throw new ArgumentNullException("p"); | ||||
|  | ||||
| 			byte[] pbSalt = p.GetByteArray(ParamSalt); | ||||
| 			if(pbSalt == null) | ||||
| 				throw new ArgumentNullException("p.Salt"); | ||||
| 			if((pbSalt.Length < MinSalt) || (pbSalt.Length > MaxSalt)) | ||||
| 				throw new ArgumentOutOfRangeException("p.Salt"); | ||||
|  | ||||
| 			uint uPar = p.GetUInt32(ParamParallelism, 0); | ||||
| 			if((uPar < MinParallelism) || (uPar > MaxParallelism)) | ||||
| 				throw new ArgumentOutOfRangeException("p.Parallelism"); | ||||
|  | ||||
| 			ulong uMem = p.GetUInt64(ParamMemory, 0); | ||||
| 			if((uMem < MinMemory) || (uMem > MaxMemory)) | ||||
| 				throw new ArgumentOutOfRangeException("p.Memory"); | ||||
|  | ||||
| 			ulong uIt = p.GetUInt64(ParamIterations, 0); | ||||
| 			if((uIt < MinIterations) || (uIt > MaxIterations)) | ||||
| 				throw new ArgumentOutOfRangeException("p.Iterations"); | ||||
|  | ||||
| 			uint v = p.GetUInt32(ParamVersion, 0); | ||||
| 			if((v < MinVersion) || (v > MaxVersion)) | ||||
| 				throw new ArgumentOutOfRangeException("p.Version"); | ||||
|  | ||||
| 			byte[] pbSecretKey = p.GetByteArray(ParamSecretKey); | ||||
| 			byte[] pbAssocData = p.GetByteArray(ParamAssocData); | ||||
|  | ||||
| 			byte[] pbRet = Argon2d(pbMsg, pbSalt, uPar, uMem, uIt, | ||||
| 				32, v, pbSecretKey, pbAssocData); | ||||
|  | ||||
| 			if(uMem > (100UL * 1024UL * 1024UL)) GC.Collect(); | ||||
| 			return pbRet; | ||||
| 		} | ||||
|  | ||||
| 		public override KdfParameters GetBestParameters(uint uMilliseconds) | ||||
| 		{ | ||||
| 			KdfParameters p = GetDefaultParameters(); | ||||
| 			Randomize(p); | ||||
|  | ||||
| 			MaximizeParamUInt64(p, ParamIterations, MinIterations, | ||||
| 				MaxIterations, uMilliseconds, true); | ||||
| 			return p; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										142
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/KdfEngine.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/KdfEngine.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public abstract class KdfEngine | ||||
| 	{ | ||||
| 		public abstract PwUuid Uuid | ||||
| 		{ | ||||
| 			get; | ||||
| 		} | ||||
|  | ||||
| 		public abstract string Name | ||||
| 		{ | ||||
| 			get; | ||||
| 		} | ||||
|  | ||||
| 		public virtual KdfParameters GetDefaultParameters() | ||||
| 		{ | ||||
| 			return new KdfParameters(this.Uuid); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Generate random seeds and store them in <paramref name="p" />. | ||||
| 		/// </summary> | ||||
| 		public virtual void Randomize(KdfParameters p) | ||||
| 		{ | ||||
| 			Debug.Assert(p != null); | ||||
| 			Debug.Assert(p.KdfUuid.Equals(this.Uuid)); | ||||
| 		} | ||||
|  | ||||
| 		public abstract byte[] Transform(byte[] pbMsg, KdfParameters p); | ||||
|  | ||||
| 		public virtual KdfParameters GetBestParameters(uint uMilliseconds) | ||||
| 		{ | ||||
| 			throw new NotImplementedException(); | ||||
| 		} | ||||
|  | ||||
| 		protected void MaximizeParamUInt64(KdfParameters p, string strName, | ||||
| 			ulong uMin, ulong uMax, uint uMilliseconds, bool bInterpSearch) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); return; } | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return; } | ||||
| 			if(uMin > uMax) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			if(uMax > (ulong.MaxValue >> 1)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				uMax = ulong.MaxValue >> 1; | ||||
|  | ||||
| 				if(uMin > uMax) { p.SetUInt64(strName, uMin); return; } | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbMsg = new byte[32]; | ||||
| 			for(int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = (byte)i; | ||||
|  | ||||
| 			ulong uLow = uMin; | ||||
| 			ulong uHigh = uMin + 1UL; | ||||
| 			long tLow = 0; | ||||
| 			long tHigh = 0; | ||||
| 			long tTarget = (long)uMilliseconds; | ||||
|  | ||||
| 			// Determine range | ||||
| 			while(uHigh <= uMax) | ||||
| 			{ | ||||
| 				p.SetUInt64(strName, uHigh); | ||||
|  | ||||
| 				// GC.Collect(); | ||||
| 				Stopwatch sw = Stopwatch.StartNew(); | ||||
| 				Transform(pbMsg, p); | ||||
| 				sw.Stop(); | ||||
|  | ||||
| 				tHigh = sw.ElapsedMilliseconds; | ||||
| 				if(tHigh > tTarget) break; | ||||
|  | ||||
| 				uLow = uHigh; | ||||
| 				tLow = tHigh; | ||||
| 				uHigh <<= 1; | ||||
| 			} | ||||
| 			if(uHigh > uMax) { uHigh = uMax; tHigh = 0; } | ||||
| 			if(uLow > uHigh) uLow = uHigh; // Skips to end | ||||
|  | ||||
| 			// Find optimal number of iterations | ||||
| 			while((uHigh - uLow) >= 2UL) | ||||
| 			{ | ||||
| 				ulong u = (uHigh + uLow) >> 1; // Binary search | ||||
| 				// Interpolation search, if possible | ||||
| 				if(bInterpSearch && (tLow > 0) && (tHigh > tTarget) && | ||||
| 					(tLow <= tTarget)) | ||||
| 				{ | ||||
| 					u = uLow + (((uHigh - uLow) * (ulong)(tTarget - tLow)) / | ||||
| 						(ulong)(tHigh - tLow)); | ||||
| 					if((u >= uLow) && (u <= uHigh)) | ||||
| 					{ | ||||
| 						u = Math.Max(u, uLow + 1UL); | ||||
| 						u = Math.Min(u, uHigh - 1UL); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						Debug.Assert(false); | ||||
| 						u = (uHigh + uLow) >> 1; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				p.SetUInt64(strName, u); | ||||
|  | ||||
| 				// GC.Collect(); | ||||
| 				Stopwatch sw = Stopwatch.StartNew(); | ||||
| 				Transform(pbMsg, p); | ||||
| 				sw.Stop(); | ||||
|  | ||||
| 				long t = sw.ElapsedMilliseconds; | ||||
| 				if(t == tTarget) { uLow = u; break; } | ||||
| 				else if(t > tTarget) { uHigh = u; tHigh = t; } | ||||
| 				else { uLow = u; tLow = t; } | ||||
| 			} | ||||
|  | ||||
| 			p.SetUInt64(strName, uLow); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,80 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public sealed class KdfParameters : VariantDictionary | ||||
| 	{ | ||||
| 		private const string ParamUuid = @"$UUID"; | ||||
|  | ||||
| 		private readonly PwUuid m_puKdf; | ||||
| 		public PwUuid KdfUuid | ||||
| 		{ | ||||
| 			get { return m_puKdf; } | ||||
| 		} | ||||
|  | ||||
| 		public KdfParameters(PwUuid puKdf) | ||||
| 		{ | ||||
| 			if(puKdf == null) throw new ArgumentNullException("puKdf"); | ||||
|  | ||||
| 			m_puKdf = puKdf; | ||||
| 			SetByteArray(ParamUuid, puKdf.UuidBytes); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Unsupported. | ||||
| 		/// </summary> | ||||
| 		public override object Clone() | ||||
| 		{ | ||||
| 			throw new NotSupportedException(); | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] SerializeExt(KdfParameters p) | ||||
| 		{ | ||||
| 			return VariantDictionary.Serialize(p); | ||||
| 		} | ||||
|  | ||||
| 		public static KdfParameters DeserializeExt(byte[] pb) | ||||
| 		{ | ||||
| 			VariantDictionary d = VariantDictionary.Deserialize(pb); | ||||
| 			if(d == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			byte[] pbUuid = d.GetByteArray(ParamUuid); | ||||
| 			if((pbUuid == null) || (pbUuid.Length != (int)PwUuid.UuidSize)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 			PwUuid pu = new PwUuid(pbUuid); | ||||
| 			KdfParameters p = new KdfParameters(pu); | ||||
| 			d.CopyTo(p); | ||||
| 			return p; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										96
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/KdfPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/KeePassLib2Android/Cryptography/KeyDerivation/KdfPool.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Cryptography.KeyDerivation | ||||
| { | ||||
| 	public static class KdfPool | ||||
| 	{ | ||||
| 		private static List<KdfEngine> g_l = new List<KdfEngine>(); | ||||
|  | ||||
| 		public static IEnumerable<KdfEngine> Engines | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				EnsureInitialized(); | ||||
| 				return g_l; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static void EnsureInitialized() | ||||
| 		{ | ||||
| 			if(g_l.Count > 0) return; | ||||
|  | ||||
| 			g_l.Add(new AesKdf()); | ||||
| 			g_l.Add(new Argon2Kdf()); | ||||
| 		} | ||||
|  | ||||
| 		internal static KdfParameters GetDefaultParameters() | ||||
| 		{ | ||||
| 			EnsureInitialized(); | ||||
| 			return g_l[0].GetDefaultParameters(); | ||||
| 		} | ||||
|  | ||||
| 		public static KdfEngine Get(PwUuid pu) | ||||
| 		{ | ||||
| 			if(pu == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			EnsureInitialized(); | ||||
|  | ||||
| 			foreach(KdfEngine kdf in g_l) | ||||
| 			{ | ||||
| 				if(pu.Equals(kdf.Uuid)) return kdf; | ||||
| 			} | ||||
|  | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public static KdfEngine Get(string strName) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			EnsureInitialized(); | ||||
|  | ||||
| 			foreach(KdfEngine kdf in g_l) | ||||
| 			{ | ||||
| 				if(strName.Equals(kdf.Name, StrUtil.CaseIgnoreCmp)) return kdf; | ||||
| 			} | ||||
|  | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public static void Add(KdfEngine kdf) | ||||
| 		{ | ||||
| 			if(kdf == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			EnsureInitialized(); | ||||
|  | ||||
| 			if(Get(kdf.Uuid) != null) { Debug.Assert(false); return; } | ||||
| 			if(Get(kdf.Name) != null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			g_l.Add(kdf); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -60,6 +60,18 @@ | ||||
|     </Reference> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="Collections\VariantDictionary.cs" /> | ||||
|     <Compile Include="Cryptography\Cipher\ChaCha20Cipher.cs" /> | ||||
|     <Compile Include="Cryptography\Cipher\ChaCha20Engine.cs" /> | ||||
|     <Compile Include="Cryptography\Cipher\CtrBlockCipher.cs" /> | ||||
|     <Compile Include="Cryptography\CryptoUtil.cs" /> | ||||
|     <Compile Include="Cryptography\Hash\Blake2b.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\AesKdf.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\Argon2Kdf.Core.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\Argon2Kdf.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\KdfEngine.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\KdfParameters.cs" /> | ||||
|     <Compile Include="Cryptography\KeyDerivation\KdfPool.cs" /> | ||||
|     <Compile Include="IDatabaseFormat.cs" /> | ||||
|     <Compile Include="Kp2aLog.cs" /> | ||||
|     <Compile Include="Resources\Resource.designer.cs" /> | ||||
| @@ -87,7 +99,6 @@ | ||||
|     <Compile Include="Cryptography\PasswordGenerator\PwProfile.cs" /> | ||||
|     <Compile Include="Cryptography\PopularPasswords.cs" /> | ||||
|     <Compile Include="Cryptography\QualityEstimation.cs" /> | ||||
|     <Compile Include="Cryptography\SelfTest.cs" /> | ||||
|     <Compile Include="Cryptography\PasswordGenerator\PwGenerator.cs" /> | ||||
|     <Compile Include="PwCustomIcon.cs" /> | ||||
|     <Compile Include="PwDatabase.cs" /> | ||||
| @@ -124,9 +135,13 @@ | ||||
|     <Compile Include="Serialization\FileLock.cs" /> | ||||
|     <Compile Include="Serialization\FileTransactionEx.cs" /> | ||||
|     <Compile Include="Serialization\HashedBlockStream.cs" /> | ||||
|     <Compile Include="Serialization\HmacBlockStream.cs" /> | ||||
|     <Compile Include="Serialization\IOConnection.cs"> | ||||
|       <SubType>Component</SubType> | ||||
|     </Compile> | ||||
|     <Compile Include="Serialization\IocProperties.cs" /> | ||||
|     <Compile Include="Serialization\IocPropertyInfo.cs" /> | ||||
|     <Compile Include="Serialization\IocPropertyInfoPool.cs" /> | ||||
|     <Compile Include="Serialization\KdbxFile.cs" /> | ||||
|     <Compile Include="Serialization\KdbxFile.Read.cs" /> | ||||
|     <Compile Include="Serialization\KdbxFile.Read.Streamed.cs" /> | ||||
| @@ -134,8 +149,6 @@ | ||||
|     <Compile Include="Serialization\IOConnectionInfo.cs" /> | ||||
|     <Compile Include="Serialization\OldFormatException.cs" /> | ||||
|     <Compile Include="Serialization\ProtoBuf\KdbpFile.cs" /> | ||||
|     <Compile Include="Translation\KPControlCustomization.cs" /> | ||||
|     <Compile Include="Translation\KPFormCustomization.cs" /> | ||||
|     <Compile Include="Translation\KPStringTable.cs" /> | ||||
|     <Compile Include="Translation\KPStringTableItem.cs" /> | ||||
|     <Compile Include="Translation\KPTranslation.cs" /> | ||||
| @@ -144,6 +157,7 @@ | ||||
|     <Compile Include="Utility\GfxUtil.cs" /> | ||||
|     <Compile Include="Utility\MemUtil.cs" /> | ||||
|     <Compile Include="Utility\MessageService.cs" /> | ||||
|     <Compile Include="Utility\MonoWorkarounds.cs" /> | ||||
|     <Compile Include="Utility\StrUtil.cs" /> | ||||
|     <Compile Include="Utility\UrlUtil.cs" /> | ||||
|     <Compile Include="Utility\TimeUtil.cs" /> | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,22 +18,16 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Text; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Security.Cryptography; | ||||
|  | ||||
| #if KeePassRT | ||||
| using Org.BouncyCastle.Crypto.Engines; | ||||
| using Org.BouncyCastle.Crypto.Parameters; | ||||
| #endif | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.KeyDerivation; | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Utility; | ||||
| using keepass2android; | ||||
|  | ||||
| namespace KeePassLib.Keys | ||||
| { | ||||
| @@ -109,7 +103,6 @@ namespace KeePassLib.Keys | ||||
| 			return m_vUserKeys.Remove(pKey); | ||||
| 		} | ||||
|  | ||||
| #if !KeePassRT | ||||
| 		/// <summary> | ||||
| 		/// Test whether the composite key contains a specific type of | ||||
| 		/// user keys (password, key file, ...). If at least one user | ||||
| @@ -125,8 +118,15 @@ namespace KeePassLib.Keys | ||||
|  | ||||
| 			foreach(IUserKey pKey in m_vUserKeys) | ||||
| 			{ | ||||
| 				if(pKey == null) { Debug.Assert(false); continue; } | ||||
|  | ||||
| #if KeePassUAP | ||||
| 				if(pKey.GetType() == tUserKeyType) | ||||
| 					return true; | ||||
| #else | ||||
| 				if(tUserKeyType.IsInstanceOfType(pKey)) | ||||
| 					return true; | ||||
| #endif | ||||
| 			} | ||||
|  | ||||
| 			return false; | ||||
| @@ -145,8 +145,15 @@ namespace KeePassLib.Keys | ||||
|  | ||||
| 			foreach(IUserKey pKey in m_vUserKeys) | ||||
| 			{ | ||||
| 				if(pKey == null) { Debug.Assert(false); continue; } | ||||
|  | ||||
| #if KeePassUAP | ||||
| 				if(pKey.GetType() == tUserKeyType) | ||||
| 					return pKey; | ||||
| #else | ||||
| 				if(tUserKeyType.IsInstanceOfType(pKey)) | ||||
| 					return pKey; | ||||
| #endif | ||||
| 			} | ||||
|  | ||||
| 			return null; | ||||
| @@ -156,8 +163,6 @@ namespace KeePassLib.Keys | ||||
| 		{ | ||||
| 			return (T) GetUserKey(typeof (T)); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Creates the composite key from the supplied user key sources (password, | ||||
| 		/// key file, user account, computer ID, etc.). | ||||
| @@ -167,21 +172,31 @@ namespace KeePassLib.Keys | ||||
| 			ValidateUserKeys(); | ||||
|  | ||||
| 			// Concatenate user key data | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
| 			List<byte[]> lData = new List<byte[]>(); | ||||
| 			int cbData = 0; | ||||
| 			foreach(IUserKey pKey in m_vUserKeys) | ||||
| 			{ | ||||
| 				ProtectedBinary b = pKey.KeyData; | ||||
| 				if(b != null) | ||||
| 				{ | ||||
| 					byte[] pbKeyData = b.ReadData(); | ||||
| 					ms.Write(pbKeyData, 0, pbKeyData.Length); | ||||
| 					MemUtil.ZeroByteArray(pbKeyData); | ||||
| 					lData.Add(pbKeyData); | ||||
| 					cbData += pbKeyData.Length; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			byte[] pbHash = sha256.ComputeHash(ms.ToArray()); | ||||
| 			ms.Close(); | ||||
| 			byte[] pbAllData = new byte[cbData]; | ||||
| 			int p = 0; | ||||
| 			foreach(byte[] pbData in lData) | ||||
| 			{ | ||||
| 				Array.Copy(pbData, 0, pbAllData, p, pbData.Length); | ||||
| 				p += pbData.Length; | ||||
| 				MemUtil.ZeroByteArray(pbData); | ||||
| 			} | ||||
| 			Debug.Assert(p == cbData); | ||||
|  | ||||
| 			byte[] pbHash = CryptoUtil.HashSha256(pbAllData); | ||||
| 			MemUtil.ZeroByteArray(pbAllData); | ||||
| 			return pbHash; | ||||
| 		} | ||||
|  | ||||
| @@ -192,21 +207,13 @@ namespace KeePassLib.Keys | ||||
| 			byte[] pbThis = CreateRawCompositeKey32(); | ||||
| 			byte[] pbOther = ckOther.CreateRawCompositeKey32(); | ||||
| 			bool bResult = MemUtil.ArraysEqual(pbThis, pbOther); | ||||
| 			Array.Clear(pbOther, 0, pbOther.Length); | ||||
| 			Array.Clear(pbThis, 0, pbThis.Length); | ||||
| 			MemUtil.ZeroByteArray(pbOther); | ||||
| 			MemUtil.ZeroByteArray(pbThis); | ||||
|  | ||||
| 			return bResult; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Generate a 32-bit wide key out of the composite key. | ||||
| 		/// </summary> | ||||
| 		/// <param name="pbKeySeed32">Seed used in the key transformation | ||||
| 		/// rounds. Must be a byte array containing exactly 32 bytes; must | ||||
| 		/// not be null.</param> | ||||
| 		/// <param name="uNumRounds">Number of key transformation rounds.</param> | ||||
| 		/// <returns>Returns a protected binary object that contains the | ||||
| 		/// resulting 32-bit wide key.</returns> | ||||
| 		[Obsolete] | ||||
| 		public ProtectedBinary GenerateKey32(byte[] pbKeySeed32, ulong uNumRounds) | ||||
| 		{ | ||||
| 			Debug.Assert(pbKeySeed32 != null); | ||||
| @@ -214,18 +221,43 @@ namespace KeePassLib.Keys | ||||
| 			Debug.Assert(pbKeySeed32.Length == 32); | ||||
| 			if(pbKeySeed32.Length != 32) throw new ArgumentException("pbKeySeed32"); | ||||
|  | ||||
| 			AesKdf kdf = new AesKdf(); | ||||
| 			KdfParameters p = kdf.GetDefaultParameters(); | ||||
| 			p.SetUInt64(AesKdf.ParamRounds, uNumRounds); | ||||
| 			p.SetByteArray(AesKdf.ParamSeed, pbKeySeed32); | ||||
|  | ||||
| 			return GenerateKey32(p); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Generate a 32-byte (256-bit) key from the composite key. | ||||
| 		/// </summary> | ||||
| 		public ProtectedBinary GenerateKey32(KdfParameters p) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); throw new ArgumentNullException("p"); } | ||||
|  | ||||
| 			byte[] pbRaw32 = CreateRawCompositeKey32(); | ||||
| 			if((pbRaw32 == null) || (pbRaw32.Length != 32)) | ||||
| 				{ Debug.Assert(false); return null; } | ||||
|  | ||||
| 			byte[] pbTrf32 = TransformKey(pbRaw32, pbKeySeed32, uNumRounds); | ||||
| 			if((pbTrf32 == null) || (pbTrf32.Length != 32)) | ||||
| 				{ Debug.Assert(false); return null; } | ||||
| 			KdfEngine kdf = KdfPool.Get(p.KdfUuid); | ||||
| 			if(kdf == null) // CryptographicExceptions are translated to "file corrupted" | ||||
| 				throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph + | ||||
| 					KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph + | ||||
| 					"UUID: " + p.KdfUuid.ToHexString() + "."); | ||||
|  | ||||
| 			byte[] pbTrf32 = kdf.Transform(pbRaw32, p); | ||||
| 			if(pbTrf32 == null) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			if(pbTrf32.Length != 32) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				pbTrf32 = CryptoUtil.HashSha256(pbTrf32); | ||||
| 			} | ||||
|  | ||||
| 			ProtectedBinary pbRet = new ProtectedBinary(true, pbTrf32); | ||||
| 			MemUtil.ZeroByteArray(pbTrf32); | ||||
| 			MemUtil.ZeroByteArray(pbRaw32); | ||||
|  | ||||
| 			return pbRet; | ||||
| 		} | ||||
|  | ||||
| @@ -245,192 +277,6 @@ namespace KeePassLib.Keys | ||||
| 				throw new InvalidOperationException(); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Transform the current key <c>uNumRounds</c> times. | ||||
| 		/// </summary> | ||||
| 		/// <param name="pbOriginalKey32">The original key which will be transformed. | ||||
| 		/// This parameter won't be modified.</param> | ||||
| 		/// <param name="pbKeySeed32">Seed used for key transformations. Must not | ||||
| 		/// be <c>null</c>. This parameter won't be modified.</param> | ||||
| 		/// <param name="uNumRounds">Transformation count.</param> | ||||
| 		/// <returns>256-bit transformed key.</returns> | ||||
| 		private static byte[] TransformKey(byte[] pbOriginalKey32, byte[] pbKeySeed32, | ||||
| 			ulong uNumRounds) | ||||
| 		{ | ||||
| 			Debug.Assert((pbOriginalKey32 != null) && (pbOriginalKey32.Length == 32)); | ||||
| 			if (pbOriginalKey32 == null) | ||||
| 				throw new ArgumentNullException("pbOriginalKey32"); | ||||
| 			if (pbOriginalKey32.Length != 32) | ||||
| 				throw new ArgumentException(); | ||||
|  | ||||
| 			Debug.Assert((pbKeySeed32 != null) && (pbKeySeed32.Length == 32)); | ||||
| 			if (pbKeySeed32 == null) | ||||
| 				throw new ArgumentNullException("pbKeySeed32"); | ||||
| 			if (pbKeySeed32.Length != 32) | ||||
| 				throw new ArgumentException(); | ||||
|  | ||||
| 			byte[] pbNewKey = new byte[32]; | ||||
| 			Array.Copy(pbOriginalKey32, pbNewKey, pbNewKey.Length); | ||||
|  | ||||
| 			// Try to use the native library first | ||||
| 			Stopwatch sw = new Stopwatch(); | ||||
| 			sw.Start(); | ||||
| 			if (NativeLib.TransformKey256(pbNewKey, pbKeySeed32, uNumRounds)) | ||||
| 			{ | ||||
| 				sw.Stop(); | ||||
| 				Kp2aLog.Log("Native transform:" +sw.ElapsedMilliseconds+"ms"); | ||||
| 				return pbNewKey; | ||||
| 			} | ||||
|  | ||||
| 			sw.Restart(); | ||||
| 			if(TransformKeyManaged(pbNewKey, pbKeySeed32, uNumRounds) == false) | ||||
| 				return null; | ||||
| 			sw.Stop(); | ||||
| 			Kp2aLog.Log("Managed transform:" +sw.ElapsedMilliseconds+"ms"); | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			return sha256.ComputeHash(pbNewKey); | ||||
| 		} | ||||
|  | ||||
| 		public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, | ||||
| 			ulong uNumRounds) | ||||
| 		{ | ||||
| #if KeePassRT | ||||
| 			KeyParameter kp = new KeyParameter(pbKeySeed32); | ||||
| 			AesEngine aes = new AesEngine(); | ||||
| 			aes.Init(true, kp); | ||||
|  | ||||
| 			for(ulong i = 0; i < uNumRounds; ++i) | ||||
| 			{ | ||||
| 				aes.ProcessBlock(pbNewKey32, 0, pbNewKey32, 0); | ||||
| 				aes.ProcessBlock(pbNewKey32, 16, pbNewKey32, 16); | ||||
| 			} | ||||
| #else | ||||
| 			byte[] pbIV = new byte[16]; | ||||
| 			Array.Clear(pbIV, 0, pbIV.Length); | ||||
|  | ||||
| 			RijndaelManaged r = new RijndaelManaged(); | ||||
| 			if(r.BlockSize != 128) // AES block size | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				r.BlockSize = 128; | ||||
| 			} | ||||
|  | ||||
| 			r.IV = pbIV; | ||||
| 			r.Mode = CipherMode.ECB; | ||||
| 			r.KeySize = 256; | ||||
| 			r.Key = pbKeySeed32; | ||||
| 			ICryptoTransform iCrypt = r.CreateEncryptor(); | ||||
|  | ||||
| 			// !iCrypt.CanReuseTransform -- doesn't work with Mono | ||||
| 			if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || | ||||
| 				(iCrypt.OutputBlockSize != 16)) | ||||
| 			{ | ||||
| 				Debug.Assert(false, "Invalid ICryptoTransform."); | ||||
| 				Debug.Assert((iCrypt.InputBlockSize == 16), "Invalid input block size!"); | ||||
| 				Debug.Assert((iCrypt.OutputBlockSize == 16), "Invalid output block size!"); | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			for(ulong i = 0; i < uNumRounds; ++i) | ||||
| 			{ | ||||
| 				iCrypt.TransformBlock(pbNewKey32, 0, 16, pbNewKey32, 0); | ||||
| 				iCrypt.TransformBlock(pbNewKey32, 16, 16, pbNewKey32, 16); | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Benchmark the <c>TransformKey</c> method. Within | ||||
| 		/// <paramref name="uMilliseconds"/> ms, random keys will be transformed | ||||
| 		/// and the number of performed transformations are returned. | ||||
| 		/// </summary> | ||||
| 		/// <param name="uMilliseconds">Test duration in ms.</param> | ||||
| 		/// <param name="uStep">Stepping. | ||||
| 		/// <paramref name="uStep" /> should be a prime number. For fast processors | ||||
| 		/// (PCs) a value of <c>3001</c> is recommended, for slower processors (PocketPC) | ||||
| 		/// a value of <c>401</c> is recommended.</param> | ||||
| 		/// <returns>Number of transformations performed in the specified | ||||
| 		/// amount of time. Maximum value is <c>uint.MaxValue</c>.</returns> | ||||
| 		public static ulong TransformKeyBenchmark(uint uMilliseconds, ulong uStep) | ||||
| 		{ | ||||
| 			ulong uRounds; | ||||
|  | ||||
| 			// Try native method | ||||
| 			if(NativeLib.TransformKeyBenchmark256(uMilliseconds, out uRounds)) | ||||
| 				return uRounds; | ||||
|  | ||||
| 			byte[] pbKey = new byte[32]; | ||||
| 			byte[] pbNewKey = new byte[32]; | ||||
| 			for(int i = 0; i < pbKey.Length; ++i) | ||||
| 			{ | ||||
| 				pbKey[i] = (byte)i; | ||||
| 				pbNewKey[i] = (byte)i; | ||||
| 			} | ||||
|  | ||||
| #if KeePassRT | ||||
| 			KeyParameter kp = new KeyParameter(pbKey); | ||||
| 			AesEngine aes = new AesEngine(); | ||||
| 			aes.Init(true, kp); | ||||
| #else | ||||
| 			byte[] pbIV = new byte[16]; | ||||
| 			Array.Clear(pbIV, 0, pbIV.Length); | ||||
|  | ||||
| 			RijndaelManaged r = new RijndaelManaged(); | ||||
| 			if(r.BlockSize != 128) // AES block size | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				r.BlockSize = 128; | ||||
| 			} | ||||
|  | ||||
| 			r.IV = pbIV; | ||||
| 			r.Mode = CipherMode.ECB; | ||||
| 			r.KeySize = 256; | ||||
| 			r.Key = pbKey; | ||||
| 			ICryptoTransform iCrypt = r.CreateEncryptor(); | ||||
|  | ||||
| 			// !iCrypt.CanReuseTransform -- doesn't work with Mono | ||||
| 			if((iCrypt == null) || (iCrypt.InputBlockSize != 16) || | ||||
| 				(iCrypt.OutputBlockSize != 16)) | ||||
| 			{ | ||||
| 				Debug.Assert(false, "Invalid ICryptoTransform."); | ||||
| 				Debug.Assert(iCrypt.InputBlockSize == 16, "Invalid input block size!"); | ||||
| 				Debug.Assert(iCrypt.OutputBlockSize == 16, "Invalid output block size!"); | ||||
| 				return PwDefs.DefaultKeyEncryptionRounds; | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			uRounds = 0; | ||||
| 			int tStart = Environment.TickCount; | ||||
| 			while(true) | ||||
| 			{ | ||||
| 				for(ulong j = 0; j < uStep; ++j) | ||||
| 				{ | ||||
| #if KeePassRT | ||||
| 					aes.ProcessBlock(pbNewKey, 0, pbNewKey, 0); | ||||
| 					aes.ProcessBlock(pbNewKey, 16, pbNewKey, 16); | ||||
| #else | ||||
| 					iCrypt.TransformBlock(pbNewKey, 0, 16, pbNewKey, 0); | ||||
| 					iCrypt.TransformBlock(pbNewKey, 16, 16, pbNewKey, 16); | ||||
| #endif | ||||
| 				} | ||||
|  | ||||
| 				uRounds += uStep; | ||||
| 				if(uRounds < uStep) // Overflow check | ||||
| 				{ | ||||
| 					uRounds = ulong.MaxValue; | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				uint tElapsed = (uint)(Environment.TickCount - tStart); | ||||
| 				if(tElapsed > uMilliseconds) break; | ||||
| 			} | ||||
|  | ||||
| 			return uRounds; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public sealed class InvalidCompositeKeyException : Exception | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -20,12 +18,15 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Xml; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Security; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Resources; | ||||
| @@ -103,12 +104,12 @@ namespace KeePassLib.Keys | ||||
| 			if (pbFileData == null) throw new Java.IO.FileNotFoundException(); | ||||
| 			m_pbFileData = new ProtectedBinary(true, pbFileData); | ||||
|  | ||||
| 			if (bThrowIfDbFile && (pbFileData.Length >= 8)) | ||||
| 			if(bThrowIfDbFile && (pbFileData.Length >= 8)) | ||||
| 			{ | ||||
| 				uint uSig1 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 0, 4)); | ||||
| 				uint uSig2 = MemUtil.BytesToUInt32(MemUtil.Mid(pbFileData, 4, 4)); | ||||
|  | ||||
| 				if (((uSig1 == KdbxFile.FileSignature1) && | ||||
| 				if(((uSig1 == KdbxFile.FileSignature1) && | ||||
| 					(uSig2 == KdbxFile.FileSignature2)) || | ||||
| 					((uSig1 == KdbxFile.FileSignaturePreRelease1) && | ||||
| 					(uSig2 == KdbxFile.FileSignaturePreRelease2)) || | ||||
| @@ -122,9 +123,9 @@ namespace KeePassLib.Keys | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbKey = LoadXmlKeyFile(pbFileData); | ||||
| 			if (pbKey == null) pbKey = LoadKeyFile(pbFileData); | ||||
| 			if(pbKey == null) pbKey = LoadKeyFile(pbFileData); | ||||
|  | ||||
| 			if (pbKey == null) throw new InvalidOperationException(); | ||||
| 			if(pbKey == null) throw new InvalidOperationException(); | ||||
|  | ||||
| 			m_ioc = iocKeyFile; | ||||
| 			m_pbKeyData = new ProtectedBinary(true, pbKey); | ||||
| @@ -137,13 +138,13 @@ namespace KeePassLib.Keys | ||||
| 			byte[] pbFileData = IOConnection.ReadFile(iocFile); | ||||
| 			Construct(pbFileData, iocFile, bThrowIfDbFile); | ||||
| 		} | ||||
|  | ||||
| 		// public void Clear() | ||||
| 		// { | ||||
| 		//	m_strPath = string.Empty; | ||||
| 		//	m_pbKeyData = null; | ||||
| 		// } | ||||
|  | ||||
|  | ||||
| 		private static byte[] LoadKeyFile(byte[] pbFileData) | ||||
| 		{ | ||||
| 			if(pbFileData == null) { Debug.Assert(false); return null; } | ||||
| @@ -155,10 +156,7 @@ namespace KeePassLib.Keys | ||||
| 			else if(iLength == 64) pbKey = LoadHexKey32(pbFileData); | ||||
|  | ||||
| 			if(pbKey == null) | ||||
| 			{ | ||||
| 				SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				pbKey = sha256.ComputeHash(pbFileData); | ||||
| 			} | ||||
| 				pbKey = CryptoUtil.HashSha256(pbFileData); | ||||
|  | ||||
| 			return pbKey; | ||||
| 		} | ||||
| @@ -178,12 +176,15 @@ namespace KeePassLib.Keys | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				string strHex = StrUtil.Utf8.GetString(pbFileData, 0, 64); | ||||
| 				if(!StrUtil.IsHexString(strHex, true)) return null; | ||||
| 				if(!StrUtil.IsHexString(pbFileData, true)) return null; | ||||
|  | ||||
| 				string strHex = StrUtil.Utf8.GetString(pbFileData); | ||||
| 				byte[] pbKey = MemUtil.HexStringToByteArray(strHex); | ||||
| 				if((pbKey == null) || (pbKey.Length != 32)) | ||||
| 				{ | ||||
| 					Debug.Assert(false); | ||||
| 					return null; | ||||
| 				} | ||||
|  | ||||
| 				return pbKey; | ||||
| 			} | ||||
| @@ -211,13 +212,13 @@ namespace KeePassLib.Keys | ||||
| 				pbFinalKey32 = pbKey32; | ||||
| 			else | ||||
| 			{ | ||||
| 				MemoryStream ms = new MemoryStream(); | ||||
| 				ms.Write(pbAdditionalEntropy, 0, pbAdditionalEntropy.Length); | ||||
| 				ms.Write(pbKey32, 0, 32); | ||||
| 				using(MemoryStream ms = new MemoryStream()) | ||||
| 				{ | ||||
| 					MemUtil.Write(ms, pbAdditionalEntropy); | ||||
| 					MemUtil.Write(ms, pbKey32); | ||||
|  | ||||
| 				SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				pbFinalKey32 = sha256.ComputeHash(ms.ToArray()); | ||||
| 				ms.Close(); | ||||
| 					pbFinalKey32 = CryptoUtil.HashSha256(ms.ToArray()); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			CreateXmlKeyFile(strFilePath, pbFinalKey32); | ||||
| @@ -292,7 +293,15 @@ namespace KeePassLib.Keys | ||||
| 			IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFile); | ||||
| 			Stream sOut = IOConnection.OpenWrite(ioc); | ||||
|  | ||||
| #if KeePassUAP | ||||
| 			XmlWriterSettings xws = new XmlWriterSettings(); | ||||
| 			xws.Encoding = StrUtil.Utf8; | ||||
| 			xws.Indent = false; | ||||
|  | ||||
| 			XmlWriter xtw = XmlWriter.Create(sOut, xws); | ||||
| #else | ||||
| 			XmlTextWriter xtw = new XmlTextWriter(sOut, StrUtil.Utf8); | ||||
| #endif | ||||
|  | ||||
| 			xtw.WriteStartDocument(); | ||||
| 			xtw.WriteWhitespace("\r\n"); | ||||
| @@ -334,6 +343,6 @@ namespace KeePassLib.Keys | ||||
| 		public void ResetIoc(IOConnectionInfo newIoc) | ||||
| 		{ | ||||
| 			m_ioc = newIoc; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,10 +18,10 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Text; | ||||
| using System.Diagnostics; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| @@ -68,8 +68,11 @@ namespace KeePassLib.Keys | ||||
| 			Debug.Assert(pbPasswordUtf8 != null); | ||||
| 			if(pbPasswordUtf8 == null) throw new ArgumentNullException("pbPasswordUtf8"); | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			byte[] pbRaw = sha256.ComputeHash(pbPasswordUtf8); | ||||
| #if (DEBUG && !KeePassLibSD) | ||||
| 			Debug.Assert(ValidatePassword(pbPasswordUtf8)); | ||||
| #endif | ||||
|  | ||||
| 			byte[] pbRaw = CryptoUtil.HashSha256(pbPasswordUtf8); | ||||
|  | ||||
| 			m_psPassword = new ProtectedString(true, pbPasswordUtf8); | ||||
| 			m_pbKeyData = new ProtectedBinary(true, pbRaw); | ||||
| @@ -80,5 +83,19 @@ namespace KeePassLib.Keys | ||||
| 		//	m_psPassword = null; | ||||
| 		//	m_pbKeyData = null; | ||||
| 		// } | ||||
|  | ||||
| #if (DEBUG && !KeePassLibSD) | ||||
| 		private static bool ValidatePassword(byte[] pb) | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				string str = StrUtil.Utf8.GetString(pb); | ||||
| 				return str.IsNormalized(NormalizationForm.FormC); | ||||
| 	} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| 			return false; | ||||
| } | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|  | ||||
| @@ -20,9 +20,13 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Security; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Resources; | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,12 +19,19 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Threading; | ||||
| using System.Diagnostics; | ||||
| using Android.Util; | ||||
| using KeePassLib.Utility; | ||||
| using System.Reflection; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
| using System.Text.RegularExpressions; | ||||
| using Java.Text; | ||||
| using keepass2android; | ||||
| #if !KeePassUAP | ||||
| using System.IO; | ||||
| using System.Threading; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Native | ||||
| { | ||||
| @@ -48,6 +53,61 @@ namespace KeePassLib.Native | ||||
| 			set { m_bAllowNative = value; } | ||||
| 		} | ||||
|  | ||||
| 		private static int? g_oiPointerSize = null; | ||||
| 		/// <summary> | ||||
| 		/// Size of a native pointer (in bytes). | ||||
| 		/// </summary> | ||||
| 		public static int PointerSize | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(!g_oiPointerSize.HasValue) | ||||
| #if KeePassUAP | ||||
| 					g_oiPointerSize = Marshal.SizeOf<IntPtr>(); | ||||
| #else | ||||
| 					g_oiPointerSize = Marshal.SizeOf(typeof(IntPtr)); | ||||
| #endif | ||||
| 				return g_oiPointerSize.Value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static ulong? m_ouMonoVersion = null; | ||||
| 		public static ulong MonoVersion | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_ouMonoVersion.HasValue) return m_ouMonoVersion.Value; | ||||
|  | ||||
| 				ulong uVersion = 0; | ||||
| 				try | ||||
| 				{ | ||||
| 					Type t = Type.GetType("Mono.Runtime"); | ||||
| 					if(t != null) | ||||
| 					{ | ||||
| 						MethodInfo mi = t.GetMethod("GetDisplayName", | ||||
| 							BindingFlags.NonPublic | BindingFlags.Static); | ||||
| 						if(mi != null) | ||||
| 						{ | ||||
| 							string strName = (mi.Invoke(null, null) as string); | ||||
| 							if(!string.IsNullOrEmpty(strName)) | ||||
| 							{ | ||||
| 								Match m = Regex.Match(strName, "\\d+(\\.\\d+)+"); | ||||
| 								if(m.Success) | ||||
| 									uVersion = StrUtil.ParseVersion(m.Value); | ||||
| 								else { Debug.Assert(false); } | ||||
| 							} | ||||
| 							else { Debug.Assert(false); } | ||||
| 						} | ||||
| 						else { Debug.Assert(false); } | ||||
| 					} | ||||
| 				} | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| 				m_ouMonoVersion = uVersion; | ||||
| 				return uVersion; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Determine if the native library is installed. | ||||
| 		/// </summary> | ||||
| @@ -91,15 +151,15 @@ namespace KeePassLib.Native | ||||
| 		{ | ||||
| 			if(m_platID.HasValue) return m_platID.Value; | ||||
|  | ||||
| #if KeePassRT | ||||
| 			m_platID = PlatformID.Win32NT; | ||||
| #if KeePassUAP | ||||
| 			m_platID = EnvironmentExt.OSVersion.Platform; | ||||
| #else | ||||
| 			m_platID = Environment.OSVersion.Platform; | ||||
| #endif | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			/*// Mono returns PlatformID.Unix on Mac OS X, workaround this | ||||
| 			//fails on Anroid | ||||
| 			//not supported on Mono | ||||
| 			if(m_platID.Value == PlatformID.Unix) | ||||
| 			{ | ||||
| 				if((RunConsoleApp("uname", null) ?? string.Empty).Trim().Equals( | ||||
| @@ -111,7 +171,111 @@ namespace KeePassLib.Native | ||||
| 			return m_platID.Value; | ||||
| 		} | ||||
|  | ||||
| 		private static DesktopType? m_tDesktop = null; | ||||
| 		public static DesktopType GetDesktopType() | ||||
| 		{ | ||||
| 			if(!m_tDesktop.HasValue) | ||||
| 			{ | ||||
| 				DesktopType t = DesktopType.None; | ||||
| 				if(!IsUnix()) t = DesktopType.Windows; | ||||
| 				else | ||||
| 				{ | ||||
| 					try | ||||
| 					{ | ||||
| 						string strXdg = (Environment.GetEnvironmentVariable( | ||||
| 							"XDG_CURRENT_DESKTOP") ?? string.Empty).Trim(); | ||||
| 						string strGdm = (Environment.GetEnvironmentVariable( | ||||
| 							"GDMSESSION") ?? string.Empty).Trim(); | ||||
| 						StringComparison sc = StrUtil.CaseIgnoreCmp; | ||||
|  | ||||
| 						if(strXdg.Equals("Unity", sc)) | ||||
| 							t = DesktopType.Unity; | ||||
| 						else if(strXdg.Equals("LXDE", sc)) | ||||
| 							t = DesktopType.Lxde; | ||||
| 						else if(strXdg.Equals("XFCE", sc)) | ||||
| 							t = DesktopType.Xfce; | ||||
| 						else if(strXdg.Equals("MATE", sc)) | ||||
| 							t = DesktopType.Mate; | ||||
| 						else if(strXdg.Equals("X-Cinnamon", sc)) | ||||
| 							t = DesktopType.Cinnamon; | ||||
| 						else if(strXdg.Equals("Pantheon", sc)) // Elementary OS | ||||
| 							t = DesktopType.Pantheon; | ||||
| 						else if(strXdg.Equals("KDE", sc) || // Mint 16 | ||||
| 							strGdm.Equals("kde-plasma", sc)) // Ubuntu 12.04 | ||||
| 							t = DesktopType.Kde; | ||||
| 						else if(strXdg.Equals("GNOME", sc)) | ||||
| 						{ | ||||
| 							if(strGdm.Equals("cinnamon", sc)) // Mint 13 | ||||
| 								t = DesktopType.Cinnamon; | ||||
| 							else t = DesktopType.Gnome; | ||||
| 						} | ||||
| 					} | ||||
| 					catch(Exception) { Debug.Assert(false); } | ||||
| 				} | ||||
|  | ||||
| 				m_tDesktop = t; | ||||
| 			} | ||||
|  | ||||
| 			return m_tDesktop.Value; | ||||
| 		} | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 		/* Not supported on Android | ||||
| 		public static string RunConsoleApp(string strAppPath, string strParams) | ||||
| 		{ | ||||
| 			return RunConsoleApp(strAppPath, strParams, null); | ||||
| 		} | ||||
| 		public static string RunConsoleApp(string strAppPath, string strParams, | ||||
| 			string strStdInput) | ||||
| 		{ | ||||
| 			return RunConsoleApp(strAppPath, strParams, strStdInput, | ||||
| 				(AppRunFlags.GetStdOutput | AppRunFlags.WaitForExit)); | ||||
| 		} | ||||
| 		*/ | ||||
| 		private delegate string RunProcessDelegate(); | ||||
|  | ||||
| 		private static void EnsureNoBom(StreamWriter sw) | ||||
| 		{ | ||||
| 			if(sw == null) { Debug.Assert(false); return; } | ||||
| 			if(!MonoWorkarounds.IsRequired(1219)) return; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				Encoding enc = sw.Encoding; | ||||
| 				if(enc == null) { Debug.Assert(false); return; } | ||||
| 				byte[] pbBom = enc.GetPreamble(); | ||||
| 				if((pbBom == null) || (pbBom.Length == 0)) return; | ||||
|  | ||||
| 				// For Mono >= 4.0 (using Microsoft's reference source) | ||||
| 				try | ||||
| 				{ | ||||
| 					FieldInfo fi = typeof(StreamWriter).GetField("haveWrittenPreamble", | ||||
| 						BindingFlags.Instance | BindingFlags.NonPublic); | ||||
| 					if(fi != null) | ||||
| 					{ | ||||
| 						fi.SetValue(sw, true); | ||||
| 						return; | ||||
| 					} | ||||
| 				} | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| 				// For Mono < 4.0 | ||||
| 				FieldInfo fiPD = typeof(StreamWriter).GetField("preamble_done", | ||||
| 					BindingFlags.Instance | BindingFlags.NonPublic); | ||||
| 				if(fiPD != null) fiPD.SetValue(sw, true); | ||||
| 				else { Debug.Assert(false); } | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Transform a key. | ||||
| 		/// </summary> | ||||
| 		/// <param name="pBuf256">Source and destination buffer.</param> | ||||
| 		/// <param name="pKey256">Key to use in the transformation.</param> | ||||
| 		/// <param name="uRounds">Number of transformation rounds.</param> | ||||
| 		/// <returns>Returns <c>true</c>, if the key was transformed successfully.</returns> | ||||
| 		/// <summary> | ||||
| 		/// Transform a key. | ||||
| 		/// </summary> | ||||
| @@ -122,7 +286,7 @@ namespace KeePassLib.Native | ||||
| 		public static bool TransformKey256(byte[] pBuf256, byte[] pKey256, | ||||
| 			ulong uRounds) | ||||
| 		{ | ||||
| 			if(m_bAllowNative == false) return false; | ||||
| 			if (m_bAllowNative == false) return false; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| @@ -136,10 +300,10 @@ namespace KeePassLib.Native | ||||
| 				return false; | ||||
| #endif | ||||
| 			} | ||||
| 			catch(Exception e) | ||||
| 			catch (Exception e) | ||||
| 			{ | ||||
| 				Kp2aLog.Log(e.Message); | ||||
| 				return false;  | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| @@ -148,19 +312,23 @@ namespace KeePassLib.Native | ||||
| 		/// <summary> | ||||
| 		/// Benchmark key transformation. | ||||
| 		/// </summary> | ||||
| 		/// <param name="uTimeMs">Number of seconds to perform the benchmark.</param> | ||||
| 		/// <param name="uTimeMs">Number of milliseconds to perform the benchmark.</param> | ||||
| 		/// <param name="puRounds">Number of transformations done.</param> | ||||
| 		/// <returns>Returns <c>true</c>, if the benchmark was successful.</returns> | ||||
| 		public static bool TransformKeyBenchmark256(uint uTimeMs, out ulong puRounds) | ||||
| 		{ | ||||
| 			puRounds = 0; | ||||
|  | ||||
| 			if(m_bAllowNative == false) return false; | ||||
| #if KeePassUAP | ||||
| 			return false; | ||||
| #else | ||||
| 			if(!m_bAllowNative) return false; | ||||
|  | ||||
| 			try { puRounds = NativeMethods.TransformKeyBenchmark(uTimeMs); } | ||||
| 			catch(Exception) { return false; } | ||||
|  | ||||
| 			return true; | ||||
| #endif | ||||
| 		} | ||||
|  | ||||
| 		private static KeyValuePair<IntPtr, IntPtr> PrepareArrays256(byte[] pBuf256, | ||||
|   | ||||
							
								
								
									
										115
									
								
								src/KeePassLib2Android/Native/NativeMethods.Unix.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/KeePassLib2Android/Native/NativeMethods.Unix.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Reflection; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Windows.Forms; | ||||
| #endif | ||||
|  | ||||
| namespace KeePassLib.Native | ||||
| { | ||||
| 	internal static partial class NativeMethods | ||||
| 	{ | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 		[StructLayout(LayoutKind.Sequential)] | ||||
| 		private struct XClassHint | ||||
| 		{ | ||||
| 			public IntPtr res_name; | ||||
| 			public IntPtr res_class; | ||||
| 		} | ||||
|  | ||||
| 		[DllImport("libX11")] | ||||
| 		private static extern int XSetClassHint(IntPtr display, IntPtr window, IntPtr class_hints); | ||||
|  | ||||
| 		private static Type m_tXplatUIX11 = null; | ||||
| 		private static Type GetXplatUIX11Type(bool bThrowOnError) | ||||
| 		{ | ||||
| 			if(m_tXplatUIX11 == null) | ||||
| 			{ | ||||
| 				// CheckState is in System.Windows.Forms | ||||
| 				string strTypeCS = typeof(CheckState).AssemblyQualifiedName; | ||||
| 				string strTypeX11 = strTypeCS.Replace("CheckState", "XplatUIX11"); | ||||
| 				m_tXplatUIX11 = Type.GetType(strTypeX11, bThrowOnError, true); | ||||
| 			} | ||||
|  | ||||
| 			return m_tXplatUIX11; | ||||
| 		} | ||||
|  | ||||
| 		private static Type m_tHwnd = null; | ||||
| 		private static Type GetHwndType(bool bThrowOnError) | ||||
| 		{ | ||||
| 			if(m_tHwnd == null) | ||||
| 			{ | ||||
| 				// CheckState is in System.Windows.Forms | ||||
| 				string strTypeCS = typeof(CheckState).AssemblyQualifiedName; | ||||
| 				string strTypeHwnd = strTypeCS.Replace("CheckState", "Hwnd"); | ||||
| 				m_tHwnd = Type.GetType(strTypeHwnd, bThrowOnError, true); | ||||
| 			} | ||||
|  | ||||
| 			return m_tHwnd; | ||||
| 		} | ||||
|  | ||||
| 		internal static void SetWmClass(Form f, string strName, string strClass) | ||||
| 		{ | ||||
| 			if(f == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			// The following crashes under Mac OS X (SIGSEGV in native code, | ||||
| 			// not just an exception), thus skip it when we're on Mac OS X; | ||||
| 			// https://sourceforge.net/projects/keepass/forums/forum/329221/topic/5860588 | ||||
| 			if(NativeLib.GetPlatformID() == PlatformID.MacOSX) return; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				Type tXplatUIX11 = GetXplatUIX11Type(true); | ||||
| 				FieldInfo fiDisplayHandle = tXplatUIX11.GetField("DisplayHandle", | ||||
| 					BindingFlags.NonPublic | BindingFlags.Static); | ||||
| 				IntPtr hDisplay = (IntPtr)fiDisplayHandle.GetValue(null); | ||||
|  | ||||
| 				Type tHwnd = GetHwndType(true); | ||||
| 				MethodInfo miObjectFromHandle = tHwnd.GetMethod("ObjectFromHandle", | ||||
| 					BindingFlags.Public | BindingFlags.Static); | ||||
| 				object oHwnd = miObjectFromHandle.Invoke(null, new object[] { f.Handle }); | ||||
|  | ||||
| 				FieldInfo fiWholeWindow = tHwnd.GetField("whole_window", | ||||
| 					BindingFlags.NonPublic | BindingFlags.Instance); | ||||
| 				IntPtr hWindow = (IntPtr)fiWholeWindow.GetValue(oHwnd); | ||||
|  | ||||
| 				XClassHint xch = new XClassHint(); | ||||
| 				xch.res_name = Marshal.StringToCoTaskMemAnsi(strName ?? string.Empty); | ||||
| 				xch.res_class = Marshal.StringToCoTaskMemAnsi(strClass ?? string.Empty); | ||||
| 				IntPtr pXch = Marshal.AllocCoTaskMem(Marshal.SizeOf(xch)); | ||||
| 				Marshal.StructureToPtr(xch, pXch, false); | ||||
|  | ||||
| 				XSetClassHint(hDisplay, hWindow, pXch); | ||||
|  | ||||
| 				Marshal.FreeCoTaskMem(pXch); | ||||
| 				Marshal.FreeCoTaskMem(xch.res_name); | ||||
| 				Marshal.FreeCoTaskMem(xch.res_class); | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,20 +18,22 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Text; | ||||
| using System.Security; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Native | ||||
| { | ||||
| 	internal static class NativeMethods | ||||
| 	internal static partial class NativeMethods | ||||
| 	{ | ||||
| 		internal const int MAX_PATH = 260; | ||||
|  | ||||
| 		// internal const uint TF_SFT_SHOWNORMAL = 0x00000001; | ||||
| 		// internal const uint TF_SFT_HIDDEN = 0x00000008; | ||||
|  | ||||
| 		/* [DllImport("KeePassNtv32.dll", EntryPoint = "TransformKey")] | ||||
| 		[return: MarshalAs(UnmanagedType.Bool)] | ||||
| 		private static extern bool TransformKey32(IntPtr pBuf256, | ||||
| @@ -70,6 +72,7 @@ namespace KeePassLib.Native | ||||
| 				return TransformKeyTimed32(pBuf256, pKey256, ref puRounds, uSeconds); | ||||
| 		} */ | ||||
|  | ||||
| #if !KeePassUAP | ||||
| 		[DllImport("KeePassLibC32.dll", EntryPoint = "TransformKey256")] | ||||
| 		[return: MarshalAs(UnmanagedType.Bool)] | ||||
| 		private static extern bool TransformKey32(IntPtr pBuf256, | ||||
| @@ -83,7 +86,7 @@ namespace KeePassLib.Native | ||||
| 		internal static bool TransformKey(IntPtr pBuf256, IntPtr pKey256, | ||||
| 			UInt64 uRounds) | ||||
| 		{ | ||||
| 			if(Marshal.SizeOf(typeof(IntPtr)) == 8) | ||||
| 			if(NativeLib.PointerSize == 8) | ||||
| 				return TransformKey64(pBuf256, pKey256, uRounds); | ||||
| 			else | ||||
| 				return TransformKey32(pBuf256, pKey256, uRounds); | ||||
| @@ -97,69 +100,87 @@ namespace KeePassLib.Native | ||||
|  | ||||
| 		internal static UInt64 TransformKeyBenchmark(UInt32 uTimeMs) | ||||
| 		{ | ||||
| 			if(Marshal.SizeOf(typeof(IntPtr)) == 8) | ||||
| 			if(NativeLib.PointerSize == 8) | ||||
| 				return TransformKeyBenchmark64(uTimeMs); | ||||
| 			else | ||||
| 				return TransformKeyBenchmark32(uTimeMs); | ||||
| 			return TransformKeyBenchmark32(uTimeMs); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 		[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] | ||||
| 		internal static extern int StrCmpLogicalW(string x, string y); | ||||
| 		/* [DllImport("KeePassLibC32.dll", EntryPoint = "TF_ShowLangBar")] | ||||
| 		[return: MarshalAs(UnmanagedType.Bool)] | ||||
| 		private static extern bool TF_ShowLangBar32(UInt32 dwFlags); | ||||
|  | ||||
| 		[DllImport("KeePassLibC64.dll", EntryPoint = "TF_ShowLangBar")] | ||||
| 		[return: MarshalAs(UnmanagedType.Bool)] | ||||
| 		private static extern bool TF_ShowLangBar64(UInt32 dwFlags); | ||||
|  | ||||
| 		internal static bool TfShowLangBar(uint dwFlags) | ||||
| 		{ | ||||
| 			if(Marshal.SizeOf(typeof(IntPtr)) == 8) | ||||
| 				return TF_ShowLangBar64(dwFlags); | ||||
| 			return TF_ShowLangBar32(dwFlags); | ||||
| 		} */ | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 		[DllImport("ShlWApi.dll", CharSet = CharSet.Auto)] | ||||
| 		[return: MarshalAs(UnmanagedType.Bool)] | ||||
| 		internal static extern bool PathRelativePathTo([Out] StringBuilder pszPath, | ||||
| 			[In] string pszFrom, [In] uint dwAttrFrom, [In] string pszTo, | ||||
| 			[In] uint dwAttrTo); | ||||
| #endif | ||||
| 			[In] string pszFrom, uint dwAttrFrom, [In] string pszTo, uint dwAttrTo); | ||||
|  | ||||
| 		private static bool? m_bSupportsLogicalCmp = null; | ||||
| 		[DllImport("ShlWApi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] | ||||
| 		private static extern int StrCmpLogicalW(string x, string y); | ||||
|  | ||||
| 		private static bool? m_obSupportsLogicalCmp = null; | ||||
|  | ||||
| 		private static void TestNaturalComparisonsSupport() | ||||
| 		{ | ||||
| #if (KeePassLibSD || KeePassRT) | ||||
| #warning No native natural comparisons supported. | ||||
| 			m_bSupportsLogicalCmp = false; | ||||
| #else | ||||
| 			try | ||||
| 			{ | ||||
| 				StrCmpLogicalW("0", "0"); // Throws exception if unsupported | ||||
| 				m_bSupportsLogicalCmp = true; | ||||
| 				m_obSupportsLogicalCmp = true; | ||||
| 			} | ||||
| 			catch(Exception) { m_bSupportsLogicalCmp = false; } | ||||
| #endif | ||||
| 			catch(Exception) { m_obSupportsLogicalCmp = false; } | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		internal static bool SupportsStrCmpNaturally | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_bSupportsLogicalCmp.HasValue == false) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 				if(!m_obSupportsLogicalCmp.HasValue) | ||||
| 					TestNaturalComparisonsSupport(); | ||||
|  | ||||
| 				return m_bSupportsLogicalCmp.Value; | ||||
| 				return m_obSupportsLogicalCmp.Value; | ||||
| #else | ||||
| 				return false; | ||||
| #endif | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		internal static int StrCmpNaturally(string x, string y) | ||||
| 		{ | ||||
| 			if(m_bSupportsLogicalCmp.HasValue == false) TestNaturalComparisonsSupport(); | ||||
| 			if(m_bSupportsLogicalCmp.Value == false) return 0; | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			if(!NativeMethods.SupportsStrCmpNaturally) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				return string.Compare(x, y, true); | ||||
| 			} | ||||
|  | ||||
| #if (KeePassLibSD || KeePassRT) | ||||
| #warning No native natural comparisons supported. | ||||
| 			return x.CompareTo(y); | ||||
| #else | ||||
| 			return StrCmpLogicalW(x, y); | ||||
| #else | ||||
| 			Debug.Assert(false); | ||||
| 			return string.Compare(x, y, true); | ||||
| #endif | ||||
| 		} | ||||
|  | ||||
| 		internal static string GetUserRuntimeDir() | ||||
| 		{ | ||||
| #if !KeePassLibSD | ||||
| #if KeePassRT | ||||
| 			string strRtDir = Windows.Storage.ApplicationData.Current.LocalFolder.Path; | ||||
| #if KeePassLibSD | ||||
| 			return Path.GetTempPath(); | ||||
| #else | ||||
| #if KeePassUAP | ||||
| 			string strRtDir = EnvironmentExt.AppDataLocalFolderPath; | ||||
| #else | ||||
| 			string strRtDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); | ||||
| 			if(string.IsNullOrEmpty(strRtDir)) | ||||
| @@ -175,8 +196,6 @@ namespace KeePassLib.Native | ||||
| 			strRtDir += PwDefs.ShortProductName; | ||||
|  | ||||
| 			return strRtDir; | ||||
| #else | ||||
| 			return Path.GetTempPath(); | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -27,7 +27,7 @@ using System.Runtime.InteropServices; | ||||
| [assembly: AssemblyConfiguration("")] | ||||
| [assembly: AssemblyCompany("Dominik Reichl")] | ||||
| [assembly: AssemblyProduct("KeePassLib")] | ||||
| [assembly: AssemblyCopyright("Copyright © 2003-2013 Dominik Reichl")] | ||||
| [assembly: AssemblyCopyright("Copyright © 2003-2016 Dominik Reichl")] | ||||
| [assembly: AssemblyTrademark("")] | ||||
| [assembly: AssemblyCulture("")] | ||||
|  | ||||
| @@ -38,5 +38,5 @@ using System.Runtime.InteropServices; | ||||
| [assembly: Guid("395f6eec-a1e0-4438-aa82-b75099348134")] | ||||
|  | ||||
| // Assembly version information | ||||
| [assembly: AssemblyVersion("2.24.0.*")] | ||||
| [assembly: AssemblyFileVersion("2.24.0.0")] | ||||
| [assembly: AssemblyVersion("2.34.0.*")] | ||||
| [assembly: AssemblyFileVersion("2.34.0.0")] | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,9 +19,9 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml.Serialization; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics; | ||||
| using System.Xml.Serialization; | ||||
|  | ||||
| using KeePassLib.Delegates; | ||||
| using KeePassLib.Interfaces; | ||||
| @@ -55,20 +55,20 @@ namespace KeePassLib | ||||
| 		/// e.g. 2.19 = 0x02130000. | ||||
| 		/// It is highly recommended to use <c>FileVersion64</c> instead. | ||||
| 		/// </summary> | ||||
| 		public const uint Version32 = 0x02180000; | ||||
| 		public const uint Version32 = 0x02220000; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Version, encoded as 64-bit unsigned integer | ||||
| 		/// (component-wise, 16 bits per component). | ||||
| 		/// </summary> | ||||
| 		public const ulong FileVersion64 = 0x0002001800000000UL; | ||||
| 		public const ulong FileVersion64 = 0x0002002200000000UL; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Version, encoded as string. | ||||
| 		/// </summary> | ||||
| 		public const string VersionString = "2.24"; | ||||
| 		public const string VersionString = "2.34"; | ||||
|  | ||||
| 		public const string Copyright = @"Copyright © 2003-2013 Dominik Reichl"; | ||||
| 		public const string Copyright = @"Copyright © 2003-2016 Dominik Reichl"; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Product website URL. Terminated by a forward slash. | ||||
| @@ -94,7 +94,8 @@ namespace KeePassLib | ||||
| 		/// URL to a TXT file (eventually compressed) that contains information | ||||
| 		/// about the latest KeePass version available on the website. | ||||
| 		/// </summary> | ||||
| 		public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz"; | ||||
| 		public const string VersionUrl = "https://sslsites.de/keepass.info/update/version2x.txt.gz"; | ||||
| 		// public const string VersionUrl = "http://keepass.info/update/version2x.txt.gz"; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// URL to the root path of the online KeePass help. Terminated by | ||||
| @@ -220,7 +221,7 @@ namespace KeePassLib | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	#pragma warning disable 1591 // Missing XML comments warning | ||||
| 	// #pragma warning disable 1591 // Missing XML comments warning | ||||
| 	/// <summary> | ||||
| 	/// Search parameters for group and entry searches. | ||||
| 	/// </summary> | ||||
| @@ -318,7 +319,7 @@ namespace KeePassLib | ||||
| 			set { m_bSearchInTags = value; } | ||||
| 		} | ||||
|  | ||||
| #if KeePassRT | ||||
| #if KeePassUAP | ||||
| 		private StringComparison m_scType = StringComparison.OrdinalIgnoreCase; | ||||
| #else | ||||
| 		private StringComparison m_scType = StringComparison.InvariantCultureIgnoreCase; | ||||
| @@ -410,9 +411,9 @@ namespace KeePassLib | ||||
| 			return (SearchParameters)this.MemberwiseClone(); | ||||
| 		} | ||||
| 	} | ||||
| 	#pragma warning restore 1591 // Missing XML comments warning | ||||
| 	// #pragma warning restore 1591 // Missing XML comments warning | ||||
|  | ||||
| 	#pragma warning disable 1591 // Missing XML comments warning | ||||
| 	// #pragma warning disable 1591 // Missing XML comments warning | ||||
| 	/// <summary> | ||||
| 	/// Memory protection configuration structure (for default fields). | ||||
| 	/// </summary> | ||||
| @@ -442,7 +443,7 @@ namespace KeePassLib | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 	#pragma warning restore 1591 // Missing XML comments warning | ||||
| 	// #pragma warning restore 1591 // Missing XML comments warning | ||||
|  | ||||
| 	public sealed class ObjectTouchedEventArgs : EventArgs | ||||
| 	{ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -20,8 +20,10 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Drawing; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Interfaces; | ||||
| @@ -70,9 +72,11 @@ namespace KeePassLib | ||||
|  | ||||
| 		private List<string> m_vTags = new List<string>(); | ||||
|  | ||||
| 		private StringDictionaryEx m_dCustomData = new StringDictionaryEx(); | ||||
| 		/// <summary> | ||||
| 		/// UUID of this entry. | ||||
| 		/// </summary> | ||||
| 		/// </summary> | ||||
| 		public PwUuid Uuid | ||||
| 		{ | ||||
| 			get { return m_uuid; } | ||||
| @@ -304,6 +308,23 @@ namespace KeePassLib | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Custom data container that can be used by plugins to store | ||||
| 		/// own data in KeePass entries. | ||||
| 		/// The data is stored in the encrypted part of encrypted | ||||
| 		/// database files. | ||||
| 		/// Use unique names for your items, e.g. "PluginName_ItemName". | ||||
| 		/// </summary> | ||||
| 		public StringDictionaryEx CustomData | ||||
| 		{ | ||||
| 			get { return m_dCustomData; } | ||||
| 			internal set | ||||
| 			{ | ||||
| 				if(value == null) { Debug.Assert(false); throw new ArgumentNullException("value"); } | ||||
| 				m_dCustomData = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static EventHandler<ObjectTouchedEventArgs> EntryTouched; | ||||
| 		public EventHandler<ObjectTouchedEventArgs> Touched; | ||||
|  | ||||
| @@ -352,12 +373,20 @@ namespace KeePassLib | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| #if DEBUG | ||||
| 		/// <summary> | ||||
| 		public override string ToString() | ||||
| 		{ | ||||
| 			return (@"PwEntry '" + m_listStrings.ReadSafe(PwDefs.TitleField) + @"'"); | ||||
| 		} | ||||
| #endif | ||||
| 		/// Clone the current entry. The returned entry is an exact value copy | ||||
| 		/// of the current entry (including UUID and parent group reference). | ||||
| 		/// All mutable members are cloned. | ||||
| 		/// </summary> | ||||
| 		/// <returns>Exact value clone. All references to mutable values changed.</returns> | ||||
| 		/// </summary> | ||||
| 		/// <returns>Exact value clone. All references to mutable values changed.</returns> | ||||
| 		public PwEntry CloneDeep() | ||||
| 		{ | ||||
| 			PwEntry peNew = new PwEntry(false, false); | ||||
| @@ -394,6 +423,8 @@ namespace KeePassLib | ||||
|  | ||||
| 			peNew.m_vTags = new List<string>(m_vTags); | ||||
|  | ||||
| 			peNew.m_dCustomData = m_dCustomData.CloneDeep(); | ||||
|  | ||||
| 			return peNew; | ||||
| 		} | ||||
|  | ||||
| @@ -515,6 +546,8 @@ namespace KeePassLib | ||||
| 				if(m_vTags[iTag] != pe.m_vTags[iTag]) return false; | ||||
| 			} | ||||
|  | ||||
| 			if(!m_dCustomData.Equals(pe.m_dCustomData)) return false; | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| @@ -531,7 +564,7 @@ namespace KeePassLib | ||||
| 		public void AssignProperties(PwEntry peTemplate, bool bOnlyIfNewer, | ||||
| 			bool bIncludeHistory, bool bAssignLocationChanged) | ||||
| 		{ | ||||
| 			Debug.Assert(peTemplate != null); if(peTemplate == null) throw new ArgumentNullException("peTemplate"); | ||||
| 			if(peTemplate == null) { Debug.Assert(false); throw new ArgumentNullException("peTemplate"); } | ||||
|  | ||||
| 			if(bOnlyIfNewer && (TimeUtil.Compare(peTemplate.LastModificationTime,LastModificationTime,true) < 0)) return; | ||||
|  | ||||
| @@ -542,10 +575,11 @@ namespace KeePassLib | ||||
| 			if(bAssignLocationChanged) | ||||
| 				m_tParentGroupLastMod = peTemplate.LocationChanged; | ||||
|  | ||||
| 			m_listStrings = peTemplate.m_listStrings; | ||||
| 			m_listBinaries = peTemplate.m_listBinaries; | ||||
| 			m_listAutoType = peTemplate.m_listAutoType; | ||||
| 			if(bIncludeHistory) m_listHistory = peTemplate.m_listHistory; | ||||
| 			m_listStrings = peTemplate.m_listStrings.CloneDeep(); | ||||
| 			m_listBinaries = peTemplate.m_listBinaries.CloneDeep(); | ||||
| 			m_listAutoType = peTemplate.m_listAutoType.CloneDeep(); | ||||
| 			if(bIncludeHistory) | ||||
| 				m_listHistory = peTemplate.m_listHistory.CloneDeep(); | ||||
|  | ||||
| 			m_pwIcon = peTemplate.m_pwIcon; | ||||
| 			m_pwCustomIconID = peTemplate.m_pwCustomIconID; // Immutable | ||||
| @@ -563,6 +597,8 @@ namespace KeePassLib | ||||
| 			m_strOverrideUrl = peTemplate.m_strOverrideUrl; | ||||
|  | ||||
| 			m_vTags = new List<string>(peTemplate.m_vTags); | ||||
|  | ||||
| 			m_dCustomData = peTemplate.m_dCustomData.CloneDeep(); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -814,6 +850,9 @@ namespace KeePassLib | ||||
| 			foreach(string strTag in m_vTags) | ||||
| 				uSize += (ulong)strTag.Length; | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dCustomData) | ||||
| 				uSize += (ulong)kvp.Key.Length + (ulong)kvp.Value.Length; | ||||
|  | ||||
| 			return uSize; | ||||
| 		} | ||||
|  | ||||
| @@ -893,6 +932,25 @@ namespace KeePassLib | ||||
| 			} | ||||
| 			return dateTime;  | ||||
| 		}		 | ||||
| 	 | ||||
|  | ||||
| 		public void SetCreatedNow() | ||||
| 		{ | ||||
| 			DateTime dt = DateTime.Now; | ||||
|  | ||||
| 			m_tCreation = dt; | ||||
| 			m_tLastAccess = dt; | ||||
| 		} | ||||
|  | ||||
| 		public PwEntry Duplicate() | ||||
| 		{ | ||||
| 			PwEntry pe = CloneDeep(); | ||||
|  | ||||
| 			pe.SetUuid(new PwUuid(true), true); | ||||
| 			pe.SetCreatedNow(); | ||||
|  | ||||
| 			return pe; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public sealed class PwEntryComparer : IComparer<PwEntry> | ||||
| @@ -918,12 +976,7 @@ namespace KeePassLib | ||||
|  | ||||
| 			if(m_bCompareNaturally) return StrUtil.CompareNaturally(strA, strB); | ||||
|  | ||||
| #if KeePassRT | ||||
| 			return string.Compare(strA, strB, m_bCaseInsensitive ? | ||||
| 				StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture); | ||||
| #else | ||||
| 			return string.Compare(strA, strB, m_bCaseInsensitive); | ||||
| #endif | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -163,6 +163,26 @@ namespace KeePassLib | ||||
| 		Manual = 2 | ||||
| 	} | ||||
|  | ||||
| 	public enum ProxyAuthType | ||||
| 	{ | ||||
| 		None = 0, | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Use default user credentials (provided by the system). | ||||
| 		/// </summary> | ||||
| 		Default = 1, | ||||
|  | ||||
| 		Manual = 2, | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// <c>Default</c> or <c>Manual</c>, depending on whether | ||||
| 		/// manual credentials are available. | ||||
| 		/// This type exists for supporting upgrading from KeePass | ||||
| 		/// 2.28 to 2.29; the user cannot select this type. | ||||
| 		/// </summary> | ||||
| 		Auto = 3 | ||||
| 	} | ||||
|  | ||||
| 	/// <summary> | ||||
| 	/// Comparison modes for in-memory protected objects. | ||||
| 	/// </summary> | ||||
| @@ -204,6 +224,9 @@ namespace KeePassLib | ||||
| 		IgnoreHistory = 0x10, | ||||
| 		IgnoreLastBackup = 0x20, | ||||
|  | ||||
| 		// For groups: | ||||
| 		PropertiesOnly = 0x40, | ||||
|  | ||||
| 		IgnoreTimes = (IgnoreLastAccess | IgnoreLastMod) | ||||
| 	} | ||||
|  | ||||
| @@ -254,14 +277,43 @@ namespace KeePassLib | ||||
| 		GetStdOutput = 1, | ||||
| 		WaitForExit = 2, | ||||
|  | ||||
| 		// This flag prevents any handles being garbage-collected | ||||
| 		// before the started process has terminated, without | ||||
| 		// blocking the current thread; | ||||
| 		// https://sourceforge.net/p/keepass/patches/84/ | ||||
| 		/// <summary> | ||||
| 		/// This flag prevents any handles being garbage-collected | ||||
| 		/// before the started process has terminated, without | ||||
| 		/// blocking the current thread. | ||||
| 		/// </summary> | ||||
| 		GCKeepAlive = 4, | ||||
|  | ||||
| 		// https://sourceforge.net/p/keepass/patches/85/ | ||||
| 		DoEvents = 8, | ||||
| 		DisableForms = 16 | ||||
| 	} | ||||
|  | ||||
| 	[Flags] | ||||
| 	public enum ScaleTransformFlags | ||||
| 	{ | ||||
| 		None = 0, | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// <c>UIIcon</c> indicates that the returned image is going | ||||
| 		/// to be displayed as icon in the UI and that it is not | ||||
| 		/// subject to future changes in size. | ||||
| 		/// </summary> | ||||
| 		UIIcon = 1 | ||||
| 	} | ||||
|  | ||||
| 	public enum DesktopType | ||||
| 	{ | ||||
| 		None = 0, | ||||
| 		Windows, | ||||
| 		Gnome, | ||||
| 		Kde, | ||||
| 		Unity, | ||||
| 		Lxde, | ||||
| 		Xfce, | ||||
| 		Mate, | ||||
| 		Cinnamon, | ||||
| 		Pantheon | ||||
| 	} | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -137,12 +137,6 @@ namespace KeePassLib | ||||
| 		{ | ||||
| 			if(other == null) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			// Shortcut | ||||
| 			if (Object.ReferenceEquals(this, other)) | ||||
| 			{ | ||||
| 				return true; | ||||
| 			} | ||||
|  | ||||
| 			for(int i = 0; i < (int)UuidSize; ++i) | ||||
| 			{ | ||||
| 				if(m_pbUuid[i] != other.m_pbUuid[i]) return false; | ||||
|   | ||||
| @@ -27,14 +27,16 @@ namespace KeePassLib.Resources | ||||
| 			if(dictNew == null) throw new ArgumentNullException("dictNew"); | ||||
|  | ||||
| 			m_strCryptoStreamFailed = TryGetEx(dictNew, "CryptoStreamFailed", m_strCryptoStreamFailed); | ||||
| 			m_strEncAlgorithmAes = TryGetEx(dictNew, "EncAlgorithmAes", m_strEncAlgorithmAes); | ||||
| 			m_strEncDataTooLarge = TryGetEx(dictNew, "EncDataTooLarge", m_strEncDataTooLarge); | ||||
| 			m_strErrorInClipboard = TryGetEx(dictNew, "ErrorInClipboard", m_strErrorInClipboard); | ||||
| 			m_strExpect100Continue = TryGetEx(dictNew, "Expect100Continue", m_strExpect100Continue); | ||||
| 			m_strFatalError = TryGetEx(dictNew, "FatalError", m_strFatalError); | ||||
| 			m_strFatalErrorText = TryGetEx(dictNew, "FatalErrorText", m_strFatalErrorText); | ||||
| 			m_strFileCorrupted = TryGetEx(dictNew, "FileCorrupted", m_strFileCorrupted); | ||||
| 			m_strFileHeaderEndEarly = TryGetEx(dictNew, "FileHeaderEndEarly", m_strFileHeaderEndEarly); | ||||
| 			m_strFileLoadFailed = TryGetEx(dictNew, "FileLoadFailed", m_strFileLoadFailed); | ||||
| 			m_strFileLockedWrite = TryGetEx(dictNew, "FileLockedWrite", m_strFileLockedWrite); | ||||
| 			m_strFileNewVerOrPlgReq = TryGetEx(dictNew, "FileNewVerOrPlgReq", m_strFileNewVerOrPlgReq); | ||||
| 			m_strFileNewVerReq = TryGetEx(dictNew, "FileNewVerReq", m_strFileNewVerReq); | ||||
| 			m_strFileSaveCorruptionWarning = TryGetEx(dictNew, "FileSaveCorruptionWarning", m_strFileSaveCorruptionWarning); | ||||
| 			m_strFileSaveFailed = TryGetEx(dictNew, "FileSaveFailed", m_strFileSaveFailed); | ||||
| @@ -44,28 +46,37 @@ namespace KeePassLib.Resources | ||||
| 			m_strFileVersionUnsupported = TryGetEx(dictNew, "FileVersionUnsupported", m_strFileVersionUnsupported); | ||||
| 			m_strFinalKeyCreationFailed = TryGetEx(dictNew, "FinalKeyCreationFailed", m_strFinalKeyCreationFailed); | ||||
| 			m_strFrameworkNotImplExcp = TryGetEx(dictNew, "FrameworkNotImplExcp", m_strFrameworkNotImplExcp); | ||||
| 			m_strGeneral = TryGetEx(dictNew, "General", m_strGeneral); | ||||
| 			m_strInvalidCompositeKey = TryGetEx(dictNew, "InvalidCompositeKey", m_strInvalidCompositeKey); | ||||
| 			m_strInvalidCompositeKeyHint = TryGetEx(dictNew, "InvalidCompositeKeyHint", m_strInvalidCompositeKeyHint); | ||||
| 			m_strInvalidDataWhileDecoding = TryGetEx(dictNew, "InvalidDataWhileDecoding", m_strInvalidDataWhileDecoding); | ||||
| 			m_strKeePass1xHint = TryGetEx(dictNew, "KeePass1xHint", m_strKeePass1xHint); | ||||
| 			m_strKeyBits = TryGetEx(dictNew, "KeyBits", m_strKeyBits); | ||||
| 			m_strKeyFileDbSel = TryGetEx(dictNew, "KeyFileDbSel", m_strKeyFileDbSel); | ||||
| 			m_strMasterSeedLengthInvalid = TryGetEx(dictNew, "MasterSeedLengthInvalid", m_strMasterSeedLengthInvalid); | ||||
| 			m_strOldFormat = TryGetEx(dictNew, "OldFormat", m_strOldFormat); | ||||
| 			m_strPassive = TryGetEx(dictNew, "Passive", m_strPassive); | ||||
| 			m_strPreAuth = TryGetEx(dictNew, "PreAuth", m_strPreAuth); | ||||
| 			m_strTimeout = TryGetEx(dictNew, "Timeout", m_strTimeout); | ||||
| 			m_strTryAgainSecs = TryGetEx(dictNew, "TryAgainSecs", m_strTryAgainSecs); | ||||
| 			m_strUnknownHeaderId = TryGetEx(dictNew, "UnknownHeaderId", m_strUnknownHeaderId); | ||||
| 			m_strUnknownKdf = TryGetEx(dictNew, "UnknownKdf", m_strUnknownKdf); | ||||
| 			m_strUserAccountKeyError = TryGetEx(dictNew, "UserAccountKeyError", m_strUserAccountKeyError); | ||||
| 			m_strUserAgent = TryGetEx(dictNew, "UserAgent", m_strUserAgent); | ||||
| 		} | ||||
|  | ||||
| 		private static readonly string[] m_vKeyNames = { | ||||
| 			"CryptoStreamFailed", | ||||
| 			"EncAlgorithmAes", | ||||
| 			"EncDataTooLarge", | ||||
| 			"ErrorInClipboard", | ||||
| 			"Expect100Continue", | ||||
| 			"FatalError", | ||||
| 			"FatalErrorText", | ||||
| 			"FileCorrupted", | ||||
| 			"FileHeaderEndEarly", | ||||
| 			"FileLoadFailed", | ||||
| 			"FileLockedWrite", | ||||
| 			"FileNewVerOrPlgReq", | ||||
| 			"FileNewVerReq", | ||||
| 			"FileSaveCorruptionWarning", | ||||
| 			"FileSaveFailed", | ||||
| @@ -75,16 +86,23 @@ namespace KeePassLib.Resources | ||||
| 			"FileVersionUnsupported", | ||||
| 			"FinalKeyCreationFailed", | ||||
| 			"FrameworkNotImplExcp", | ||||
| 			"General", | ||||
| 			"InvalidCompositeKey", | ||||
| 			"InvalidCompositeKeyHint", | ||||
| 			"InvalidDataWhileDecoding", | ||||
| 			"KeePass1xHint", | ||||
| 			"KeyBits", | ||||
| 			"KeyFileDbSel", | ||||
| 			"MasterSeedLengthInvalid", | ||||
| 			"OldFormat", | ||||
| 			"Passive", | ||||
| 			"PreAuth", | ||||
| 			"Timeout", | ||||
| 			"TryAgainSecs", | ||||
| 			"UnknownHeaderId", | ||||
| 			"UserAccountKeyError" | ||||
| 			"UnknownKdf", | ||||
| 			"UserAccountKeyError", | ||||
| 			"UserAgent" | ||||
| 		}; | ||||
|  | ||||
| 		public static string[] GetKeyNames() | ||||
| @@ -103,15 +121,15 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strCryptoStreamFailed; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strEncAlgorithmAes = | ||||
| 			@"AES/Rijndael (256-Bit Key)"; | ||||
| 		private static string m_strEncDataTooLarge = | ||||
| 			@"The data is too large to be encrypted/decrypted securely using {PARAM}."; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'AES/Rijndael (256-Bit Key)'. | ||||
| 		/// 'The data is too large to be encrypted/decrypted securely using {PARAM}.'. | ||||
| 		/// </summary> | ||||
| 		public static string EncAlgorithmAes | ||||
| 		public static string EncDataTooLarge | ||||
| 		{ | ||||
| 			get { return m_strEncAlgorithmAes; } | ||||
| 			get { return m_strEncDataTooLarge; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strErrorInClipboard = | ||||
| @@ -125,6 +143,17 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strErrorInClipboard; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strExpect100Continue = | ||||
| 			@"Expect 100-Continue responses"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'Expect 100-Continue responses'. | ||||
| 		/// </summary> | ||||
| 		public static string Expect100Continue | ||||
| 		{ | ||||
| 			get { return m_strExpect100Continue; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strFatalError = | ||||
| 			@"Fatal Error"; | ||||
| 		/// <summary> | ||||
| @@ -191,6 +220,17 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strFileLockedWrite; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strFileNewVerOrPlgReq = | ||||
| 			@"A newer KeePass version or a plugin is required to open this file."; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'A newer KeePass version or a plugin is required to open this file.'. | ||||
| 		/// </summary> | ||||
| 		public static string FileNewVerOrPlgReq | ||||
| 		{ | ||||
| 			get { return m_strFileNewVerOrPlgReq; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strFileNewVerReq = | ||||
| 			@"A newer KeePass version is required to open this file."; | ||||
| 		/// <summary> | ||||
| @@ -290,6 +330,17 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strFrameworkNotImplExcp; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strGeneral = | ||||
| 			@"General"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'General'. | ||||
| 		/// </summary> | ||||
| 		public static string General | ||||
| 		{ | ||||
| 			get { return m_strGeneral; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strInvalidCompositeKey = | ||||
| 			@"The composite key is invalid!"; | ||||
| 		/// <summary> | ||||
| @@ -334,6 +385,17 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strKeePass1xHint; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strKeyBits = | ||||
| 			@"{PARAM}-bit key"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// '{PARAM}-bit key'. | ||||
| 		/// </summary> | ||||
| 		public static string KeyBits | ||||
| 		{ | ||||
| 			get { return m_strKeyBits; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strKeyFileDbSel = | ||||
| 			@"Database files cannot be used as key files."; | ||||
| 		/// <summary> | ||||
| @@ -367,6 +429,39 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strOldFormat; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strPassive = | ||||
| 			@"Passive"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'Passive'. | ||||
| 		/// </summary> | ||||
| 		public static string Passive | ||||
| 		{ | ||||
| 			get { return m_strPassive; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strPreAuth = | ||||
| 			@"Pre-authenticate"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'Pre-authenticate'. | ||||
| 		/// </summary> | ||||
| 		public static string PreAuth | ||||
| 		{ | ||||
| 			get { return m_strPreAuth; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strTimeout = | ||||
| 			@"Timeout"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'Timeout'. | ||||
| 		/// </summary> | ||||
| 		public static string Timeout | ||||
| 		{ | ||||
| 			get { return m_strTimeout; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strTryAgainSecs = | ||||
| 			@"Please try it again in a few seconds."; | ||||
| 		/// <summary> | ||||
| @@ -389,6 +484,17 @@ namespace KeePassLib.Resources | ||||
| 			get { return m_strUnknownHeaderId; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strUnknownKdf = | ||||
| 			@"Unknown key derivation function!"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'Unknown key derivation function!'. | ||||
| 		/// </summary> | ||||
| 		public static string UnknownKdf | ||||
| 		{ | ||||
| 			get { return m_strUnknownKdf; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strUserAccountKeyError = | ||||
| 			@"The operating system did not grant KeePass read/write access to the user profile folder, where the protected user key is stored."; | ||||
| 		/// <summary> | ||||
| @@ -399,5 +505,16 @@ namespace KeePassLib.Resources | ||||
| 		{ | ||||
| 			get { return m_strUserAccountKeyError; } | ||||
| 		} | ||||
|  | ||||
| 		private static string m_strUserAgent = | ||||
| 			@"User agent"; | ||||
| 		/// <summary> | ||||
| 		/// Look up a localized string similar to | ||||
| 		/// 'User agent'. | ||||
| 		/// </summary> | ||||
| 		public static string UserAgent | ||||
| 		{ | ||||
| 			get { return m_strUserAgent; } | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -20,10 +18,16 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Security.Cryptography; | ||||
| using System.Diagnostics; | ||||
| using System.Threading; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| #if KeePassLibSD | ||||
| @@ -32,6 +36,17 @@ using KeePassLibSD; | ||||
|  | ||||
| namespace KeePassLib.Security | ||||
| { | ||||
| 	[Flags] | ||||
| 	public enum PbCryptFlags | ||||
| 	{ | ||||
| 		None = 0, | ||||
| 		Encrypt = 1, | ||||
| 		Decrypt = 2 | ||||
| 	} | ||||
|  | ||||
| 	public delegate void PbCryptDelegate(byte[] pbData, PbCryptFlags cf, | ||||
| 		long lID); | ||||
|  | ||||
| 	/// <summary> | ||||
| 	/// Represents a protected binary, i.e. a byte array that is encrypted | ||||
| 	/// in memory. A <c>ProtectedBinary</c> object is immutable and | ||||
| @@ -39,26 +54,97 @@ namespace KeePassLib.Security | ||||
| 	/// </summary> | ||||
| 	public sealed class ProtectedBinary : IEquatable<ProtectedBinary> | ||||
| 	{ | ||||
| 		private const int PmBlockSize = 16; | ||||
| 		private const int BlockSize = 16; | ||||
|  | ||||
| 		// In-memory protection is supported only on Windows 2000 SP3 and | ||||
| 		// higher. | ||||
| 		private static bool m_bProtectionSupported; | ||||
| 		private static PbCryptDelegate g_fExtCrypt = null; | ||||
| 		/// <summary> | ||||
| 		/// A plugin can provide a custom memory protection method | ||||
| 		/// by assigning a non-null delegate to this property. | ||||
| 		/// </summary> | ||||
| 		public static PbCryptDelegate ExtCrypt | ||||
| 		{ | ||||
| 			get { return g_fExtCrypt; } | ||||
| 			set { g_fExtCrypt = value; } | ||||
| 		} | ||||
|  | ||||
| 		// Local copy of the delegate that was used for encryption, | ||||
| 		// in order to allow correct decryption even when the global | ||||
| 		// delegate changes | ||||
| 		private PbCryptDelegate m_fExtCrypt = null; | ||||
|  | ||||
| 		private enum PbMemProt | ||||
| 		{ | ||||
| 			None = 0, | ||||
| 			ProtectedMemory, | ||||
| 			ChaCha20, | ||||
| 			ExtCrypt | ||||
| 		} | ||||
|  | ||||
| 		// ProtectedMemory is supported only on Windows 2000 SP3 and higher | ||||
| #if !KeePassLibSD | ||||
| 		private static bool? g_obProtectedMemorySupported = null; | ||||
| #endif | ||||
| 		private static bool ProtectedMemorySupported | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| #if KeePassLibSD | ||||
| 				return false; | ||||
| #else | ||||
| 				bool? ob = g_obProtectedMemorySupported; | ||||
| 				if(ob.HasValue) return ob.Value; | ||||
|  | ||||
| 				// Mono does not implement any encryption for ProtectedMemory; | ||||
| 				// https://sourceforge.net/p/keepass/feature-requests/1907/ | ||||
| 				if(NativeLib.IsUnix()) | ||||
| 				{ | ||||
| 					g_obProtectedMemorySupported = false; | ||||
| 					return false; | ||||
| 				} | ||||
|  | ||||
| 				ob = false; | ||||
| 				try // Test whether ProtectedMemory is supported | ||||
| 				{ | ||||
| 					// BlockSize * 3 in order to test encryption for multiple | ||||
| 					// blocks, but not introduce a power of 2 as factor | ||||
| 					byte[] pb = new byte[ProtectedBinary.BlockSize * 3]; | ||||
| 					for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)i; | ||||
|  | ||||
| 					throw new NotSupportedException(); | ||||
| 					for(int i = 0; i < pb.Length; ++i) | ||||
| 					{ | ||||
| 						if(pb[i] != (byte)i) { ob = true; break; } | ||||
| 					} | ||||
| 				} | ||||
| 				catch(Exception) { } // Windows 98 / ME | ||||
|  | ||||
| 				g_obProtectedMemorySupported = ob; | ||||
| 				return ob.Value; | ||||
| #endif | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private static long g_lCurID = 0; | ||||
| 		private long m_lID; | ||||
|  | ||||
| 		private byte[] m_pbData; // Never null | ||||
|  | ||||
| 		// The real length of the data. This value can be different than | ||||
| 		// The real length of the data; this value can be different from | ||||
| 		// m_pbData.Length, as the length of m_pbData always is a multiple | ||||
| 		// of PmBlockSize (required for fast in-memory protection). | ||||
| 		// of BlockSize (required for ProtectedMemory) | ||||
| 		private uint m_uDataLen; | ||||
|  | ||||
| 		private bool m_bProtected; | ||||
| 		private bool m_bProtected; // Protection requested by the caller | ||||
|  | ||||
| 		private PbMemProt m_mp = PbMemProt.None; // Actual protection | ||||
|  | ||||
| 		private object m_objSync = new object(); | ||||
|  | ||||
| 		private static byte[] g_pbKey32 = null; | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// A flag specifying whether the <c>ProtectedBinary</c> object has | ||||
| 		/// turned on in-memory protection or not. | ||||
| 		/// turned on memory protection or not. | ||||
| 		/// </summary> | ||||
| 		public bool IsProtected | ||||
| 		{ | ||||
| @@ -73,19 +159,13 @@ namespace KeePassLib.Security | ||||
| 			get { return m_uDataLen; } | ||||
| 		} | ||||
|  | ||||
| 		static ProtectedBinary() | ||||
| 		{ | ||||
| 			//protection not supported on Android currently | ||||
| 			m_bProtectionSupported = false; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Construct a new, empty protected binary data object. Protection | ||||
| 		/// is disabled. | ||||
| 		/// Construct a new, empty protected binary data object. | ||||
| 		/// Protection is disabled. | ||||
| 		/// </summary> | ||||
| 		public ProtectedBinary() | ||||
| 		{ | ||||
| 			Init(false, new byte[0]); | ||||
| 			Init(false, MemUtil.EmptyByteArray); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -110,34 +190,99 @@ namespace KeePassLib.Security | ||||
| 		/// <param name="bEnableProtection">Enable protection or not.</param> | ||||
| 		/// <param name="xbProtected"><c>XorredBuffer</c> object used to | ||||
| 		/// initialize the <c>ProtectedBinary</c> object.</param> | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the input | ||||
| 		/// parameter is <c>null</c>.</exception> | ||||
| 		public ProtectedBinary(bool bEnableProtection, XorredBuffer xbProtected) | ||||
| 		{ | ||||
| 			Debug.Assert(xbProtected != null); if(xbProtected == null) throw new ArgumentNullException("xbProtected"); | ||||
| 			Debug.Assert(xbProtected != null); | ||||
| 			if(xbProtected == null) throw new ArgumentNullException("xbProtected"); | ||||
|  | ||||
| 			byte[] pb = xbProtected.ReadPlainText(); | ||||
| 			Init(bEnableProtection, pb); | ||||
| 			MemUtil.ZeroByteArray(pb); | ||||
|  | ||||
| 			if(bEnableProtection) MemUtil.ZeroByteArray(pb); | ||||
| 		} | ||||
|  | ||||
| 		private void Init(bool bEnableProtection, byte[] pbData) | ||||
| 		{ | ||||
| 			if(pbData == null) throw new ArgumentNullException("pbData"); | ||||
|  | ||||
| #if KeePassLibSD | ||||
| 			m_lID = ++g_lCurID; | ||||
| #else | ||||
| 			m_lID = Interlocked.Increment(ref g_lCurID); | ||||
| #endif | ||||
|  | ||||
| 			m_bProtected = bEnableProtection; | ||||
| 			m_uDataLen = (uint)pbData.Length; | ||||
|  | ||||
| 			int nBlocks = (int)m_uDataLen / PmBlockSize; | ||||
| 			if((nBlocks * PmBlockSize) < (int)m_uDataLen) ++nBlocks; | ||||
| 			Debug.Assert((nBlocks * PmBlockSize) >= (int)m_uDataLen); | ||||
| 			const int bs = ProtectedBinary.BlockSize; | ||||
| 			int nBlocks = (int)m_uDataLen / bs; | ||||
| 			if((nBlocks * bs) < (int)m_uDataLen) ++nBlocks; | ||||
| 			Debug.Assert((nBlocks * bs) >= (int)m_uDataLen); | ||||
|  | ||||
| 			m_pbData = new byte[nBlocks * PmBlockSize]; | ||||
| 			m_pbData = new byte[nBlocks * bs]; | ||||
| 			Array.Copy(pbData, m_pbData, (int)m_uDataLen); | ||||
|  | ||||
| 			// Data size must be > 0, otherwise 'Protect' throws | ||||
| 			if(m_bProtected && m_bProtectionSupported && (m_uDataLen > 0)) | ||||
| 				throw new NotSupportedException(); | ||||
| 			Encrypt(); | ||||
| 		} | ||||
|  | ||||
| 		private void Encrypt() | ||||
| 		{ | ||||
| 			Debug.Assert(m_mp == PbMemProt.None); | ||||
|  | ||||
| 			// Nothing to do if caller didn't request protection | ||||
| 			if(!m_bProtected) return; | ||||
|  | ||||
| 			// ProtectedMemory.Protect throws for data size == 0 | ||||
| 			if(m_pbData.Length == 0) return; | ||||
|  | ||||
| 			PbCryptDelegate f = g_fExtCrypt; | ||||
| 			if(f != null) | ||||
| 			{ | ||||
| 				f(m_pbData, PbCryptFlags.Encrypt, m_lID); | ||||
|  | ||||
| 				m_fExtCrypt = f; | ||||
| 				m_mp = PbMemProt.ExtCrypt; | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			 | ||||
|  | ||||
| 			byte[] pbKey32 = g_pbKey32; | ||||
| 			if(pbKey32 == null) | ||||
| 			{ | ||||
| 				pbKey32 = CryptoRandom.Instance.GetRandomBytes(32); | ||||
|  | ||||
| 				byte[] pbUpd = Interlocked.Exchange<byte[]>(ref g_pbKey32, pbKey32); | ||||
| 				if(pbUpd != null) pbKey32 = pbUpd; | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbIV = new byte[12]; | ||||
| 			MemUtil.UInt64ToBytesEx((ulong)m_lID, pbIV, 4); | ||||
| 			using(ChaCha20Cipher c = new ChaCha20Cipher(pbKey32, pbIV, true)) | ||||
| 			{ | ||||
| 				c.Encrypt(m_pbData, 0, m_pbData.Length); | ||||
| 			} | ||||
| 			m_mp = PbMemProt.ChaCha20; | ||||
| 		} | ||||
|  | ||||
| 		private void Decrypt() | ||||
| 		{ | ||||
| 			if(m_pbData.Length == 0) return; | ||||
|  | ||||
| 			else if(m_mp == PbMemProt.ChaCha20) | ||||
| 			{ | ||||
| 				byte[] pbIV = new byte[12]; | ||||
| 				MemUtil.UInt64ToBytesEx((ulong)m_lID, pbIV, 4); | ||||
| 				using(ChaCha20Cipher c = new ChaCha20Cipher(g_pbKey32, pbIV, true)) | ||||
| 				{ | ||||
| 					c.Decrypt(m_pbData, 0, m_pbData.Length); | ||||
| 				} | ||||
| 			} | ||||
| 			else if(m_mp == PbMemProt.ExtCrypt) | ||||
| 				m_fExtCrypt(m_pbData, PbCryptFlags.Decrypt, m_lID); | ||||
| 			else { Debug.Assert(m_mp == PbMemProt.None); } | ||||
|  | ||||
| 			m_mp = PbMemProt.None; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -150,18 +295,16 @@ namespace KeePassLib.Security | ||||
| 		/// protected data and can therefore be cleared safely.</returns> | ||||
| 		public byte[] ReadData() | ||||
| 		{ | ||||
| 			if(m_uDataLen == 0) return new byte[0]; | ||||
| 			if(m_uDataLen == 0) return MemUtil.EmptyByteArray; | ||||
|  | ||||
| 			byte[] pbReturn = new byte[m_uDataLen]; | ||||
|  | ||||
| 			if(m_bProtected && m_bProtectionSupported) | ||||
| 			lock(m_objSync) | ||||
| 			{ | ||||
| 				lock(m_objSync) | ||||
| 				{ | ||||
| 					throw new NotSupportedException(); | ||||
| 				} | ||||
| 				Decrypt(); | ||||
| 				Array.Copy(m_pbData, pbReturn, (int)m_uDataLen); | ||||
| 				Encrypt(); | ||||
| 			} | ||||
| 			else Array.Copy(m_pbData, pbReturn, (int)m_uDataLen); | ||||
|  | ||||
| 			return pbReturn; | ||||
| 		} | ||||
| @@ -171,9 +314,6 @@ namespace KeePassLib.Security | ||||
| 		/// of bytes generated by a random stream. | ||||
| 		/// </summary> | ||||
| 		/// <param name="crsRandomSource">Random number source.</param> | ||||
| 		/// <returns>Protected data.</returns> | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the input | ||||
| 		/// parameter is <c>null</c>.</exception> | ||||
| 		public byte[] ReadXorredData(CryptoRandomStream crsRandomSource) | ||||
| 		{ | ||||
| 			Debug.Assert(crsRandomSource != null); | ||||
| @@ -183,7 +323,7 @@ namespace KeePassLib.Security | ||||
| 			uint uLen = (uint)pbData.Length; | ||||
|  | ||||
| 			byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); | ||||
| 			Debug.Assert(randomPad.Length == uLen); | ||||
| 			Debug.Assert(randomPad.Length == pbData.Length); | ||||
|  | ||||
| 			for(uint i = 0; i < uLen; ++i) | ||||
| 				pbData[i] ^= randomPad[i]; | ||||
| @@ -191,8 +331,11 @@ namespace KeePassLib.Security | ||||
| 			return pbData; | ||||
| 		} | ||||
|  | ||||
| 		private int? m_hash = null; | ||||
| 		public override int GetHashCode() | ||||
| 		{ | ||||
| 			if(m_hash.HasValue) return m_hash.Value; | ||||
|  | ||||
| 			int h = (m_bProtected ? 0x7B11D289 : 0); | ||||
|  | ||||
| 			byte[] pb = ReadData(); | ||||
| @@ -203,6 +346,7 @@ namespace KeePassLib.Security | ||||
| 			} | ||||
| 			MemUtil.ZeroByteArray(pb); | ||||
|  | ||||
| 			m_hash = h; | ||||
| 			return h; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,8 +18,8 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Text; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Utility; | ||||
| @@ -47,7 +47,7 @@ namespace KeePassLib.Security | ||||
|  | ||||
| 		private bool m_bIsProtected; | ||||
|  | ||||
| 		private static ProtectedString m_psEmpty = new ProtectedString(); | ||||
| 		private static readonly ProtectedString m_psEmpty = new ProtectedString(); | ||||
| 		public static ProtectedString Empty | ||||
| 		{ | ||||
| 			get { return m_psEmpty; } | ||||
| @@ -55,7 +55,7 @@ namespace KeePassLib.Security | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// A flag specifying whether the <c>ProtectedString</c> object | ||||
| 		/// has turned on in-memory protection or not. | ||||
| 		/// has turned on memory protection or not. | ||||
| 		/// </summary> | ||||
| 		public bool IsProtected | ||||
| 		{ | ||||
| @@ -112,10 +112,9 @@ namespace KeePassLib.Security | ||||
| 		/// to the value supplied in the parameters. | ||||
| 		/// </summary> | ||||
| 		/// <param name="bEnableProtection">If this parameter is <c>true</c>, | ||||
| 		/// the string will be protected in-memory (encrypted). If it | ||||
| 		/// the string will be protected in memory (encrypted). If it | ||||
| 		/// is <c>false</c>, the string will be stored as plain-text.</param> | ||||
| 		/// <param name="strValue">The initial string value. This | ||||
| 		/// parameter won't be modified.</param> | ||||
| 		/// <param name="strValue">The initial string value.</param> | ||||
| 		public ProtectedString(bool bEnableProtection, string strValue) | ||||
| 		{ | ||||
| 			Init(bEnableProtection, strValue); | ||||
| @@ -126,7 +125,7 @@ namespace KeePassLib.Security | ||||
| 		/// to the value supplied in the parameters (UTF-8 encoded string). | ||||
| 		/// </summary> | ||||
| 		/// <param name="bEnableProtection">If this parameter is <c>true</c>, | ||||
| 		/// the string will be protected in-memory (encrypted). If it | ||||
| 		/// the string will be protected in memory (encrypted). If it | ||||
| 		/// is <c>false</c>, the string will be stored as plain-text.</param> | ||||
| 		/// <param name="vUtf8Value">The initial string value, encoded as | ||||
| 		/// UTF-8 byte array. This parameter won't be modified; the caller | ||||
| @@ -144,15 +143,15 @@ namespace KeePassLib.Security | ||||
| 		/// <param name="xbProtected"><c>XorredBuffer</c> object containing the | ||||
| 		/// string in UTF-8 representation. The UTF-8 string must not | ||||
| 		/// be <c>null</c>-terminated.</param> | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the input | ||||
| 		/// parameter is <c>null</c>.</exception> | ||||
| 		public ProtectedString(bool bEnableProtection, XorredBuffer xbProtected) | ||||
| 		{ | ||||
| 			Debug.Assert(xbProtected != null); | ||||
| 			if(xbProtected == null) throw new ArgumentNullException("xbProtected"); | ||||
|  | ||||
| 			byte[] pb = xbProtected.ReadPlainText(); | ||||
| 			Init(bEnableProtection, pb); | ||||
| 			MemUtil.ZeroByteArray(pb); | ||||
|  | ||||
| 			if(bEnableProtection) MemUtil.ZeroByteArray(pb); | ||||
| 		} | ||||
|  | ||||
| 		private void Init(bool bEnableProtection, string str) | ||||
| @@ -222,8 +221,6 @@ namespace KeePassLib.Security | ||||
| 		/// </summary> | ||||
| 		/// <param name="crsRandomSource">Random number source.</param> | ||||
| 		/// <returns>Protected string.</returns> | ||||
| 		/// <exception cref="System.ArgumentNullException">Thrown if the input | ||||
| 		/// parameter is <c>null</c>.</exception> | ||||
| 		public byte[] ReadXorredString(CryptoRandomStream crsRandomSource) | ||||
| 		{ | ||||
| 			Debug.Assert(crsRandomSource != null); if(crsRandomSource == null) throw new ArgumentNullException("crsRandomSource"); | ||||
| @@ -232,7 +229,7 @@ namespace KeePassLib.Security | ||||
| 			uint uLen = (uint)pbData.Length; | ||||
|  | ||||
| 			byte[] randomPad = crsRandomSource.GetRandomBytes(uLen); | ||||
| 			Debug.Assert(randomPad.Length == uLen); | ||||
| 			Debug.Assert(randomPad.Length == pbData.Length); | ||||
|  | ||||
| 			for(uint i = 0; i < uLen; ++i) | ||||
| 				pbData[i] ^= randomPad[i]; | ||||
| @@ -246,7 +243,103 @@ namespace KeePassLib.Security | ||||
|  | ||||
| 			byte[] pb = ReadUtf8(); | ||||
| 			ProtectedString ps = new ProtectedString(bProtect, pb); | ||||
| 			MemUtil.ZeroByteArray(pb); | ||||
|  | ||||
| 			if(bProtect) MemUtil.ZeroByteArray(pb); | ||||
| 			return ps; | ||||
| 		} | ||||
|  | ||||
| 		public ProtectedString Insert(int iStart, string strInsert) | ||||
| 		{ | ||||
| 			if(iStart < 0) throw new ArgumentOutOfRangeException("iStart"); | ||||
| 			if(strInsert == null) throw new ArgumentNullException("strInsert"); | ||||
| 			if(strInsert.Length == 0) return this; | ||||
|  | ||||
| 			// Only operate directly with strings when m_bIsProtected is | ||||
| 			// false, not in the case of non-null m_strPlainText, because | ||||
| 			// the operation creates a new sequence in memory | ||||
| 			if(!m_bIsProtected) | ||||
| 				return new ProtectedString(false, ReadString().Insert( | ||||
| 					iStart, strInsert)); | ||||
|  | ||||
| 			UTF8Encoding utf8 = StrUtil.Utf8; | ||||
|  | ||||
| 			byte[] pb = ReadUtf8(); | ||||
| 			char[] v = utf8.GetChars(pb); | ||||
| 			char[] vNew; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				if(iStart > v.Length) | ||||
| 					throw new ArgumentOutOfRangeException("iStart"); | ||||
|  | ||||
| 				char[] vIns = strInsert.ToCharArray(); | ||||
|  | ||||
| 				vNew = new char[v.Length + vIns.Length]; | ||||
| 				Array.Copy(v, 0, vNew, 0, iStart); | ||||
| 				Array.Copy(vIns, 0, vNew, iStart, vIns.Length); | ||||
| 				Array.Copy(v, iStart, vNew, iStart + vIns.Length, | ||||
| 					v.Length - iStart); | ||||
| 			} | ||||
| 			finally | ||||
| 			{ | ||||
| 				Array.Clear(v, 0, v.Length); | ||||
| 				MemUtil.ZeroByteArray(pb); | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbNew = utf8.GetBytes(vNew); | ||||
| 			ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew); | ||||
|  | ||||
| 			Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == | ||||
| 				ReadString().Insert(iStart, strInsert)); | ||||
|  | ||||
| 			Array.Clear(vNew, 0, vNew.Length); | ||||
| 			MemUtil.ZeroByteArray(pbNew); | ||||
| 			return ps; | ||||
| 		} | ||||
|  | ||||
| 		public ProtectedString Remove(int iStart, int nCount) | ||||
| 		{ | ||||
| 			if(iStart < 0) throw new ArgumentOutOfRangeException("iStart"); | ||||
| 			if(nCount < 0) throw new ArgumentOutOfRangeException("nCount"); | ||||
| 			if(nCount == 0) return this; | ||||
|  | ||||
| 			// Only operate directly with strings when m_bIsProtected is | ||||
| 			// false, not in the case of non-null m_strPlainText, because | ||||
| 			// the operation creates a new sequence in memory | ||||
| 			if(!m_bIsProtected) | ||||
| 				return new ProtectedString(false, ReadString().Remove( | ||||
| 					iStart, nCount)); | ||||
|  | ||||
| 			UTF8Encoding utf8 = StrUtil.Utf8; | ||||
|  | ||||
| 			byte[] pb = ReadUtf8(); | ||||
| 			char[] v = utf8.GetChars(pb); | ||||
| 			char[] vNew; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				if((iStart + nCount) > v.Length) | ||||
| 					throw new ArgumentException("iStart + nCount"); | ||||
|  | ||||
| 				vNew = new char[v.Length - nCount]; | ||||
| 				Array.Copy(v, 0, vNew, 0, iStart); | ||||
| 				Array.Copy(v, iStart + nCount, vNew, iStart, v.Length - | ||||
| 					(iStart + nCount)); | ||||
| 			} | ||||
| 			finally | ||||
| 			{ | ||||
| 				Array.Clear(v, 0, v.Length); | ||||
| 				MemUtil.ZeroByteArray(pb); | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbNew = utf8.GetBytes(vNew); | ||||
| 			ProtectedString ps = new ProtectedString(m_bIsProtected, pbNew); | ||||
|  | ||||
| 			Debug.Assert(utf8.GetString(pbNew, 0, pbNew.Length) == | ||||
| 				ReadString().Remove(iStart, nCount)); | ||||
|  | ||||
| 			Array.Clear(vNew, 0, vNew.Length); | ||||
| 			MemUtil.ZeroByteArray(pbNew); | ||||
| 			return ps; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,8 +19,8 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,10 +19,10 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Threading; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Threading; | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Resources; | ||||
| @@ -139,7 +137,7 @@ namespace KeePassLib.Serialization | ||||
| 					if(!v[0].StartsWith(LockFileHeader)) { Debug.Assert(false); return null; } | ||||
| 					return new LockFileInfo(v[1], v[2], v[3], v[4], v[5]); | ||||
| 				} | ||||
| 				catch(Java.IO.FileNotFoundException) { } | ||||
| 				catch(FileNotFoundException) { } | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
| 				finally { if(s != null) s.Close(); } | ||||
|  | ||||
| @@ -154,15 +152,17 @@ namespace KeePassLib.Serialization | ||||
| 				try | ||||
| 				{ | ||||
| 					byte[] pbID = CryptoRandom.Instance.GetRandomBytes(16); | ||||
| 					string strTime = TimeUtil.SerializeUtc(DateTime.Now); | ||||
| 					string strTime = TimeUtil.SerializeUtc(DateTime.UtcNow); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 					lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime, | ||||
| #if KeePassUAP | ||||
| 						EnvironmentExt.UserName, EnvironmentExt.MachineName, | ||||
| 						EnvironmentExt.UserDomainName); | ||||
| #elif KeePassLibSD | ||||
| 						string.Empty, string.Empty, string.Empty); | ||||
| #else | ||||
| 						Environment.UserName, Environment.MachineName, | ||||
| 						Environment.UserDomainName); | ||||
| #else | ||||
| 					lfi = new LockFileInfo(Convert.ToBase64String(pbID), strTime, | ||||
| 						string.Empty, string.Empty, string.Empty); | ||||
| #endif | ||||
|  | ||||
| 					StringBuilder sb = new StringBuilder(); | ||||
| @@ -244,8 +244,8 @@ namespace KeePassLib.Serialization | ||||
| 				if(bDisposing) Thread.Sleep(50); | ||||
| 			} | ||||
|  | ||||
| 			if(bDisposing && !bFileDeleted) | ||||
| 				IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception | ||||
| 			// if(bDisposing && !bFileDeleted) | ||||
| 			//	IOConnection.DeleteFile(m_iocLockFile); // Possibly with exception | ||||
|  | ||||
| 			m_iocLockFile = null; | ||||
| 		} | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|  | ||||
| @@ -21,11 +21,11 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| using System.Security.AccessControl; | ||||
| #endif | ||||
|  | ||||
| @@ -44,6 +44,9 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private const string StrTempSuffix = ".tmp"; | ||||
|  | ||||
| 		private static Dictionary<string, bool> g_dEnabled = | ||||
| 			new Dictionary<string, bool>(StrUtil.CaseIgnoreComparer); | ||||
|  | ||||
| 		public FileTransactionEx(IOConnectionInfo iocBaseFile) | ||||
| 		{ | ||||
| 			Initialize(iocBaseFile, true); | ||||
| @@ -101,7 +104,7 @@ namespace KeePassLib.Serialization | ||||
| 		{ | ||||
| 			bool bMadeUnhidden = UrlUtil.UnhideFile(m_iocBase.Path); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
|  | ||||
| 			bool bEfsEncrypted = false; | ||||
| #endif | ||||
| @@ -130,7 +133,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			IOConnection.RenameFile(m_iocTemp, m_iocBase); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			if(m_iocBase.IsLocalFile()) | ||||
| 			{ | ||||
| 				try | ||||
| @@ -148,5 +151,15 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			if(bMadeUnhidden) UrlUtil.HideFile(m_iocBase.Path, true); // Hide again | ||||
| 		} | ||||
|  | ||||
| 		// For plugins | ||||
| 		public static void Configure(string strPrefix, bool? obTransacted) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strPrefix)) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			if(obTransacted.HasValue) | ||||
| 				g_dEnabled[strPrefix] = obTransacted.Value; | ||||
| 			else g_dEnabled.Remove(strPrefix); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|  | ||||
| @@ -20,11 +20,11 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.IO; | ||||
| using System.Security.Cryptography; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| @@ -74,7 +74,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 	public sealed class HashedBlockStream : Stream | ||||
| 	{ | ||||
| 		private const int m_nDefaultBufferSize = 1024 * 1024; // 1 MB | ||||
| 		private const int NbDefaultBufferSize = 1024 * 1024; // 1 MB | ||||
|  | ||||
| 		private Stream m_sBaseStream; | ||||
| 		private bool m_bWriting; | ||||
| @@ -87,7 +87,7 @@ namespace KeePassLib.Serialization | ||||
| 		private byte[] m_pbBuffer; | ||||
| 		private int m_nBufferPos = 0; | ||||
|  | ||||
| 		private uint m_uBufferIndex = 0; | ||||
| 		private uint m_uBlockIndex = 0; | ||||
|  | ||||
| 		public override bool CanRead | ||||
| 		{ | ||||
| @@ -106,13 +106,13 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		public override long Length | ||||
| 		{ | ||||
| 			get { throw new NotSupportedException(); } | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public override long Position | ||||
| 		{ | ||||
| 			get { throw new NotSupportedException(); } | ||||
| 			set { throw new NotSupportedException(); } | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 			set { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public HashedBlockStream(Stream sBaseStream, bool bWriting) | ||||
| @@ -137,25 +137,25 @@ namespace KeePassLib.Serialization | ||||
| 			if(sBaseStream == null) throw new ArgumentNullException("sBaseStream"); | ||||
| 			if(nBufferSize < 0) throw new ArgumentOutOfRangeException("nBufferSize"); | ||||
|  | ||||
| 			if(nBufferSize == 0) nBufferSize = m_nDefaultBufferSize; | ||||
| 			if(nBufferSize == 0) nBufferSize = NbDefaultBufferSize; | ||||
|  | ||||
| 			m_sBaseStream = sBaseStream; | ||||
| 			m_bWriting = bWriting; | ||||
| 			m_bVerify = bVerify; | ||||
|  | ||||
| 			UTF8Encoding utf8 = StrUtil.Utf8; | ||||
| 			if(m_bWriting == false) // Reading mode | ||||
| 			if(!m_bWriting) // Reading mode | ||||
| 			{ | ||||
| 				if(m_sBaseStream.CanRead == false) | ||||
| 				if(!m_sBaseStream.CanRead) | ||||
| 					throw new InvalidOperationException(); | ||||
|  | ||||
| 				m_brInput = new BinaryReader(sBaseStream, utf8); | ||||
|  | ||||
| 				m_pbBuffer = new byte[0]; | ||||
| 				m_pbBuffer = MemUtil.EmptyByteArray; | ||||
| 			} | ||||
| 			else // Writing mode | ||||
| 			{ | ||||
| 				if(m_sBaseStream.CanWrite == false) | ||||
| 				if(!m_sBaseStream.CanWrite) | ||||
| 					throw new InvalidOperationException(); | ||||
|  | ||||
| 				m_bwOutput = new BinaryWriter(sBaseStream, utf8); | ||||
| @@ -169,7 +169,7 @@ namespace KeePassLib.Serialization | ||||
| 			if(m_bWriting) m_bwOutput.Flush(); | ||||
| 		} | ||||
|  | ||||
| #if KeePassRT | ||||
| #if KeePassUAP | ||||
| 		protected override void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if(!disposing) return; | ||||
| @@ -179,7 +179,7 @@ namespace KeePassLib.Serialization | ||||
| #endif | ||||
| 			if(m_sBaseStream != null) | ||||
| 			{ | ||||
| 				if(m_bWriting == false) // Reading mode | ||||
| 				if(!m_bWriting) // Reading mode | ||||
| 				{ | ||||
| 					m_brInput.Close(); | ||||
| 					m_brInput = null; | ||||
| @@ -224,7 +224,7 @@ namespace KeePassLib.Serialization | ||||
| 				if(m_nBufferPos == m_pbBuffer.Length) | ||||
| 				{ | ||||
| 					if(ReadHashedBlock() == false) | ||||
| 						return nCount - nRemaining; // Bytes actually read | ||||
| 						return (nCount - nRemaining); // Bytes actually read | ||||
| 				} | ||||
|  | ||||
| 				int nCopy = Math.Min(m_pbBuffer.Length - m_nBufferPos, nRemaining); | ||||
| @@ -246,9 +246,9 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			m_nBufferPos = 0; | ||||
|  | ||||
| 			if(m_brInput.ReadUInt32() != m_uBufferIndex) | ||||
| 			if(m_brInput.ReadUInt32() != m_uBlockIndex) | ||||
| 				throw new InvalidDataException(); | ||||
| 			++m_uBufferIndex; | ||||
| 			++m_uBlockIndex; | ||||
|  | ||||
| 			byte[] pbStoredHash = m_brInput.ReadBytes(32); | ||||
| 			if((pbStoredHash == null) || (pbStoredHash.Length != 32)) | ||||
| @@ -273,7 +273,7 @@ namespace KeePassLib.Serialization | ||||
| 				} | ||||
|  | ||||
| 				m_bEos = true; | ||||
| 				m_pbBuffer = new byte[0]; | ||||
| 				m_pbBuffer = MemUtil.EmptyByteArray; | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| @@ -283,17 +283,13 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			if(m_bVerify) | ||||
| 			{ | ||||
| 				SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				byte[] pbComputedHash = sha256.ComputeHash(m_pbBuffer); | ||||
| 				byte[] pbComputedHash = CryptoUtil.HashSha256(m_pbBuffer); | ||||
| 				if((pbComputedHash == null) || (pbComputedHash.Length != 32)) | ||||
| 					throw new InvalidOperationException(); | ||||
|  | ||||
| 				for(int iHashPos = 0; iHashPos < 32; ++iHashPos) | ||||
| 				{ | ||||
| 					if(pbStoredHash[iHashPos] != pbComputedHash[iHashPos]) | ||||
| 				if(!MemUtil.ArraysEqual(pbStoredHash, pbComputedHash)) | ||||
| 						throw new InvalidDataException(); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
| @@ -320,26 +316,24 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private void WriteHashedBlock() | ||||
| 		{ | ||||
| 			m_bwOutput.Write(m_uBufferIndex); | ||||
| 			++m_uBufferIndex; | ||||
| 			m_bwOutput.Write(m_uBlockIndex); | ||||
| 			++m_uBlockIndex; | ||||
|  | ||||
| 			if(m_nBufferPos > 0) | ||||
| 			{ | ||||
| 				SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				byte[] pbHash = CryptoUtil.HashSha256(m_pbBuffer, 0, m_nBufferPos); | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 				byte[] pbHash = sha256.ComputeHash(m_pbBuffer, 0, m_nBufferPos); | ||||
| #else | ||||
| 				byte[] pbHash; | ||||
| 				if(m_nBufferPos == m_pbBuffer.Length) | ||||
| 					pbHash = sha256.ComputeHash(m_pbBuffer); | ||||
| 				else | ||||
| 				{ | ||||
| 					byte[] pbData = new byte[m_nBufferPos]; | ||||
| 					Array.Copy(m_pbBuffer, 0, pbData, 0, m_nBufferPos); | ||||
| 					pbHash = sha256.ComputeHash(pbData); | ||||
| 				} | ||||
| #endif | ||||
|  | ||||
| 				// SHA256Managed sha256 = new SHA256Managed(); | ||||
| 				// byte[] pbHash; | ||||
| 				// if(m_nBufferPos == m_pbBuffer.Length) | ||||
| 				//	pbHash = sha256.ComputeHash(m_pbBuffer); | ||||
| 				// else | ||||
| 				// { | ||||
| 				//	byte[] pbData = new byte[m_nBufferPos]; | ||||
| 				//	Array.Copy(m_pbBuffer, 0, pbData, 0, m_nBufferPos); | ||||
| 				//	pbHash = sha256.ComputeHash(pbData); | ||||
| 				// } | ||||
|  | ||||
| 				m_bwOutput.Write(pbHash); | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										325
									
								
								src/KeePassLib2Android/Serialization/HmacBlockStream.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								src/KeePassLib2Android/Serialization/HmacBlockStream.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| { | ||||
| 	public sealed class HmacBlockStream : Stream | ||||
| 	{ | ||||
| 		private const int NbDefaultBufferSize = 1024 * 1024; // 1 MB | ||||
|  | ||||
| 		private Stream m_sBase; | ||||
| 		private readonly bool m_bWriting; | ||||
| 		private readonly bool m_bVerify; | ||||
| 		private byte[] m_pbKey; | ||||
|  | ||||
| 		private bool m_bEos = false; | ||||
| 		private byte[] m_pbBuffer; | ||||
| 		private int m_iBufferPos = 0; | ||||
|  | ||||
| 		private ulong m_uBlockIndex = 0; | ||||
|  | ||||
| 		public override bool CanRead | ||||
| 		{ | ||||
| 			get { return !m_bWriting; } | ||||
| 		} | ||||
|  | ||||
| 		public override bool CanSeek | ||||
| 		{ | ||||
| 			get { return false; } | ||||
| 		} | ||||
|  | ||||
| 		public override bool CanWrite | ||||
| 		{ | ||||
| 			get { return m_bWriting; } | ||||
| 		} | ||||
|  | ||||
| 		public override long Length | ||||
| 		{ | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public override long Position | ||||
| 		{ | ||||
| 			get { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 			set { Debug.Assert(false); throw new NotSupportedException(); } | ||||
| 		} | ||||
|  | ||||
| 		public HmacBlockStream(Stream sBase, bool bWriting, bool bVerify, | ||||
| 			byte[] pbKey) | ||||
| 		{ | ||||
| 			if(sBase == null) throw new ArgumentNullException("sBase"); | ||||
| 			if(pbKey == null) throw new ArgumentNullException("pbKey"); | ||||
|  | ||||
| 			m_sBase = sBase; | ||||
| 			m_bWriting = bWriting; | ||||
| 			m_bVerify = bVerify; | ||||
| 			m_pbKey = pbKey; | ||||
|  | ||||
| 			if(!m_bWriting) // Reading mode | ||||
| 			{ | ||||
| 				if(!m_sBase.CanRead) throw new InvalidOperationException(); | ||||
|  | ||||
| 				m_pbBuffer = MemUtil.EmptyByteArray; | ||||
| 			} | ||||
| 			else // Writing mode | ||||
| 			{ | ||||
| 				if(!m_sBase.CanWrite) throw new InvalidOperationException(); | ||||
|  | ||||
| 				m_pbBuffer = new byte[NbDefaultBufferSize]; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		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) | ||||
| 		{ | ||||
| 			if(!disposing) return; | ||||
| #else | ||||
| 		public override void Close() | ||||
| 		{ | ||||
| #endif | ||||
| 			if(m_sBase != null) | ||||
| 			{ | ||||
| 				if(m_bWriting) | ||||
| 				{ | ||||
| 					if(m_iBufferPos == 0) // No data left in buffer | ||||
| 						WriteSafeBlock(); // Write terminating block | ||||
| 					else | ||||
| 					{ | ||||
| 						WriteSafeBlock(); // Write remaining buffered data | ||||
| 						WriteSafeBlock(); // Write terminating block | ||||
| 					} | ||||
|  | ||||
| 					Flush(); | ||||
| 				} | ||||
|  | ||||
| 				m_sBase.Close(); | ||||
| 				m_sBase = null; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public override long Seek(long lOffset, SeekOrigin soOrigin) | ||||
| 		{ | ||||
| 			Debug.Assert(false); | ||||
| 			throw new NotSupportedException(); | ||||
| 		} | ||||
|  | ||||
| 		public override void SetLength(long lValue) | ||||
| 		{ | ||||
| 			Debug.Assert(false); | ||||
| 			throw new NotSupportedException(); | ||||
| 		} | ||||
|  | ||||
| 		internal static byte[] GetHmacKey64(byte[] pbKey, ulong uBlockIndex) | ||||
| 		{ | ||||
| 			if(pbKey == null) throw new ArgumentNullException("pbKey"); | ||||
| 			Debug.Assert(pbKey.Length == 64); | ||||
|  | ||||
| 			// We are computing the HMAC using SHA-256, whose internal | ||||
| 			// block size is 512 bits; thus create a key that is 512 | ||||
| 			// bits long (using SHA-512) | ||||
|  | ||||
| 			byte[] pbBlockKey; | ||||
| 			using(SHA512Managed h = new SHA512Managed()) | ||||
| 			{ | ||||
| 				byte[] pbIndex = MemUtil.UInt64ToBytes(uBlockIndex); | ||||
|  | ||||
| 				h.TransformBlock(pbIndex, 0, pbIndex.Length, pbIndex, 0); | ||||
| 				h.TransformBlock(pbKey, 0, pbKey.Length, pbKey, 0); | ||||
| 				h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
|  | ||||
| 				pbBlockKey = h.Hash; | ||||
| 			} | ||||
|  | ||||
| #if DEBUG | ||||
| 			byte[] pbZero = new byte[64]; | ||||
| 			Debug.Assert((pbBlockKey.Length == 64) && !MemUtil.ArraysEqual( | ||||
| 				pbBlockKey, pbZero)); // Ensure we own pbBlockKey | ||||
| #endif | ||||
| 			return pbBlockKey; | ||||
| 		} | ||||
|  | ||||
| 		public override int Read(byte[] pbBuffer, int iOffset, int nCount) | ||||
| 		{ | ||||
| 			if(m_bWriting) throw new InvalidOperationException(); | ||||
|  | ||||
| 			int nRemaining = nCount; | ||||
| 			while(nRemaining > 0) | ||||
| 			{ | ||||
| 				if(m_iBufferPos == m_pbBuffer.Length) | ||||
| 				{ | ||||
| 					if(!ReadSafeBlock()) | ||||
| 						return (nCount - nRemaining); // Bytes actually read | ||||
| 				} | ||||
|  | ||||
| 				int nCopy = Math.Min(m_pbBuffer.Length - m_iBufferPos, nRemaining); | ||||
| 				Debug.Assert(nCopy > 0); | ||||
|  | ||||
| 				Array.Copy(m_pbBuffer, m_iBufferPos, pbBuffer, iOffset, nCopy); | ||||
|  | ||||
| 				iOffset += nCopy; | ||||
| 				m_iBufferPos += nCopy; | ||||
|  | ||||
| 				nRemaining -= nCopy; | ||||
| 			} | ||||
|  | ||||
| 			return nCount; | ||||
| 		} | ||||
|  | ||||
| 		private bool ReadSafeBlock() | ||||
| 		{ | ||||
| 			if(m_bEos) return false; // End of stream reached already | ||||
|  | ||||
| 			byte[] pbStoredHmac = MemUtil.Read(m_sBase, 32); | ||||
| 			if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) | ||||
| 				throw new EndOfStreamException(); | ||||
|  | ||||
| 			// Block index is implicit: it's used in the HMAC computation, | ||||
| 			// but does not need to be stored | ||||
| 			// byte[] pbBlockIndex = MemUtil.Read(m_sBase, 8); | ||||
| 			// if((pbBlockIndex == null) || (pbBlockIndex.Length != 8)) | ||||
| 			//	throw new EndOfStreamException(); | ||||
| 			// ulong uBlockIndex = MemUtil.BytesToUInt64(pbBlockIndex); | ||||
| 			// if((uBlockIndex != m_uBlockIndex) && m_bVerify) | ||||
| 			//	throw new InvalidDataException(); | ||||
| 			byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); | ||||
|  | ||||
| 			byte[] pbBlockSize = MemUtil.Read(m_sBase, 4); | ||||
| 			if((pbBlockSize == null) || (pbBlockSize.Length != 4)) | ||||
| 				throw new EndOfStreamException(); | ||||
| 			int nBlockSize = MemUtil.BytesToInt32(pbBlockSize); | ||||
| 			if(nBlockSize < 0) | ||||
| 				throw new InvalidDataException(KLRes.FileCorrupted); | ||||
|  | ||||
| 			m_iBufferPos = 0; | ||||
|  | ||||
| 			m_pbBuffer = MemUtil.Read(m_sBase, nBlockSize); | ||||
| 			if((m_pbBuffer == null) || ((m_pbBuffer.Length != nBlockSize) && m_bVerify)) | ||||
| 				throw new EndOfStreamException(); | ||||
|  | ||||
| 			if(m_bVerify) | ||||
| 			{ | ||||
| 				byte[] pbCmpHmac; | ||||
| 				byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); | ||||
| 				using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) | ||||
| 				{ | ||||
| 					h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, | ||||
| 						pbBlockIndex, 0); | ||||
| 					h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, | ||||
| 						pbBlockSize, 0); | ||||
|  | ||||
| 					if(m_pbBuffer.Length > 0) | ||||
| 						h.TransformBlock(m_pbBuffer, 0, m_pbBuffer.Length, | ||||
| 							m_pbBuffer, 0); | ||||
|  | ||||
| 					h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
|  | ||||
| 					pbCmpHmac = h.Hash; | ||||
| 				} | ||||
| 				MemUtil.ZeroByteArray(pbBlockKey); | ||||
|  | ||||
| 				if(!MemUtil.ArraysEqual(pbCmpHmac, pbStoredHmac)) | ||||
| 					throw new InvalidDataException(KLRes.FileCorrupted); | ||||
| 			} | ||||
|  | ||||
| 			++m_uBlockIndex; | ||||
|  | ||||
| 			if(nBlockSize == 0) | ||||
| 			{ | ||||
| 				m_bEos = true; | ||||
| 				return false; // No further data available | ||||
| 			} | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public override void Write(byte[] pbBuffer, int iOffset, int nCount) | ||||
| 		{ | ||||
| 			if(!m_bWriting) throw new InvalidOperationException(); | ||||
|  | ||||
| 			while(nCount > 0) | ||||
| 			{ | ||||
| 				if(m_iBufferPos == m_pbBuffer.Length) | ||||
| 					WriteSafeBlock(); | ||||
|  | ||||
| 				int nCopy = Math.Min(m_pbBuffer.Length - m_iBufferPos, nCount); | ||||
| 				Debug.Assert(nCopy > 0); | ||||
|  | ||||
| 				Array.Copy(pbBuffer, iOffset, m_pbBuffer, m_iBufferPos, nCopy); | ||||
|  | ||||
| 				iOffset += nCopy; | ||||
| 				m_iBufferPos += nCopy; | ||||
|  | ||||
| 				nCount -= nCopy; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private void WriteSafeBlock() | ||||
| 		{ | ||||
| 			byte[] pbBlockIndex = MemUtil.UInt64ToBytes(m_uBlockIndex); | ||||
|  | ||||
| 			int cbBlockSize = m_iBufferPos; | ||||
| 			byte[] pbBlockSize = MemUtil.Int32ToBytes(cbBlockSize); | ||||
|  | ||||
| 			byte[] pbBlockHmac; | ||||
| 			byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); | ||||
| 			using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) | ||||
| 			{ | ||||
| 				h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, | ||||
| 					pbBlockIndex, 0); | ||||
| 				h.TransformBlock(pbBlockSize, 0, pbBlockSize.Length, | ||||
| 					pbBlockSize, 0); | ||||
|  | ||||
| 				if(cbBlockSize > 0) | ||||
| 					h.TransformBlock(m_pbBuffer, 0, cbBlockSize, m_pbBuffer, 0); | ||||
|  | ||||
| 				h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); | ||||
|  | ||||
| 				pbBlockHmac = h.Hash; | ||||
| 			} | ||||
| 			MemUtil.ZeroByteArray(pbBlockKey); | ||||
|  | ||||
| 			MemUtil.Write(m_sBase, pbBlockHmac); | ||||
| 			// MemUtil.Write(m_sBase, pbBlockIndex); // Implicit | ||||
| 			MemUtil.Write(m_sBase, pbBlockSize); | ||||
| 			if(cbBlockSize > 0) | ||||
| 				m_sBase.Write(m_pbBuffer, 0, cbBlockSize); | ||||
|  | ||||
| 			++m_uBlockIndex; | ||||
| 			m_iBufferPos = 0; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,12 +19,11 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Net; | ||||
| using System.ComponentModel; | ||||
| using System.Xml.Serialization; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Xml.Serialization; | ||||
|  | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Utility; | ||||
| @@ -122,7 +121,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private bool m_bComplete = false; | ||||
| 		[XmlIgnore] | ||||
| 		internal bool IsComplete // Credentials etc. fully specified | ||||
| 		public bool IsComplete // Credentials etc. fully specified | ||||
| 		{ | ||||
| 			get { return m_bComplete; } | ||||
| 			set { m_bComplete = value; } | ||||
| @@ -134,16 +133,53 @@ namespace KeePassLib.Serialization | ||||
| 			set { m_ioHint = value; } | ||||
| 		} */ | ||||
|  | ||||
| 		public IOConnectionInfo CloneDeep() | ||||
| 		private IocProperties m_props = new IocProperties(); | ||||
| 		[XmlIgnore] | ||||
| 		public IocProperties Properties | ||||
| 		{ | ||||
| 			return (IOConnectionInfo)this.MemberwiseClone(); | ||||
| 			get { return m_props; } | ||||
| 			set | ||||
| 			{ | ||||
| 				if(value == null) throw new ArgumentNullException("value"); | ||||
| 				m_props = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// For serialization only; use <c>Properties</c> in code. | ||||
| 		/// </summary> | ||||
| 		[DefaultValue("")] | ||||
| 		public string PropertiesEx | ||||
| 		{ | ||||
| 			get { return m_props.Serialize(); } | ||||
| 			set | ||||
| 			{ | ||||
| 				if(value == null) throw new ArgumentNullException("value"); | ||||
|  | ||||
| 				IocProperties p = IocProperties.Deserialize(value); | ||||
| 				Debug.Assert(p != null); | ||||
| 				m_props = (p ?? new IocProperties()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public IOConnectionInfo CloneDeep() | ||||
| 		{ | ||||
| 			IOConnectionInfo ioc = (IOConnectionInfo)this.MemberwiseClone(); | ||||
| 			ioc.m_props = m_props.CloneDeep(); | ||||
| 			return ioc; | ||||
| 		} | ||||
|  | ||||
| #if DEBUG // For debugger display only | ||||
| 		public override string ToString() | ||||
| 		{ | ||||
| 			return GetDisplayName(); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		 | ||||
| 		/// <summary> | ||||
| 		/// Serialize the current connection info to a string. Credentials | ||||
| 		/// are only serialized if the <c>SaveCredentials</c> property | ||||
| 		/// is <c>true</c>. | ||||
| 		/// are serialized based on the <c>CredSaveMode</c> property. | ||||
| 		/// </summary> | ||||
| 		/// <param name="iocToCompile">Input object to be serialized.</param> | ||||
| 		/// <returns>Serialized object as string.</returns> | ||||
| @@ -215,9 +251,8 @@ namespace KeePassLib.Serialization | ||||
| 			s.Password = TransformUnreadable(vParts[3], false); | ||||
| 			return s; | ||||
| 		} | ||||
|  | ||||
|  | ||||
|  | ||||
| 		 | ||||
| 		 | ||||
| 		/// <summary> | ||||
| 		/// Very simple string protection. Doesn't really encrypt the input | ||||
| 		/// string, only encodes it that it's not readable on the first glance. | ||||
| @@ -256,21 +291,21 @@ namespace KeePassLib.Serialization | ||||
| 				return StrUtil.Utf8.GetString(pbBase, 0, pbBase.Length); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		 | ||||
|  | ||||
| 		public string GetDisplayName() | ||||
| 		{ | ||||
| 			string str = m_strUrl; | ||||
|  | ||||
| 			if(m_strUser.Length > 0) | ||||
| 				str += " (" + m_strUser + ")"; | ||||
| 				str += (" (" + m_strUser + ")"); | ||||
|  | ||||
| 			return str; | ||||
| 		} | ||||
|  | ||||
| 		public bool IsEmpty() | ||||
| 		{ | ||||
| 			return (m_strUrl.Length > 0); | ||||
| 			return (m_strUrl.Length == 0); | ||||
| 		} | ||||
|  | ||||
| 		public static IOConnectionInfo FromPath(string strPath) | ||||
| @@ -293,7 +328,7 @@ namespace KeePassLib.Serialization | ||||
| 		public bool IsLocalFile() | ||||
| 		{ | ||||
| 			// Not just ":/", see e.g. AppConfigEx.ChangePathRelAbs | ||||
| 			return (m_strUrl.IndexOf(@"://") < 0); | ||||
| 			return (m_strUrl.IndexOf("://") < 0); | ||||
| 		} | ||||
|  | ||||
| 		public void ClearCredentials(bool bDependingOnRememberMode) | ||||
|   | ||||
							
								
								
									
										192
									
								
								src/KeePassLib2Android/Serialization/IocProperties.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/KeePassLib2Android/Serialization/IocProperties.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| using StrDict = System.Collections.Generic.Dictionary<string, string>; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| { | ||||
| 	public interface IHasIocProperties | ||||
| 	{ | ||||
| 		IocProperties IOConnectionProperties { get; set; } | ||||
| 	} | ||||
|  | ||||
| 	public sealed class IocProperties : IDeepCloneable<IocProperties> | ||||
| 	{ | ||||
| 		private StrDict m_dict = new StrDict(); | ||||
|  | ||||
| 		public IocProperties() | ||||
| 		{ | ||||
| 		} | ||||
|  | ||||
| 		public IocProperties CloneDeep() | ||||
| 		{ | ||||
| 			IocProperties p = new IocProperties(); | ||||
| 			p.m_dict = new StrDict(m_dict); | ||||
| 			return p; | ||||
| 		} | ||||
|  | ||||
| 		public string Get(string strKey) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strKey)) return null; | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 			{ | ||||
| 				if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp)) | ||||
| 					return kvp.Value; | ||||
| 			} | ||||
|  | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public void Set(string strKey, string strValue) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strKey)) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 			{ | ||||
| 				if(kvp.Key.Equals(strKey, StrUtil.CaseIgnoreCmp)) | ||||
| 				{ | ||||
| 					if(string.IsNullOrEmpty(strValue)) m_dict.Remove(kvp.Key); | ||||
| 					else m_dict[kvp.Key] = strValue; | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(!string.IsNullOrEmpty(strValue)) m_dict[strKey] = strValue; | ||||
| 		} | ||||
|  | ||||
| 		public bool? GetBool(string strKey) | ||||
| 		{ | ||||
| 			string str = Get(strKey); | ||||
| 			if(string.IsNullOrEmpty(str)) return null; | ||||
|  | ||||
| 			return StrUtil.StringToBool(str); | ||||
| 		} | ||||
|  | ||||
| 		public void SetBool(string strKey, bool? ob) | ||||
| 		{ | ||||
| 			if(ob.HasValue) Set(strKey, (ob.Value ? "1" : "0")); | ||||
| 			else Set(strKey, null); | ||||
| 		} | ||||
|  | ||||
| 		public long? GetLong(string strKey) | ||||
| 		{ | ||||
| 			string str = Get(strKey); | ||||
| 			if(string.IsNullOrEmpty(str)) return null; | ||||
|  | ||||
| 			long l; | ||||
| 			if(StrUtil.TryParseLongInvariant(str, out l)) return l; | ||||
| 			Debug.Assert(false); | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public void SetLong(string strKey, long? ol) | ||||
| 		{ | ||||
| 			if(ol.HasValue) | ||||
| 				Set(strKey, ol.Value.ToString(NumberFormatInfo.InvariantInfo)); | ||||
| 			else Set(strKey, null); | ||||
| 		} | ||||
|  | ||||
| 		public string Serialize() | ||||
| 		{ | ||||
| 			if(m_dict.Count == 0) return string.Empty; | ||||
|  | ||||
| 			StringBuilder sbAll = new StringBuilder(); | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 			{ | ||||
| 				sbAll.Append(kvp.Key); | ||||
| 				sbAll.Append(kvp.Value); | ||||
| 			} | ||||
|  | ||||
| 			string strAll = sbAll.ToString(); | ||||
| 			char chSepOuter = ';'; | ||||
| 			if(strAll.IndexOf(chSepOuter) >= 0) | ||||
| 				chSepOuter = StrUtil.GetUnusedChar(strAll); | ||||
|  | ||||
| 			strAll += chSepOuter; | ||||
| 			char chSepInner = '='; | ||||
| 			if(strAll.IndexOf(chSepInner) >= 0) | ||||
| 				chSepInner = StrUtil.GetUnusedChar(strAll); | ||||
|  | ||||
| 			StringBuilder sb = new StringBuilder(); | ||||
| 			sb.Append(chSepOuter); | ||||
| 			sb.Append(chSepInner); | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 			{ | ||||
| 				sb.Append(chSepOuter); | ||||
| 				sb.Append(kvp.Key); | ||||
| 				sb.Append(chSepInner); | ||||
| 				sb.Append(kvp.Value); | ||||
| 			} | ||||
|  | ||||
| 			return sb.ToString(); | ||||
| 		} | ||||
|  | ||||
| 		public static IocProperties Deserialize(string strSerialized) | ||||
| 		{ | ||||
| 			IocProperties p = new IocProperties(); | ||||
| 			if(string.IsNullOrEmpty(strSerialized)) return p; // No assert | ||||
|  | ||||
| 			char chSepOuter = strSerialized[0]; | ||||
| 			string[] v = strSerialized.Substring(1).Split(new char[] { chSepOuter }); | ||||
| 			if((v == null) || (v.Length < 2)) { Debug.Assert(false); return p; } | ||||
|  | ||||
| 			string strMeta = v[0]; | ||||
| 			if(string.IsNullOrEmpty(strMeta)) { Debug.Assert(false); return p; } | ||||
|  | ||||
| 			char chSepInner = strMeta[0]; | ||||
| 			char[] vSepInner = new char[] { chSepInner }; | ||||
|  | ||||
| 			for(int i = 1; i < v.Length; ++i) | ||||
| 			{ | ||||
| 				string strProp = v[i]; | ||||
| 				if(string.IsNullOrEmpty(strProp)) { Debug.Assert(false); continue; } | ||||
|  | ||||
| 				string[] vProp = strProp.Split(vSepInner); | ||||
| 				if((vProp == null) || (vProp.Length < 2)) { Debug.Assert(false); continue; } | ||||
| 				Debug.Assert(vProp.Length == 2); | ||||
|  | ||||
| 				p.Set(vProp[0], vProp[1]); | ||||
| 			} | ||||
|  | ||||
| 			return p; | ||||
| 		} | ||||
|  | ||||
| 		public void CopyTo(IocProperties p) | ||||
| 		{ | ||||
| 			if(p == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			foreach(KeyValuePair<string, string> kvp in m_dict) | ||||
| 			{ | ||||
| 				p.m_dict[kvp.Key] = kvp.Value; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										99
									
								
								src/KeePassLib2Android/Serialization/IocPropertyInfo.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/KeePassLib2Android/Serialization/IocPropertyInfo.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| { | ||||
| 	public sealed class IocPropertyInfo | ||||
| 	{ | ||||
| 		private readonly string m_strName; | ||||
| 		public string Name | ||||
| 		{ | ||||
| 			get { return m_strName; } | ||||
| 		} | ||||
|  | ||||
| 		private readonly Type m_t; | ||||
| 		public Type Type | ||||
| 		{ | ||||
| 			get { return m_t; } | ||||
| 		} | ||||
|  | ||||
| 		private string m_strDisplayName; | ||||
| 		public string DisplayName | ||||
| 		{ | ||||
| 			get { return m_strDisplayName; } | ||||
| 			set | ||||
| 			{ | ||||
| 				if(value == null) throw new ArgumentNullException("value"); | ||||
| 				m_strDisplayName = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private List<string> m_lProtocols = new List<string>(); | ||||
| 		public IEnumerable<string> Protocols | ||||
| 		{ | ||||
| 			get { return m_lProtocols; } | ||||
| 		} | ||||
|  | ||||
| 		public IocPropertyInfo(string strName, Type t, string strDisplayName, | ||||
| 			string[] vProtocols) | ||||
| 		{ | ||||
| 			if(strName == null) throw new ArgumentNullException("strName"); | ||||
| 			if(t == null) throw new ArgumentNullException("t"); | ||||
| 			if(strDisplayName == null) throw new ArgumentNullException("strDisplayName"); | ||||
|  | ||||
| 			m_strName = strName; | ||||
| 			m_t = t; | ||||
| 			m_strDisplayName = strDisplayName; | ||||
|  | ||||
| 			AddProtocols(vProtocols); | ||||
| 		} | ||||
|  | ||||
| 		public void AddProtocols(string[] v) | ||||
| 		{ | ||||
| 			if(v == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			foreach(string strProtocol in v) | ||||
| 			{ | ||||
| 				if(strProtocol == null) continue; | ||||
|  | ||||
| 				string str = strProtocol.Trim(); | ||||
| 				if(str.Length == 0) continue; | ||||
|  | ||||
| 				bool bFound = false; | ||||
| 				foreach(string strEx in m_lProtocols) | ||||
| 				{ | ||||
| 					if(strEx.Equals(str, StrUtil.CaseIgnoreCmp)) | ||||
| 					{ | ||||
| 						bFound = true; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if(!bFound) m_lProtocols.Add(str); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										123
									
								
								src/KeePassLib2Android/Serialization/IocPropertyInfoPool.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/KeePassLib2Android/Serialization/IocPropertyInfoPool.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| { | ||||
| 	public static class IocKnownProtocols | ||||
| 	{ | ||||
| 		public const string Http = "HTTP"; | ||||
| 		public const string Https = "HTTPS"; | ||||
| 		public const string WebDav = "WebDAV"; | ||||
| 		public const string Ftp = "FTP"; | ||||
| 	} | ||||
|  | ||||
| 	public static class IocKnownProperties | ||||
| 	{ | ||||
| 		public const string Timeout = "Timeout"; | ||||
| 		public const string PreAuth = "PreAuth"; | ||||
|  | ||||
| 		public const string UserAgent = "UserAgent"; | ||||
| 		public const string Expect100Continue = "Expect100Continue"; | ||||
|  | ||||
| 		public const string Passive = "Passive"; | ||||
| 	} | ||||
|  | ||||
| 	public static class IocPropertyInfoPool | ||||
| 	{ | ||||
| 		private static List<IocPropertyInfo> m_l = null; | ||||
| 		public static IEnumerable<IocPropertyInfo> PropertyInfos | ||||
| 		{ | ||||
| 			get { EnsureInitialized(); return m_l; } | ||||
| 		} | ||||
|  | ||||
| 		private static void EnsureInitialized() | ||||
| 		{ | ||||
| 			if(m_l != null) return; | ||||
|  | ||||
| 			string strGen = KLRes.General; | ||||
| 			string strHttp = IocKnownProtocols.Http; | ||||
| 			string strHttps = IocKnownProtocols.Https; | ||||
| 			string strWebDav = IocKnownProtocols.WebDav; | ||||
| 			string strFtp = IocKnownProtocols.Ftp; | ||||
|  | ||||
| 			string[] vGen = new string[] { strGen }; | ||||
| 			string[] vHttp = new string[] { strHttp, strHttps, strWebDav }; | ||||
| 			string[] vFtp = new string[] { strFtp }; | ||||
|  | ||||
| 			List<IocPropertyInfo> l = new List<IocPropertyInfo>(); | ||||
|  | ||||
| 			l.Add(new IocPropertyInfo(IocKnownProperties.Timeout, | ||||
| 				typeof(long), KLRes.Timeout + " [ms]", vGen)); | ||||
| 			l.Add(new IocPropertyInfo(IocKnownProperties.PreAuth, | ||||
| 				typeof(bool), KLRes.PreAuth, vGen)); | ||||
|  | ||||
| 			l.Add(new IocPropertyInfo(IocKnownProperties.UserAgent, | ||||
| 				typeof(string), KLRes.UserAgent, vHttp)); | ||||
| 			l.Add(new IocPropertyInfo(IocKnownProperties.Expect100Continue, | ||||
| 				typeof(bool), KLRes.Expect100Continue, vHttp)); | ||||
|  | ||||
| 			l.Add(new IocPropertyInfo(IocKnownProperties.Passive, | ||||
| 				typeof(bool), KLRes.Passive, vFtp)); | ||||
|  | ||||
| 			// l.Add(new IocPropertyInfo("Test", typeof(bool), | ||||
| 			//	"Long long long long long long long long long long long long long long long long long long long long", | ||||
| 			//	new string[] { "Proto 1/9", "Proto 2/9", "Proto 3/9", "Proto 4/9", "Proto 5/9", | ||||
| 			//	"Proto 6/9", "Proto 7/9", "Proto 8/9", "Proto 9/9" })); | ||||
|  | ||||
| 			m_l = l; | ||||
| 		} | ||||
|  | ||||
| 		public static IocPropertyInfo Get(string strName) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return null; } | ||||
|  | ||||
| 			EnsureInitialized(); | ||||
| 			foreach(IocPropertyInfo pi in m_l) | ||||
| 			{ | ||||
| 				if(pi.Name.Equals(strName, StrUtil.CaseIgnoreCmp)) | ||||
| 					return pi; | ||||
| 			} | ||||
|  | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		public static bool Add(IocPropertyInfo pi) | ||||
| 		{ | ||||
| 			if(pi == null) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			// Name must be non-empty | ||||
| 			string strName = pi.Name; | ||||
| 			if(string.IsNullOrEmpty(strName)) { Debug.Assert(false); return false; } | ||||
|  | ||||
| 			IocPropertyInfo piEx = Get(strName); // Ensures initialized | ||||
| 			if(piEx != null) { Debug.Assert(false); return false; } // Exists already | ||||
|  | ||||
| 			m_l.Add(pi); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,18 +19,17 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.Drawing; | ||||
| using System.Xml; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Drawing; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib; | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Security; | ||||
| @@ -45,49 +42,6 @@ namespace KeePassLib.Serialization | ||||
| 	/// </summary> | ||||
| 	public sealed partial class KdbxFile | ||||
| 	{ | ||||
| 		private class ColorTranslator | ||||
| 		{ | ||||
| 			public static Color FromHtml(String colorString) | ||||
| 			{ | ||||
| 				Color color; | ||||
| 				 | ||||
| 				if (colorString.StartsWith("#")) | ||||
| 				{ | ||||
| 					colorString = colorString.Substring(1); | ||||
| 				} | ||||
| 				if (colorString.EndsWith(";")) | ||||
| 				{ | ||||
| 					colorString = colorString.Substring(0, colorString.Length - 1); | ||||
| 				} | ||||
| 				 | ||||
| 				int red, green, blue; | ||||
| 				switch (colorString.Length) | ||||
| 				{ | ||||
| 				case 6: | ||||
| 					red = int.Parse(colorString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 					green = int.Parse(colorString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 					blue = int.Parse(colorString.Substring(4, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 					color = Color.FromArgb(red, green, blue); | ||||
| 					break; | ||||
| 				case 3: | ||||
| 					red = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 					green = int.Parse(colorString.Substring(1, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 					blue = int.Parse(colorString.Substring(2, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 					color = Color.FromArgb(red, green, blue); | ||||
| 					break; | ||||
| 				case 1: | ||||
| 					red = green = blue = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 					color = Color.FromArgb(red, green, blue); | ||||
| 					break; | ||||
| 				default: | ||||
| 					throw new ArgumentException("Invalid color: " + colorString); | ||||
| 				} | ||||
| 				return color; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		private enum KdbContext | ||||
| 		{ | ||||
| 			Null, | ||||
| @@ -104,13 +58,17 @@ namespace KeePassLib.Serialization | ||||
| 			DeletedObject, | ||||
| 			Group, | ||||
| 			GroupTimes, | ||||
| 			GroupCustomData, | ||||
| 			GroupCustomDataItem, | ||||
| 			Entry, | ||||
| 			EntryTimes, | ||||
| 			EntryString, | ||||
| 			EntryBinary, | ||||
| 			EntryAutoType, | ||||
| 			EntryAutoTypeItem, | ||||
| 			EntryHistory | ||||
| 			EntryHistory, | ||||
| 			EntryCustomData, | ||||
| 			EntryCustomDataItem | ||||
| 		} | ||||
|  | ||||
| 		private bool m_bReadNextNode = true; | ||||
| @@ -130,10 +88,14 @@ namespace KeePassLib.Serialization | ||||
| 		private byte[] m_pbCustomIconData = null; | ||||
| 		private string m_strCustomDataKey = null; | ||||
| 		private string m_strCustomDataValue = null; | ||||
| 		private string m_strGroupCustomDataKey = null; | ||||
| 		private string m_strGroupCustomDataValue = null; | ||||
| 		private string m_strEntryCustomDataKey = null; | ||||
| 		private string m_strEntryCustomDataValue = null; | ||||
|  | ||||
| 		private void ReadXmlStreamed(Stream readerStream, Stream sParentStream) | ||||
| 		private void ReadXmlStreamed(Stream sXml, Stream sParent) | ||||
| 		{ | ||||
| 			ReadDocumentStreamed(CreateXmlReader(readerStream), sParentStream); | ||||
| 			ReadDocumentStreamed(CreateXmlReader(sXml), sParent); | ||||
| 		} | ||||
|  | ||||
| 		internal static XmlReaderSettings CreateStdXmlReaderSettings() | ||||
| @@ -145,9 +107,12 @@ namespace KeePassLib.Serialization | ||||
| 			xrs.IgnoreProcessingInstructions = true; | ||||
| 			xrs.IgnoreWhitespace = true; | ||||
|  | ||||
| #if !KeePassRT | ||||
| #if KeePassUAP | ||||
| 			xrs.DtdProcessing = DtdProcessing.Prohibit; | ||||
| #else | ||||
| #if !KeePassLibSD | ||||
| 			xrs.ProhibitDtd = true; | ||||
| 			xrs.ProhibitDtd = true; // Obsolete in .NET 4, but still there | ||||
| 			// xrs.DtdProcessing = DtdProcessing.Prohibit; // .NET 4 only | ||||
| #endif | ||||
| 			xrs.ValidationType = ValidationType.None; | ||||
| #endif | ||||
| @@ -258,15 +223,25 @@ namespace KeePassLib.Serialization | ||||
| 						ReadString(xr); // Ignore | ||||
| 					else if(xr.Name == ElemHeaderHash) | ||||
| 					{ | ||||
| 						// The header hash is typically only stored in | ||||
| 						// KDBX <= 3.1 files, not in KDBX >= 4 files | ||||
| 						// (here, the header is verified via a HMAC), | ||||
| 						// but we also support it for KDBX >= 4 files | ||||
| 						// (i.e. if it's present, we check it) | ||||
|  | ||||
| 						string strHash = ReadString(xr); | ||||
| 						if(!string.IsNullOrEmpty(strHash) && (m_pbHashOfHeader != null) && | ||||
| 							!m_bRepairMode) | ||||
| 						{ | ||||
| 							Debug.Assert(m_uFileVersion <= FileVersion32_3); | ||||
|  | ||||
| 							byte[] pbHash = Convert.FromBase64String(strHash); | ||||
| 							if(!MemUtil.ArraysEqual(pbHash, m_pbHashOfHeader)) | ||||
| 								throw new IOException(KLRes.FileCorrupted); | ||||
| 						} | ||||
| 					} | ||||
| 					else if(xr.Name == ElemSettingsChanged) | ||||
| 						m_pwDatabase.SettingsChanged = ReadTime(xr); | ||||
| 					else if(xr.Name == ElemDbName) | ||||
| 						m_pwDatabase.Name = ReadString(xr); | ||||
| 					else if(xr.Name == ElemDbNameChanged) | ||||
| @@ -426,6 +401,8 @@ namespace KeePassLib.Serialization | ||||
| 						m_ctxGroup.EnableSearching = StrUtil.StringToBoolEx(ReadString(xr)); | ||||
| 					else if(xr.Name == ElemLastTopVisibleEntry) | ||||
| 						m_ctxGroup.LastTopVisibleEntry = ReadUuid(xr); | ||||
| 					else if(xr.Name == ElemCustomData) | ||||
| 						return SwitchContext(ctx, KdbContext.GroupCustomData, xr); | ||||
| 					else if(xr.Name == ElemGroup) | ||||
| 					{ | ||||
| 						m_ctxGroup = new PwGroup(false, false); | ||||
| @@ -446,6 +423,20 @@ namespace KeePassLib.Serialization | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.GroupCustomData: | ||||
| 					if(xr.Name == ElemStringDictExItem) | ||||
| 						return SwitchContext(ctx, KdbContext.GroupCustomDataItem, xr); | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.GroupCustomDataItem: | ||||
| 					if(xr.Name == ElemKey) | ||||
| 						m_strGroupCustomDataKey = ReadString(xr); | ||||
| 					else if(xr.Name == ElemValue) | ||||
| 						m_strGroupCustomDataValue = ReadString(xr); | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.Entry: | ||||
| 					if(xr.Name == ElemUuid) | ||||
| 						m_ctxEntry.Uuid = ReadUuid(xr); | ||||
| @@ -477,6 +468,8 @@ namespace KeePassLib.Serialization | ||||
| 						return SwitchContext(ctx, KdbContext.EntryBinary, xr); | ||||
| 					else if(xr.Name == ElemAutoType) | ||||
| 						return SwitchContext(ctx, KdbContext.EntryAutoType, xr); | ||||
| 					else if(xr.Name == ElemCustomData) | ||||
| 						return SwitchContext(ctx, KdbContext.EntryCustomData, xr); | ||||
| 					else if(xr.Name == ElemHistory) | ||||
| 					{ | ||||
| 						Debug.Assert(m_bEntryInHistory == false); | ||||
| @@ -497,15 +490,15 @@ namespace KeePassLib.Serialization | ||||
| 						(ITimeLogger)m_ctxGroup : (ITimeLogger)m_ctxEntry); | ||||
| 					Debug.Assert(tl != null); | ||||
|  | ||||
| 					if(xr.Name == ElemLastModTime) | ||||
| 						tl.SetLazyLastModificationTime(ReadString(xr)); | ||||
| 					else if(xr.Name == ElemCreationTime) | ||||
| 					if(xr.Name == ElemCreationTime) | ||||
| 						tl.SetLazyCreationTime(ReadString(xr)); | ||||
| 					else if(xr.Name == ElemLastAccessTime) | ||||
| 					else if (xr.Name == ElemLastModTime) | ||||
| 						tl.SetLazyLastModificationTime(ReadString(xr)); | ||||
| 					else if (xr.Name == ElemLastAccessTime) | ||||
| 						tl.SetLazyLastAccessTime(ReadString(xr)); | ||||
| 					else if(xr.Name == ElemExpiryTime) | ||||
| 					else if (xr.Name == ElemExpiryTime) | ||||
| 						tl.SetLazyExpiryTime(ReadString(xr)); | ||||
| 					else if(xr.Name == ElemExpires) | ||||
| 					else if (xr.Name == ElemExpires) | ||||
| 						tl.Expires = ReadBool(xr, false); | ||||
| 					else if(xr.Name == ElemUsageCount) | ||||
| 						tl.UsageCount = ReadULong(xr, 0); | ||||
| @@ -551,6 +544,20 @@ namespace KeePassLib.Serialization | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.EntryCustomData: | ||||
| 					if(xr.Name == ElemStringDictExItem) | ||||
| 						return SwitchContext(ctx, KdbContext.EntryCustomDataItem, xr); | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.EntryCustomDataItem: | ||||
| 					if(xr.Name == ElemKey) | ||||
| 						m_strEntryCustomDataKey = ReadString(xr); | ||||
| 					else if(xr.Name == ElemValue) | ||||
| 						m_strEntryCustomDataValue = ReadString(xr); | ||||
| 					else ReadUnknown(xr); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbContext.EntryHistory: | ||||
| 					if(xr.Name == ElemEntry) | ||||
| 					{ | ||||
| @@ -652,6 +659,19 @@ namespace KeePassLib.Serialization | ||||
| 			} | ||||
| 			else if((ctx == KdbContext.GroupTimes) && (xr.Name == ElemTimes)) | ||||
| 				return KdbContext.Group; | ||||
| 			else if((ctx == KdbContext.GroupCustomData) && (xr.Name == ElemCustomData)) | ||||
| 				return KdbContext.Group; | ||||
| 			else if((ctx == KdbContext.GroupCustomDataItem) && (xr.Name == ElemStringDictExItem)) | ||||
| 			{ | ||||
| 				if((m_strGroupCustomDataKey != null) && (m_strGroupCustomDataValue != null)) | ||||
| 					m_ctxGroup.CustomData.Set(m_strGroupCustomDataKey, m_strGroupCustomDataValue); | ||||
| 				else { Debug.Assert(false); } | ||||
|  | ||||
| 				m_strGroupCustomDataKey = null; | ||||
| 				m_strGroupCustomDataValue = null; | ||||
|  | ||||
| 				return KdbContext.GroupCustomData; | ||||
| 			} | ||||
| 			else if((ctx == KdbContext.Entry) && (xr.Name == ElemEntry)) | ||||
| 			{ | ||||
| 				// Create new UUID if absent | ||||
| @@ -702,6 +722,19 @@ namespace KeePassLib.Serialization | ||||
| 				m_ctxATSeq = null; | ||||
| 				return KdbContext.EntryAutoType; | ||||
| 			} | ||||
| 			else if((ctx == KdbContext.EntryCustomData) && (xr.Name == ElemCustomData)) | ||||
| 				return KdbContext.Entry; | ||||
| 			else if((ctx == KdbContext.EntryCustomDataItem) && (xr.Name == ElemStringDictExItem)) | ||||
| 			{ | ||||
| 				if((m_strEntryCustomDataKey != null) && (m_strEntryCustomDataValue != null)) | ||||
| 					m_ctxEntry.CustomData.Set(m_strEntryCustomDataKey, m_strEntryCustomDataValue); | ||||
| 				else { Debug.Assert(false); } | ||||
|  | ||||
| 				m_strEntryCustomDataKey = null; | ||||
| 				m_strEntryCustomDataValue = null; | ||||
|  | ||||
| 				return KdbContext.EntryCustomData; | ||||
| 			} | ||||
| 			else if((ctx == KdbContext.EntryHistory) && (xr.Name == ElemHistory)) | ||||
| 			{ | ||||
| 				m_bEntryInHistory = false; | ||||
| @@ -852,7 +885,19 @@ namespace KeePassLib.Serialization | ||||
| 				if(strRef != null) | ||||
| 				{ | ||||
| 					ProtectedBinary pb = BinPoolGet(strRef); | ||||
| 					if(pb != null) return pb; | ||||
| 					if(pb != null) | ||||
| 					{ | ||||
| 						// https://sourceforge.net/p/keepass/feature-requests/2023/ | ||||
| 						xr.MoveToElement(); | ||||
| #if DEBUG | ||||
| 						string strInner = ReadStringRaw(xr); | ||||
| 						Debug.Assert(string.IsNullOrEmpty(strInner)); | ||||
| #else | ||||
| 						ReadStringRaw(xr); | ||||
| #endif | ||||
|  | ||||
| 						return pb; | ||||
| 					} | ||||
| 					else { Debug.Assert(false); } | ||||
| 				} | ||||
| 				else { Debug.Assert(false); } | ||||
| @@ -914,7 +959,7 @@ namespace KeePassLib.Serialization | ||||
| 						byte[] pbEncrypted; | ||||
| 						if(strEncrypted.Length > 0) | ||||
| 							pbEncrypted = Convert.FromBase64String(strEncrypted); | ||||
| 						else pbEncrypted = new byte[0]; | ||||
| 						else pbEncrypted = MemUtil.EmptyByteArray; | ||||
|  | ||||
| 						byte[] pbPad = m_randomStream.GetRandomBytes((uint)pbEncrypted.Length); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,25 +19,31 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| #else | ||||
| using KeePassLibSD; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Cryptography.KeyDerivation; | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Keys; | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| using keepass2android; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| @@ -48,80 +54,119 @@ namespace KeePassLib.Serialization | ||||
| 	public sealed partial class KdbxFile | ||||
| 	{ | ||||
| 		/// <summary> | ||||
| 		/// Load a KDB file from a file. | ||||
| 		/// Load a KDBX file. | ||||
| 		/// </summary> | ||||
| 		/// <param name="strFilePath">File to load.</param> | ||||
| 		/// <param name="kdbFormat">Format specifier.</param> | ||||
| 		/// <param name="fmt">Format.</param> | ||||
| 		/// <param name="slLogger">Status logger (optional).</param> | ||||
| 		public void Load(string strFilePath, KdbxFormat kdbFormat, IStatusLogger slLogger) | ||||
| 		public void Load(string strFilePath, KdbxFormat fmt, IStatusLogger slLogger) | ||||
| 		{ | ||||
| 			IOConnectionInfo ioc = IOConnectionInfo.FromPath(strFilePath); | ||||
| 			Load(IOConnection.OpenRead(ioc), kdbFormat, slLogger); | ||||
| 			Load(IOConnection.OpenRead(ioc), fmt, slLogger); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Load a KDB file from a stream. | ||||
| 		/// Load a KDBX file from a stream. | ||||
| 		/// </summary> | ||||
| 		/// <param name="sSource">Stream to read the data from. Must contain | ||||
| 		/// a KDBX stream.</param> | ||||
| 		/// <param name="kdbFormat">Format specifier.</param> | ||||
| 		/// <param name="fmt">Format.</param> | ||||
| 		/// <param name="slLogger">Status logger (optional).</param> | ||||
| 		public void Load(Stream sSource, KdbxFormat kdbFormat, IStatusLogger slLogger) | ||||
| 		public void Load(Stream sSource, KdbxFormat fmt, IStatusLogger slLogger) | ||||
| 		{ | ||||
| 			Debug.Assert(sSource != null); | ||||
| 			if(sSource == null) throw new ArgumentNullException("sSource"); | ||||
|  | ||||
| 			m_format = kdbFormat; | ||||
| 			m_format = fmt; | ||||
| 			m_slLogger = slLogger; | ||||
|  | ||||
| 			HashingStreamEx hashedStream = new HashingStreamEx(sSource, false, null); | ||||
|  | ||||
| 			UTF8Encoding encNoBom = StrUtil.Utf8; | ||||
| 			byte[] pbCipherKey = null; | ||||
| 			byte[] pbHmacKey64 = null; | ||||
|  | ||||
| 			List<Stream> lStreams = new List<Stream>(); | ||||
| 			lStreams.Add(sSource); | ||||
|  | ||||
| 			HashingStreamEx sHashing = new HashingStreamEx(sSource, false, null); | ||||
| 			lStreams.Add(sHashing); | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				BinaryReaderEx br = null; | ||||
| 				BinaryReaderEx brDecrypted = null; | ||||
| 				Stream readerStream = null; | ||||
|  | ||||
| 				if(kdbFormat == KdbxFormat.Default || kdbFormat == KdbxFormat.ProtocolBuffers) | ||||
| 				Stream sXml; | ||||
| 				if (fmt == KdbxFormat.Default || fmt == KdbxFormat.ProtocolBuffers) | ||||
| 				{ | ||||
| 					br = new BinaryReaderEx(hashedStream, encNoBom, KLRes.FileCorrupted); | ||||
| 					ReadHeader(br); | ||||
|  | ||||
| 					Stream sDecrypted = AttachStreamDecryptor(hashedStream); | ||||
| 					if((sDecrypted == null) || (sDecrypted == hashedStream)) | ||||
| 						throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
| 					BinaryReaderEx br = new BinaryReaderEx(sHashing, | ||||
| 						encNoBom, KLRes.FileCorrupted); | ||||
| 					byte[] pbHeader = LoadHeader(br); | ||||
|  | ||||
| 					int cbEncKey, cbEncIV; | ||||
| 					ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV); | ||||
| 			 | ||||
| 					if (m_slLogger != null) | ||||
| 						m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo); | ||||
| 			 | ||||
| 					ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); | ||||
|  | ||||
| 					brDecrypted = new BinaryReaderEx(sDecrypted, encNoBom, KLRes.FileCorrupted); | ||||
| 					byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32); | ||||
|  | ||||
| 					if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32)) | ||||
| 						throw new InvalidDataException(); | ||||
|  | ||||
| 					if (m_slLogger != null) | ||||
| 						m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo); | ||||
|  | ||||
| 					for(int iStart = 0; iStart < 32; ++iStart) | ||||
| 					Stream sPlain; | ||||
| 					if(m_uFileVersion <= FileVersion32_3) | ||||
| 					{ | ||||
| 						if(pbStoredStartBytes[iStart] != m_pbStreamStartBytes[iStart]) | ||||
| 							throw new InvalidCompositeKeyException(); | ||||
| 					} | ||||
| 						Stream sDecrypted = EncryptStream(sHashing, iCipher, | ||||
| 							pbCipherKey, cbEncIV, false); | ||||
| 						if((sDecrypted == null) || (sDecrypted == sHashing)) | ||||
| 							throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
|  | ||||
| 					Stream sHashed = new HashedBlockStream(sDecrypted, false, 0, | ||||
| 						!m_bRepairMode); | ||||
| 						if (m_slLogger != null) | ||||
| 							m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo); | ||||
|  | ||||
| 						lStreams.Add(sDecrypted); | ||||
|  | ||||
| 						BinaryReaderEx brDecrypted = new BinaryReaderEx(sDecrypted, | ||||
| 							encNoBom, KLRes.FileCorrupted); | ||||
| 						byte[] pbStoredStartBytes = brDecrypted.ReadBytes(32); | ||||
|  | ||||
| 						if((m_pbStreamStartBytes == null) || (m_pbStreamStartBytes.Length != 32)) | ||||
| 							throw new InvalidDataException(); | ||||
| 						if(!MemUtil.ArraysEqual(pbStoredStartBytes, m_pbStreamStartBytes)) | ||||
| 							throw new InvalidCompositeKeyException(); | ||||
|  | ||||
| 						if (m_slLogger != null) | ||||
| 							m_slLogger.SetText("KP2AKEY_DecodingDatabase", LogStatusType.AdditionalInfo); | ||||
|  | ||||
|  | ||||
| 						sPlain = new HashedBlockStream(sDecrypted, false, 0, !m_bRepairMode); | ||||
| 					} | ||||
| 					else // KDBX >= 4 | ||||
| 					{ | ||||
| 						byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); | ||||
| 						byte[] pbStoredHmac = MemUtil.Read(sHashing, 32); | ||||
| 						if((pbStoredHmac == null) || (pbStoredHmac.Length != 32)) | ||||
| 							throw new InvalidDataException(); | ||||
| 						if(!MemUtil.ArraysEqual(pbHeaderHmac, pbStoredHmac)) | ||||
| 							throw new InvalidCompositeKeyException(); | ||||
|  | ||||
| 						HmacBlockStream sBlocks = new HmacBlockStream(sHashing, | ||||
| 							false, !m_bRepairMode, pbHmacKey64); | ||||
| 						lStreams.Add(sBlocks); | ||||
|  | ||||
| 						sPlain = EncryptStream(sBlocks, iCipher, pbCipherKey, | ||||
| 							cbEncIV, false); | ||||
| 						if((sPlain == null) || (sPlain == sBlocks)) | ||||
| 							throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
| 					} | ||||
| 					lStreams.Add(sPlain); | ||||
|  | ||||
| 					if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip) | ||||
| 						readerStream = new GZipStream(sHashed, CompressionMode.Decompress); | ||||
| 					else readerStream = sHashed; | ||||
| 					{ | ||||
| 						sXml = new GZipStream(sPlain, CompressionMode.Decompress); | ||||
| 						lStreams.Add(sXml); | ||||
| 					} | ||||
| 					else sXml = sPlain; | ||||
| 				} | ||||
| 				else if(kdbFormat == KdbxFormat.PlainXml) | ||||
| 					readerStream = hashedStream; | ||||
| 				else { Debug.Assert(false); throw new FormatException("KdbFormat"); } | ||||
| 				else if(fmt == KdbxFormat.PlainXml) | ||||
| 					sXml = sHashing; | ||||
| 				else { Debug.Assert(false); throw new ArgumentOutOfRangeException("fmt"); } | ||||
|  | ||||
| 				if(kdbFormat != KdbxFormat.PlainXml) // Is an encrypted format | ||||
| 				if(fmt == KdbxFormat.Default) | ||||
| 				{ | ||||
| 					if(m_pbProtectedStreamKey == null) | ||||
| 					{ | ||||
| @@ -135,39 +180,60 @@ namespace KeePassLib.Serialization | ||||
| 				else m_randomStream = null; // No random stream for plain-text files | ||||
| 				if (m_slLogger != null) | ||||
| 					m_slLogger.SetText("KP2AKEY_ParsingDatabase", LogStatusType.AdditionalInfo); | ||||
| 				 | ||||
| #if KeePassDebug_WriteXml | ||||
| 				// FileStream fsOut = new FileStream("Raw.xml", FileMode.Create, | ||||
| 				//	FileAccess.Write, FileShare.None); | ||||
| 				// try | ||||
| 				// { | ||||
| 				//	while(true) | ||||
| 				//	{ | ||||
| 				//		int b = sXml.ReadByte(); | ||||
| 				//		if(b == -1) break; | ||||
| 				//		fsOut.WriteByte((byte)b); | ||||
| 				//	} | ||||
| 				// } | ||||
| 				// catch(Exception) { } | ||||
| 				// fsOut.Close(); | ||||
| #endif | ||||
| 				var stopWatch = Stopwatch.StartNew(); | ||||
| 				 | ||||
| 				if (kdbFormat == KdbxFormat.ProtocolBuffers) | ||||
| 				if (fmt == KdbxFormat.ProtocolBuffers) | ||||
| 				{ | ||||
| 					KdbpFile.ReadDocument(m_pwDatabase, readerStream, m_pbProtectedStreamKey, m_pbHashOfHeader); | ||||
| 					KdbpFile.ReadDocument(m_pwDatabase, sXml, m_pbProtectedStreamKey, m_pbHashOfHeader); | ||||
|  | ||||
| 					Kp2aLog.Log(String.Format("KdbpFile.ReadDocument: {0}ms", stopWatch.ElapsedMilliseconds)); | ||||
|  | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					ReadXmlStreamed(readerStream, hashedStream); | ||||
|  | ||||
| 					ReadXmlStreamed(sXml, sHashing); | ||||
|  | ||||
| 					Kp2aLog.Log(String.Format("ReadXmlStreamed: {0}ms", stopWatch.ElapsedMilliseconds)); | ||||
| 				} | ||||
|  | ||||
| 				readerStream.Close(); | ||||
| 				// GC.KeepAlive(br); | ||||
| 				// GC.KeepAlive(brDecrypted); | ||||
| 				// ReadXmlDom(sXml); | ||||
| 			} | ||||
| 			catch(CryptographicException) // Thrown on invalid padding | ||||
| 			{ | ||||
| 				throw new CryptographicException(KLRes.FileCorrupted); | ||||
| 			} | ||||
| 			finally { CommonCleanUpRead(sSource, hashedStream); } | ||||
| 			finally | ||||
| 			{ | ||||
| 				if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey); | ||||
| 				if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64); | ||||
|  | ||||
| 				CommonCleanUpRead(lStreams, sHashing); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private void CommonCleanUpRead(Stream sSource, HashingStreamEx hashedStream) | ||||
| 		private void CommonCleanUpRead(List<Stream> lStreams, HashingStreamEx sHashing) | ||||
| 		{ | ||||
| 			hashedStream.Close(); | ||||
| 			m_pbHashOfFileOnDisk = hashedStream.Hash; | ||||
| 			CloseStreams(lStreams); | ||||
|  | ||||
| 			sSource.Close(); | ||||
| 			Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed | ||||
| 			m_pbHashOfFileOnDisk = sHashing.Hash; | ||||
| 			Debug.Assert(m_pbHashOfFileOnDisk != null); | ||||
|  | ||||
| 			// Reset memory protection settings (to always use reasonable | ||||
| 			// defaults) | ||||
| @@ -180,10 +246,16 @@ namespace KeePassLib.Serialization | ||||
| 			// the history maintenance settings) | ||||
| 			m_pwDatabase.MaintainBackups(); // Don't mark database as modified | ||||
|  | ||||
| 			// Expand the root group, such that in case the user accidently | ||||
| 			// collapses the root group he can simply reopen the database | ||||
| 			PwGroup pgRoot = m_pwDatabase.RootGroup; | ||||
| 			if(pgRoot != null) pgRoot.IsExpanded = true; | ||||
| 			else { Debug.Assert(false); } | ||||
|  | ||||
| 			m_pbHashOfHeader = null; | ||||
| 		} | ||||
|  | ||||
| 		private void ReadHeader(BinaryReaderEx br) | ||||
| 		private byte[] LoadHeader(BinaryReaderEx br) | ||||
| 		{ | ||||
| 			MemoryStream msHeader = new MemoryStream(); | ||||
| 			Debug.Assert(br.CopyDataTo == null); | ||||
| @@ -208,18 +280,19 @@ namespace KeePassLib.Serialization | ||||
| 			if((uVersion & FileVersionCriticalMask) > (FileVersion32 & FileVersionCriticalMask)) | ||||
| 				throw new FormatException(KLRes.FileVersionUnsupported + | ||||
| 					MessageService.NewParagraph + KLRes.FileNewVerReq); | ||||
| 			m_uFileVersion = uVersion; | ||||
|  | ||||
| 			while(true) | ||||
| 			{ | ||||
| 				if(ReadHeaderField(br) == false) | ||||
| 					break; | ||||
| 				if(!ReadHeaderField(br)) break; | ||||
| 			} | ||||
|  | ||||
| 			br.CopyDataTo = null; | ||||
| 			byte[] pbHeader = msHeader.ToArray(); | ||||
| 			msHeader.Close(); | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			m_pbHashOfHeader = sha256.ComputeHash(pbHeader); | ||||
|  | ||||
| 			m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader); | ||||
| 			return pbHeader; | ||||
| 		} | ||||
|  | ||||
| 		private bool ReadHeaderField(BinaryReaderEx brSource) | ||||
| @@ -228,15 +301,21 @@ namespace KeePassLib.Serialization | ||||
| 			if(brSource == null) throw new ArgumentNullException("brSource"); | ||||
|  | ||||
| 			byte btFieldID = brSource.ReadByte(); | ||||
| 			ushort uSize = MemUtil.BytesToUInt16(brSource.ReadBytes(2)); | ||||
|  | ||||
| 			byte[] pbData = null; | ||||
| 			if(uSize > 0) | ||||
| 			int cbSize; | ||||
| 			Debug.Assert(m_uFileVersion > 0); | ||||
| 			if(m_uFileVersion <= FileVersion32_3) | ||||
| 				cbSize = (int)MemUtil.BytesToUInt16(brSource.ReadBytes(2)); | ||||
| 			else cbSize = MemUtil.BytesToInt32(brSource.ReadBytes(4)); | ||||
| 			if(cbSize < 0) throw new FormatException(KLRes.FileCorrupted); | ||||
|  | ||||
| 			byte[] pbData = MemUtil.EmptyByteArray; | ||||
| 			if(cbSize > 0) | ||||
| 			{ | ||||
| 				string strPrevExcpText = brSource.ReadExceptionText; | ||||
| 				brSource.ReadExceptionText = KLRes.FileHeaderEndEarly; | ||||
|  | ||||
| 				pbData = brSource.ReadBytes(uSize); | ||||
| 				pbData = brSource.ReadBytes(cbSize); | ||||
|  | ||||
| 				brSource.ReadExceptionText = strPrevExcpText; | ||||
| 			} | ||||
| @@ -262,13 +341,27 @@ namespace KeePassLib.Serialization | ||||
| 					CryptoRandom.Instance.AddEntropy(pbData); | ||||
| 					break; | ||||
|  | ||||
| 				// Obsolete; for backward compatibility only | ||||
| 				case KdbxHeaderFieldID.TransformSeed: | ||||
| 					m_pbTransformSeed = pbData; | ||||
| 					AesKdf kdfS = new AesKdf(); | ||||
| 					if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfS.Uuid)) | ||||
| 						m_pwDatabase.KdfParameters = kdfS.GetDefaultParameters(); | ||||
|  | ||||
| 					// m_pbTransformSeed = pbData; | ||||
| 					m_pwDatabase.KdfParameters.SetByteArray(AesKdf.ParamSeed, pbData); | ||||
|  | ||||
| 					CryptoRandom.Instance.AddEntropy(pbData); | ||||
| 					break; | ||||
|  | ||||
| 				// Obsolete; for backward compatibility only | ||||
| 				case KdbxHeaderFieldID.TransformRounds: | ||||
| 					m_pwDatabase.KeyEncryptionRounds = MemUtil.BytesToUInt64(pbData); | ||||
| 					AesKdf kdfR = new AesKdf(); | ||||
| 					if(!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfR.Uuid)) | ||||
| 						m_pwDatabase.KdfParameters = kdfR.GetDefaultParameters(); | ||||
|  | ||||
| 					// m_pwDatabase.KeyEncryptionRounds = MemUtil.BytesToUInt64(pbData); | ||||
| 					m_pwDatabase.KdfParameters.SetUInt64(AesKdf.ParamRounds, | ||||
| 						MemUtil.BytesToUInt64(pbData)); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbxHeaderFieldID.EncryptionIV: | ||||
| @@ -281,6 +374,7 @@ namespace KeePassLib.Serialization | ||||
| 					break; | ||||
|  | ||||
| 				case KdbxHeaderFieldID.StreamStartBytes: | ||||
| 					Debug.Assert(m_uFileVersion <= FileVersion32_3); | ||||
| 					m_pbStreamStartBytes = pbData; | ||||
| 					break; | ||||
|  | ||||
| @@ -288,6 +382,15 @@ namespace KeePassLib.Serialization | ||||
| 					SetInnerRandomStreamID(pbData); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbxHeaderFieldID.KdfParameters: | ||||
| 					m_pwDatabase.KdfParameters = KdfParameters.DeserializeExt(pbData); | ||||
| 					break; | ||||
|  | ||||
| 				case KdbxHeaderFieldID.PublicCustomData: | ||||
| 					Debug.Assert(m_pwDatabase.PublicCustomData.Count == 0); | ||||
| 					m_pwDatabase.PublicCustomData = VariantDictionary.Deserialize(pbData); | ||||
| 					break; | ||||
|  | ||||
| 				default: | ||||
| 					Debug.Assert(false); | ||||
| 					if(m_slLogger != null) | ||||
| @@ -301,7 +404,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private void SetCipher(byte[] pbID) | ||||
| 		{ | ||||
| 			if((pbID == null) || (pbID.Length != 16)) | ||||
| 			if((pbID == null) || (pbID.Length != (int)PwUuid.UuidSize)) | ||||
| 				throw new FormatException(KLRes.FileUnknownCipher); | ||||
|  | ||||
| 			m_pwDatabase.DataCipherUuid = new PwUuid(pbID); | ||||
| @@ -325,36 +428,6 @@ namespace KeePassLib.Serialization | ||||
| 			m_craInnerRandomStream = (CrsAlgorithm)uID; | ||||
| 		} | ||||
|  | ||||
| 		private Stream AttachStreamDecryptor(Stream s) | ||||
| 		{ | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
|  | ||||
| 			Debug.Assert(m_pbMasterSeed.Length == 32); | ||||
| 			if(m_pbMasterSeed.Length != 32) | ||||
| 				throw new FormatException(KLRes.MasterSeedLengthInvalid); | ||||
| 			ms.Write(m_pbMasterSeed, 0, 32); | ||||
| 			if (m_slLogger != null) | ||||
| 				m_slLogger.SetText("KP2AKEY_TransformingKey", LogStatusType.AdditionalInfo); | ||||
| 			byte[] pKey32 = m_pwDatabase.MasterKey.GenerateKey32(m_pbTransformSeed, | ||||
| 				m_pwDatabase.KeyEncryptionRounds).ReadData(); | ||||
| 			if((pKey32 == null) || (pKey32.Length != 32)) | ||||
| 				throw new SecurityException(KLRes.InvalidCompositeKey); | ||||
| 			ms.Write(pKey32, 0, 32); | ||||
| 			 | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			byte[] aesKey = sha256.ComputeHash(ms.ToArray()); | ||||
|  | ||||
| 			ms.Close(); | ||||
| 			Array.Clear(pKey32, 0, 32); | ||||
|  | ||||
| 			if((aesKey == null) || (aesKey.Length != 32)) | ||||
| 				throw new SecurityException(KLRes.FinalKeyCreationFailed); | ||||
|  | ||||
| 			ICipherEngine iEngine = CipherPool.GlobalPool.GetCipher(m_pwDatabase.DataCipherUuid); | ||||
| 			if(iEngine == null) throw new SecurityException(KLRes.FileUnknownCipher); | ||||
| 			return iEngine.DecryptStream(s, aesKey, m_pbEncryptionIV); | ||||
| 		} | ||||
|  | ||||
| 		[Obsolete] | ||||
| 		public static List<PwEntry> ReadEntries(PwDatabase pwDatabase, Stream msData) | ||||
| 		{ | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,30 +19,35 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Xml; | ||||
| using System.Security; | ||||
| using System.Security.Cryptography; | ||||
| using System.Drawing; | ||||
| using System.Globalization; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Security; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| #else | ||||
| #if !KeePassUAP | ||||
| using System.Drawing; | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| #if KeePassLibSD | ||||
| using KeePassLibSD; | ||||
| #else | ||||
| using System.IO.Compression; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Cryptography.KeyDerivation; | ||||
| using KeePassLib.Delegates; | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Keys; | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| using keepass2android; | ||||
|  | ||||
| namespace KeePassLib.Serialization | ||||
| @@ -54,7 +57,7 @@ namespace KeePassLib.Serialization | ||||
| 	/// </summary> | ||||
| 	public sealed partial class KdbxFile | ||||
| 	{ | ||||
| 		// public void Save(string strFile, PwGroup pgDataSource, KdbxFormat format, | ||||
| 		// public void Save(string strFile, PwGroup pgDataSource, KdbxFormat fmt, | ||||
| 		//	IStatusLogger slLogger) | ||||
| 		// { | ||||
| 		//	bool bMadeUnhidden = UrlUtil.UnhideFile(strFile); | ||||
| @@ -72,175 +75,257 @@ namespace KeePassLib.Serialization | ||||
| 		/// <param name="pgDataSource">Group containing all groups and | ||||
| 		/// entries to write. If <c>null</c>, the complete database will | ||||
| 		/// be written.</param> | ||||
| 		/// <param name="format">Format of the file to create.</param> | ||||
| 		/// <param name="fmt">Format of the file to create.</param> | ||||
| 		/// <param name="slLogger">Logger that recieves status information.</param> | ||||
| 		public void Save(Stream sSaveTo, PwGroup pgDataSource, KdbxFormat format, | ||||
| 		public void Save(Stream sSaveTo, PwGroup pgDataSource, KdbxFormat fmt, | ||||
| 			IStatusLogger slLogger) | ||||
| 		{ | ||||
| 			Debug.Assert(sSaveTo != null); | ||||
| 			if(sSaveTo == null) throw new ArgumentNullException("sSaveTo"); | ||||
|  | ||||
| 			m_format = format; | ||||
| 			m_format = fmt; | ||||
| 			m_slLogger = slLogger; | ||||
|  | ||||
| 			HashingStreamEx hashedStream = new HashingStreamEx(sSaveTo, true, null); | ||||
|  | ||||
| 			UTF8Encoding encNoBom = StrUtil.Utf8; | ||||
| 			CryptoRandom cr = CryptoRandom.Instance; | ||||
| 			byte[] pbCipherKey = null; | ||||
| 			byte[] pbHmacKey64 = null; | ||||
|  | ||||
| 			List<Stream> lStreams = new List<Stream>(); | ||||
| 			lStreams.Add(sSaveTo); | ||||
|  | ||||
| 			HashingStreamEx sHashing = new HashingStreamEx(sSaveTo, true, null); | ||||
| 			lStreams.Add(sHashing); | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				m_pbMasterSeed = cr.GetRandomBytes(32); | ||||
| 				m_pbTransformSeed = cr.GetRandomBytes(32); | ||||
| 				m_pbEncryptionIV = cr.GetRandomBytes(16); | ||||
| 				m_uFileVersion = GetMinKdbxVersion(); | ||||
|  | ||||
| 				m_pbProtectedStreamKey = cr.GetRandomBytes(32); | ||||
| 				m_craInnerRandomStream = CrsAlgorithm.Salsa20; | ||||
| 				int cbEncKey, cbEncIV; | ||||
| 				ICipherEngine iCipher = GetCipher(out cbEncKey, out cbEncIV); | ||||
|  | ||||
| 				m_pbMasterSeed = cr.GetRandomBytes(32); | ||||
| 				m_pbEncryptionIV = cr.GetRandomBytes((uint)cbEncIV); | ||||
|  | ||||
| 				// m_pbTransformSeed = cr.GetRandomBytes(32); | ||||
| 				PwUuid puKdf = m_pwDatabase.KdfParameters.KdfUuid; | ||||
| 				KdfEngine kdf = KdfPool.Get(puKdf); | ||||
| 				if(kdf == null) | ||||
| 					throw new Exception(KLRes.UnknownKdf + MessageService.NewParagraph + | ||||
| 						// KLRes.FileNewVerOrPlgReq + MessageService.NewParagraph + | ||||
| 						"UUID: " + puKdf.ToHexString() + "."); | ||||
| 				kdf.Randomize(m_pwDatabase.KdfParameters); | ||||
|  | ||||
| 				if(m_uFileVersion <= FileVersion32_3) | ||||
| 				{ | ||||
| 					m_craInnerRandomStream = CrsAlgorithm.Salsa20; | ||||
| 					m_pbProtectedStreamKey = cr.GetRandomBytes(32); | ||||
| 				} | ||||
| 				else // KDBX >= 4 | ||||
| 				{ | ||||
| 					m_craInnerRandomStream = CrsAlgorithm.ChaCha20; | ||||
| 					m_pbProtectedStreamKey = cr.GetRandomBytes(64); | ||||
| 				} | ||||
| 				m_randomStream = new CryptoRandomStream(m_craInnerRandomStream, | ||||
| 					m_pbProtectedStreamKey); | ||||
|  | ||||
| 				m_pbStreamStartBytes = cr.GetRandomBytes(32); | ||||
| 				if(m_uFileVersion <= FileVersion32_3) | ||||
| 					m_pbStreamStartBytes = cr.GetRandomBytes(32); | ||||
|  | ||||
| 				Stream writerStream; | ||||
| 				if(m_format == KdbxFormat.Default || m_format == KdbxFormat.ProtocolBuffers) | ||||
| 				Stream sXml; | ||||
| 				if (m_format == KdbxFormat.Default || m_format == KdbxFormat.ProtocolBuffers) | ||||
| 				{ | ||||
| 					WriteHeader(hashedStream); // Also flushes the stream | ||||
| 					byte[] pbHeader = GenerateHeader(); | ||||
| 					m_pbHashOfHeader = CryptoUtil.HashSha256(pbHeader); | ||||
|  | ||||
| 					Stream sEncrypted = AttachStreamEncryptor(hashedStream); | ||||
| 					if((sEncrypted == null) || (sEncrypted == hashedStream)) | ||||
| 						throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
| 					MemUtil.Write(sHashing, pbHeader); | ||||
| 					sHashing.Flush(); | ||||
|  | ||||
| 					sEncrypted.Write(m_pbStreamStartBytes, 0, m_pbStreamStartBytes.Length); | ||||
| 					ComputeKeys(out pbCipherKey, cbEncKey, out pbHmacKey64); | ||||
|  | ||||
| 					Stream sHashed = new HashedBlockStream(sEncrypted, true); | ||||
| 					Stream sPlain; | ||||
| 					if(m_uFileVersion <= FileVersion32_3) | ||||
| 					{ | ||||
| 						Stream sEncrypted = EncryptStream(sHashing, iCipher, | ||||
| 							pbCipherKey, cbEncIV, true); | ||||
| 						if((sEncrypted == null) || (sEncrypted == sHashing)) | ||||
| 							throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
| 						lStreams.Add(sEncrypted); | ||||
|  | ||||
| 						MemUtil.Write(sEncrypted, m_pbStreamStartBytes); | ||||
|  | ||||
| 						sPlain = new HashedBlockStream(sEncrypted, true); | ||||
| 					} | ||||
| 					else // KDBX >= 4 | ||||
| 					{ | ||||
| 						byte[] pbHeaderHmac = ComputeHeaderHmac(pbHeader, pbHmacKey64); | ||||
| 						MemUtil.Write(sHashing, pbHeaderHmac); | ||||
|  | ||||
| 						Stream sBlocks = new HmacBlockStream(sHashing, true, | ||||
| 							true, pbHmacKey64); | ||||
| 						lStreams.Add(sBlocks); | ||||
|  | ||||
| 						sPlain = EncryptStream(sBlocks, iCipher, pbCipherKey, | ||||
| 							cbEncIV, true); | ||||
| 						if((sPlain == null) || (sPlain == sBlocks)) | ||||
| 							throw new SecurityException(KLRes.CryptoStreamFailed); | ||||
| 					} | ||||
| 					lStreams.Add(sPlain); | ||||
|  | ||||
| 					if(m_pwDatabase.Compression == PwCompressionAlgorithm.GZip) | ||||
| 						writerStream = new GZipStream(sHashed, CompressionMode.Compress); | ||||
| 					else | ||||
| 						writerStream = sHashed; | ||||
| 					{ | ||||
| 						sXml = new GZipStream(sPlain, CompressionMode.Compress); | ||||
| 						lStreams.Add(sXml); | ||||
| 					} | ||||
| 					else sXml = sPlain; | ||||
| 				} | ||||
| 				else if(m_format == KdbxFormat.PlainXml) | ||||
| 					writerStream = hashedStream; | ||||
| 				else { Debug.Assert(false); throw new FormatException("KdbFormat"); } | ||||
| 					sXml = sHashing; | ||||
| 				else | ||||
| 				{ | ||||
| 					Debug.Assert(false); | ||||
| 					throw new ArgumentOutOfRangeException("fmt"); | ||||
| 				} | ||||
|  | ||||
| 				var stopWatch = Stopwatch.StartNew(); | ||||
|  | ||||
| 				if (m_format == KdbxFormat.ProtocolBuffers) | ||||
| 				{ | ||||
| 					KdbpFile.WriteDocument(m_pwDatabase, writerStream, m_pbProtectedStreamKey, m_pbHashOfHeader); | ||||
| 					KdbpFile.WriteDocument(m_pwDatabase, sXml, m_pbProtectedStreamKey, m_pbHashOfHeader); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					m_xmlWriter = new XmlTextWriter(writerStream, encNoBom); | ||||
|  | ||||
| #if KeePassUAP | ||||
| 					XmlWriterSettings xws = new XmlWriterSettings(); | ||||
| 					xws.Encoding = encNoBom; | ||||
| 					xws.Indent = true; | ||||
| 					xws.IndentChars = "\t"; | ||||
| 					xws.NewLineOnAttributes = false; | ||||
|  | ||||
| 					XmlWriter xw = XmlWriter.Create(sXml, xws); | ||||
| #else | ||||
| 					XmlTextWriter xw = new XmlTextWriter(sXml, encNoBom); | ||||
|  | ||||
| 					xw.Formatting = Formatting.Indented; | ||||
| 					xw.IndentChar = '\t'; | ||||
| 					xw.Indentation = 1; | ||||
| #endif | ||||
| 					m_xmlWriter = xw; | ||||
|  | ||||
| 					WriteDocument(pgDataSource); | ||||
|  | ||||
| 					m_xmlWriter.Flush(); | ||||
| 					m_xmlWriter.Close(); | ||||
| 				} | ||||
|  | ||||
| 				writerStream.Close(); | ||||
|  | ||||
| 				Kp2aLog.Log(String.Format("{1}: {0}ms", stopWatch.ElapsedMilliseconds, m_format == KdbxFormat.ProtocolBuffers ? "KdbpFile.WriteDocument" : "Xml WriteDocument")); | ||||
| 			 | ||||
| 			} | ||||
| 			finally { CommonCleanUpWrite(sSaveTo, hashedStream); } | ||||
| 			finally | ||||
| 			{ | ||||
| 				if(pbCipherKey != null) MemUtil.ZeroByteArray(pbCipherKey); | ||||
| 				if(pbHmacKey64 != null) MemUtil.ZeroByteArray(pbHmacKey64); | ||||
|  | ||||
| 				CommonCleanUpWrite(lStreams, sHashing); | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		private void CommonCleanUpWrite(Stream sSaveTo, HashingStreamEx hashedStream) | ||||
| 		private void CommonCleanUpWrite(List<Stream> lStreams, HashingStreamEx sHashing) | ||||
| 		{ | ||||
| 			hashedStream.Close(); | ||||
| 			m_pbHashOfFileOnDisk = hashedStream.Hash; | ||||
| 			CloseStreams(lStreams); | ||||
|  | ||||
| 			sSaveTo.Close(); | ||||
| 			Debug.Assert(lStreams.Contains(sHashing)); // sHashing must be closed | ||||
| 			m_pbHashOfFileOnDisk = sHashing.Hash; | ||||
| 			Debug.Assert(m_pbHashOfFileOnDisk != null); | ||||
|  | ||||
| 			m_xmlWriter = null; | ||||
| 			m_pbHashOfHeader = null; | ||||
| 		} | ||||
|  | ||||
| 		private void WriteHeader(Stream s) | ||||
| 		private byte[] GenerateHeader() | ||||
| 		{ | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
| 			byte[] pbHeader; | ||||
| 			using(MemoryStream ms = new MemoryStream()) | ||||
| 			{ | ||||
| 				MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature1)); | ||||
| 				MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature2)); | ||||
| 				MemUtil.Write(ms, MemUtil.UInt32ToBytes(m_uFileVersion)); | ||||
|  | ||||
| 			MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature1)); | ||||
| 			MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileSignature2)); | ||||
| 			MemUtil.Write(ms, MemUtil.UInt32ToBytes(FileVersion32)); | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.CipherID, | ||||
| 					m_pwDatabase.DataCipherUuid.UuidBytes); | ||||
|  | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.CipherID, | ||||
| 				m_pwDatabase.DataCipherUuid.UuidBytes); | ||||
| 				int nCprID = (int)m_pwDatabase.Compression; | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.CompressionFlags, | ||||
| 					MemUtil.UInt32ToBytes((uint)nCprID)); | ||||
|  | ||||
| 			int nCprID = (int)m_pwDatabase.Compression; | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.CompressionFlags, | ||||
| 				MemUtil.UInt32ToBytes((uint)nCprID)); | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed); | ||||
|  | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.MasterSeed, m_pbMasterSeed); | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.TransformSeed, m_pbTransformSeed); | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.TransformRounds, | ||||
| 				MemUtil.UInt64ToBytes(m_pwDatabase.KeyEncryptionRounds)); | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV); | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.ProtectedStreamKey, m_pbProtectedStreamKey); | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes, m_pbStreamStartBytes); | ||||
| 				if(m_uFileVersion <= FileVersion32_3) | ||||
| 				{ | ||||
| 					Debug.Assert(m_pwDatabase.KdfParameters.KdfUuid.Equals( | ||||
| 						(new AesKdf()).Uuid)); | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.TransformSeed, | ||||
| 						m_pwDatabase.KdfParameters.GetByteArray(AesKdf.ParamSeed)); | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.TransformRounds, | ||||
| 						MemUtil.UInt64ToBytes(m_pwDatabase.KdfParameters.GetUInt64( | ||||
| 						AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds))); | ||||
| 				} | ||||
| 				else | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.KdfParameters, | ||||
| 						KdfParameters.SerializeExt(m_pwDatabase.KdfParameters)); | ||||
|  | ||||
| 			int nIrsID = (int)m_craInnerRandomStream; | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID, | ||||
| 				MemUtil.UInt32ToBytes((uint)nIrsID)); | ||||
| 				if(m_pbEncryptionIV.Length > 0) | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.EncryptionIV, m_pbEncryptionIV); | ||||
|  | ||||
| 			WriteHeaderField(ms, KdbxHeaderFieldID.EndOfHeader, new byte[]{ | ||||
| 				(byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }); | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.ProtectedStreamKey, m_pbProtectedStreamKey); | ||||
|  | ||||
| 			byte[] pbHeader = ms.ToArray(); | ||||
| 			ms.Close(); | ||||
| 				if(m_uFileVersion <= FileVersion32_3) | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.StreamStartBytes, | ||||
| 						m_pbStreamStartBytes); | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			m_pbHashOfHeader = sha256.ComputeHash(pbHeader); | ||||
| 				int nIrsID = (int)m_craInnerRandomStream; | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.InnerRandomStreamID, | ||||
| 					MemUtil.Int32ToBytes(nIrsID)); | ||||
|  | ||||
| 			s.Write(pbHeader, 0, pbHeader.Length); | ||||
| 			s.Flush(); | ||||
| 				// Write public custom data only when there is at least one item, | ||||
| 				// because KDBX 3.1 didn't support this field yet | ||||
| 				if(m_pwDatabase.PublicCustomData.Count > 0) | ||||
| 					WriteHeaderField(ms, KdbxHeaderFieldID.PublicCustomData, | ||||
| 						VariantDictionary.Serialize(m_pwDatabase.PublicCustomData)); | ||||
|  | ||||
| 				WriteHeaderField(ms, KdbxHeaderFieldID.EndOfHeader, new byte[] { | ||||
| 					(byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n' }); | ||||
|  | ||||
| 				pbHeader = ms.ToArray(); | ||||
| 			} | ||||
|  | ||||
| 			return pbHeader; | ||||
| 		} | ||||
|  | ||||
| 		private static void WriteHeaderField(Stream s, KdbxHeaderFieldID kdbID, | ||||
| 		private void WriteHeaderField(Stream s, KdbxHeaderFieldID kdbID, | ||||
| 			byte[] pbData) | ||||
| 		{ | ||||
| 			s.WriteByte((byte)kdbID); | ||||
|  | ||||
| 			if(pbData != null) | ||||
| 			byte[] pb = (pbData ?? MemUtil.EmptyByteArray); | ||||
| 			int cb = pb.Length; | ||||
| 			if(cb < 0) { Debug.Assert(false); throw new OutOfMemoryException(); } | ||||
|  | ||||
| 			Debug.Assert(m_uFileVersion > 0); | ||||
| 			if(m_uFileVersion <= FileVersion32_3) | ||||
| 			{ | ||||
| 				ushort uLength = (ushort)pbData.Length; | ||||
| 				MemUtil.Write(s, MemUtil.UInt16ToBytes(uLength)); | ||||
| 				if(cb > (int)ushort.MaxValue) | ||||
| 				{ | ||||
| 					Debug.Assert(false); | ||||
| 					throw new ArgumentOutOfRangeException("pbData"); | ||||
| 				} | ||||
|  | ||||
| 				if(uLength > 0) s.Write(pbData, 0, pbData.Length); | ||||
| 				MemUtil.Write(s, MemUtil.UInt16ToBytes((ushort)cb)); | ||||
| 			} | ||||
| 			else MemUtil.Write(s, MemUtil.UInt16ToBytes((ushort)0)); | ||||
| 		} | ||||
| 			else MemUtil.Write(s, MemUtil.Int32ToBytes(cb)); | ||||
|  | ||||
| 		private Stream AttachStreamEncryptor(Stream s) | ||||
| 		{ | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
|  | ||||
| 			Debug.Assert(m_pbMasterSeed != null); | ||||
| 			Debug.Assert(m_pbMasterSeed.Length == 32); | ||||
| 			ms.Write(m_pbMasterSeed, 0, 32); | ||||
|  | ||||
| 			Debug.Assert(m_pwDatabase != null); | ||||
| 			Debug.Assert(m_pwDatabase.MasterKey != null); | ||||
| 			ProtectedBinary pbinKey = m_pwDatabase.MasterKey.GenerateKey32( | ||||
| 				m_pbTransformSeed, m_pwDatabase.KeyEncryptionRounds); | ||||
| 			Debug.Assert(pbinKey != null); | ||||
| 			if(pbinKey == null) | ||||
| 				throw new SecurityException(KLRes.InvalidCompositeKey); | ||||
| 			byte[] pKey32 = pbinKey.ReadData(); | ||||
| 			if((pKey32 == null) || (pKey32.Length != 32)) | ||||
| 				throw new SecurityException(KLRes.InvalidCompositeKey); | ||||
| 			ms.Write(pKey32, 0, 32); | ||||
|  | ||||
| 			SHA256Managed sha256 = new SHA256Managed(); | ||||
| 			byte[] aesKey = sha256.ComputeHash(ms.ToArray()); | ||||
| 			 | ||||
| 			ms.Close(); | ||||
| 			Array.Clear(pKey32, 0, 32); | ||||
|  | ||||
| 			Debug.Assert(CipherPool.GlobalPool != null); | ||||
| 			ICipherEngine iEngine = CipherPool.GlobalPool.GetCipher(m_pwDatabase.DataCipherUuid); | ||||
| 			if(iEngine == null) throw new SecurityException(KLRes.FileUnknownCipher); | ||||
| 			return iEngine.EncryptStream(s, aesKey, m_pbEncryptionIV); | ||||
| 			if(cb > 0) s.Write(pb, 0, cb); | ||||
| 		} | ||||
|  | ||||
| 		private void WriteDocument(PwGroup pgDataSource) | ||||
| @@ -255,10 +340,6 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			BinPoolBuild(pgRoot); | ||||
|  | ||||
| 			m_xmlWriter.Formatting = Formatting.Indented; | ||||
| 			m_xmlWriter.IndentChar = '\t'; | ||||
| 			m_xmlWriter.Indentation = 1; | ||||
|  | ||||
| 			m_xmlWriter.WriteStartDocument(true); | ||||
| 			m_xmlWriter.WriteStartElement(ElemDocNode); | ||||
|  | ||||
| @@ -330,12 +411,15 @@ namespace KeePassLib.Serialization | ||||
| 		{ | ||||
| 			m_xmlWriter.WriteStartElement(ElemMeta); | ||||
|  | ||||
| 			WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false); // Generator name | ||||
| 			WriteObject(ElemGenerator, PwDatabase.LocalizedAppName, false); | ||||
|  | ||||
| 			if(m_pbHashOfHeader != null) | ||||
| 			if((m_pbHashOfHeader != null) && (m_uFileVersion <= FileVersion32_3)) | ||||
| 				WriteObject(ElemHeaderHash, Convert.ToBase64String( | ||||
| 					m_pbHashOfHeader), false); | ||||
|  | ||||
| 			if(m_uFileVersion > FileVersion32_3) | ||||
| 				WriteObject(ElemSettingsChanged, m_pwDatabase.SettingsChanged); | ||||
|  | ||||
| 			WriteObject(ElemDbName, m_pwDatabase.Name, true); | ||||
| 			WriteObject(ElemDbNameChanged, m_pwDatabase.NameChanged); | ||||
| 			WriteObject(ElemDbDesc, m_pwDatabase.Description, true); | ||||
| @@ -386,6 +470,9 @@ namespace KeePassLib.Serialization | ||||
| 			WriteObject(ElemEnableAutoType, StrUtil.BoolToStringEx(pg.EnableAutoType), false); | ||||
| 			WriteObject(ElemEnableSearching, StrUtil.BoolToStringEx(pg.EnableSearching), false); | ||||
| 			WriteObject(ElemLastTopVisibleEntry, pg.LastTopVisibleEntry); | ||||
|  | ||||
| 			if(pg.CustomData.Count > 0) | ||||
| 				WriteList(ElemCustomData, pg.CustomData); | ||||
| 		} | ||||
|  | ||||
| 		private void EndGroup() | ||||
| @@ -401,7 +488,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			WriteObject(ElemUuid, pe.Uuid); | ||||
| 			WriteObject(ElemIcon, (int)pe.IconId); | ||||
| 			 | ||||
|  | ||||
| 			if(!pe.CustomIconUuid.Equals(PwUuid.Zero)) | ||||
| 				WriteObject(ElemCustomIconID, pe.CustomIconUuid); | ||||
|  | ||||
| @@ -416,6 +503,9 @@ namespace KeePassLib.Serialization | ||||
| 			WriteList(pe.Binaries); | ||||
| 			WriteList(ElemAutoType, pe.AutoType); | ||||
|  | ||||
| 			if(pe.CustomData.Count > 0) | ||||
| 				WriteList(ElemCustomData, pe.CustomData); | ||||
|  | ||||
| 			if(!bIsHistory) WriteList(ElemHistory, pe.History, true); | ||||
| 			else { Debug.Assert(pe.History.UCount == 0); } | ||||
|  | ||||
| @@ -468,8 +558,8 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 			m_xmlWriter.WriteStartElement(name); | ||||
|  | ||||
| 			WriteObject(ElemLastModTime, times.LastModificationTime); | ||||
| 			WriteObject(ElemCreationTime, times.CreationTime); | ||||
| 			WriteObject(ElemLastModTime, times.LastModificationTime); | ||||
| 			WriteObject(ElemLastAccessTime, times.LastAccessTime); | ||||
| 			WriteObject(ElemExpiryTime, times.ExpiryTime); | ||||
| 			WriteObject(ElemExpires, times.Expires); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,20 +19,25 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Xml; | ||||
| using System.Text; | ||||
| using System.Diagnostics; | ||||
| using System.Drawing; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.Security; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| #if !KeePassUAP | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Cryptography; | ||||
| using KeePassLib.Cryptography.Cipher; | ||||
| using KeePassLib.Cryptography.KeyDerivation; | ||||
| using KeePassLib.Delegates; | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Resources; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| @@ -61,6 +66,47 @@ namespace KeePassLib.Serialization | ||||
| 	/// </summary> | ||||
| 	public sealed partial class KdbxFile | ||||
| 	{ | ||||
| 		private class ColorTranslator | ||||
| 		{ | ||||
| 			public static Color FromHtml(String colorString) | ||||
| 			{ | ||||
| 				Color color; | ||||
|  | ||||
| 				if (colorString.StartsWith("#")) | ||||
| 				{ | ||||
| 					colorString = colorString.Substring(1); | ||||
| 				} | ||||
| 				if (colorString.EndsWith(";")) | ||||
| 				{ | ||||
| 					colorString = colorString.Substring(0, colorString.Length - 1); | ||||
| 				} | ||||
|  | ||||
| 				int red, green, blue; | ||||
| 				switch (colorString.Length) | ||||
| 				{ | ||||
| 					case 6: | ||||
| 						red = int.Parse(colorString.Substring(0, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 						green = int.Parse(colorString.Substring(2, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 						blue = int.Parse(colorString.Substring(4, 2), System.Globalization.NumberStyles.HexNumber); | ||||
| 						color = Color.FromArgb(red, green, blue); | ||||
| 						break; | ||||
| 					case 3: | ||||
| 						red = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 						green = int.Parse(colorString.Substring(1, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 						blue = int.Parse(colorString.Substring(2, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 						color = Color.FromArgb(red, green, blue); | ||||
| 						break; | ||||
| 					case 1: | ||||
| 						red = green = blue = int.Parse(colorString.Substring(0, 1), System.Globalization.NumberStyles.HexNumber); | ||||
| 						color = Color.FromArgb(red, green, blue); | ||||
| 						break; | ||||
| 					default: | ||||
| 						throw new ArgumentException("Invalid color: " + colorString); | ||||
| 				} | ||||
| 				return color; | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 		/// <summary> | ||||
| 		/// File identifier, first 32-bit value. | ||||
| 		/// </summary> | ||||
| @@ -78,7 +124,8 @@ namespace KeePassLib.Serialization | ||||
| 		/// The first 2 bytes are critical (i.e. loading will fail, if the | ||||
| 		/// file version is too high), the last 2 bytes are informational. | ||||
| 		/// </summary> | ||||
| 		private const uint FileVersion32 = 0x00030001; | ||||
| 		private const uint FileVersion32 = 0x00040000; | ||||
| 		private const uint FileVersion32_3 = 0x00030001; // Old format | ||||
|  | ||||
| 		private const uint FileVersionCriticalMask = 0xFFFF0000; | ||||
|  | ||||
| @@ -97,6 +144,7 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private const string ElemGenerator = "Generator"; | ||||
| 		private const string ElemHeaderHash = "HeaderHash"; | ||||
| 		private const string ElemSettingsChanged = "SettingsChanged"; | ||||
| 		private const string ElemDbName = "DatabaseName"; | ||||
| 		private const string ElemDbNameChanged = "DatabaseNameChanged"; | ||||
| 		private const string ElemDbDesc = "DatabaseDescription"; | ||||
| @@ -192,19 +240,20 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		private PwDatabase m_pwDatabase; // Not null, see constructor | ||||
|  | ||||
| 		private XmlTextWriter m_xmlWriter = null; | ||||
| 		private XmlWriter m_xmlWriter = null; | ||||
| 		private CryptoRandomStream m_randomStream = null; | ||||
| 		private KdbxFormat m_format = KdbxFormat.Default; | ||||
| 		private IStatusLogger m_slLogger = null; | ||||
|  | ||||
| 		private uint m_uFileVersion = 0; | ||||
| 		private byte[] m_pbMasterSeed = null; | ||||
| 		private byte[] m_pbTransformSeed = null; | ||||
| 		// private byte[] m_pbTransformSeed = null; | ||||
| 		private byte[] m_pbEncryptionIV = null; | ||||
| 		private byte[] m_pbProtectedStreamKey = null; | ||||
| 		private byte[] m_pbStreamStartBytes = null; | ||||
|  | ||||
| 		// ArcFourVariant only for compatibility; KeePass will default to a | ||||
| 		// different (more secure) algorithm when *writing* databases | ||||
| 		// ArcFourVariant only for backward compatibility; KeePass defaults | ||||
| 		// to a more secure algorithm when *writing* databases | ||||
| 		private CrsAlgorithm m_craInnerRandomStream = CrsAlgorithm.ArcFourVariant; | ||||
|  | ||||
| 		private Dictionary<string, ProtectedBinary> m_dictBinPool = | ||||
| @@ -227,12 +276,14 @@ namespace KeePassLib.Serialization | ||||
| 			CipherID = 2, | ||||
| 			CompressionFlags = 3, | ||||
| 			MasterSeed = 4, | ||||
| 			TransformSeed = 5, | ||||
| 			TransformRounds = 6, | ||||
| 			TransformSeed = 5, // KDBX 3.1, for backward compatibility only | ||||
| 			TransformRounds = 6, // KDBX 3.1, for backward compatibility only | ||||
| 			EncryptionIV = 7, | ||||
| 			ProtectedStreamKey = 8, | ||||
| 			StreamStartBytes = 9, | ||||
| 			InnerRandomStreamID = 10 | ||||
| 			StreamStartBytes = 9, // KDBX 3.1, for backward compatibility only | ||||
| 			InnerRandomStreamID = 10, | ||||
| 			KdfParameters = 11, // KDBX 4 | ||||
| 			PublicCustomData = 12 // KDBX 4 | ||||
| 		} | ||||
|  | ||||
| 		public byte[] HashOfFileOnDisk | ||||
| @@ -291,6 +342,152 @@ namespace KeePassLib.Serialization | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		private uint GetMinKdbxVersion() | ||||
| 		{ | ||||
| 			AesKdf kdfAes = new AesKdf(); | ||||
| 			if(!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) | ||||
| 				return FileVersion32; | ||||
|  | ||||
| 			if(m_pwDatabase.PublicCustomData.Count > 0) | ||||
| 				return FileVersion32; | ||||
|  | ||||
| 			bool bCustomData = false; | ||||
| 			GroupHandler gh = delegate(PwGroup pg) | ||||
| 			{ | ||||
| 				if(pg == null) { Debug.Assert(false); return true; } | ||||
| 				if(pg.CustomData.Count > 0) { bCustomData = true; return false; } | ||||
| 				return true; | ||||
| 			}; | ||||
| 			EntryHandler eh = delegate(PwEntry pe) | ||||
| 			{ | ||||
| 				if(pe == null) { Debug.Assert(false); return true; } | ||||
| 				if(pe.CustomData.Count > 0) { bCustomData = true; return false; } | ||||
| 				return true; | ||||
| 			}; | ||||
| 			gh(m_pwDatabase.RootGroup); | ||||
| 			m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); | ||||
| 			if(bCustomData) return FileVersion32; | ||||
|  | ||||
| 			return FileVersion32_3; // KDBX 3.1 is sufficient | ||||
| 		} | ||||
|  | ||||
| 		private void ComputeKeys(out byte[] pbCipherKey, int cbCipherKey, | ||||
| 			out byte[] pbHmacKey64) | ||||
| 		{ | ||||
| 			byte[] pbCmp = new byte[32 + 32 + 1]; | ||||
| 			try | ||||
| 			{ | ||||
| 				Debug.Assert(m_pbMasterSeed != null); | ||||
| 				if(m_pbMasterSeed == null) | ||||
| 					throw new ArgumentNullException("m_pbMasterSeed"); | ||||
| 				Debug.Assert(m_pbMasterSeed.Length == 32); | ||||
| 				if(m_pbMasterSeed.Length != 32) | ||||
| 					throw new FormatException(KLRes.MasterSeedLengthInvalid); | ||||
| 				Array.Copy(m_pbMasterSeed, 0, pbCmp, 0, 32); | ||||
|  | ||||
| 				Debug.Assert(m_pwDatabase != null); | ||||
| 				Debug.Assert(m_pwDatabase.MasterKey != null); | ||||
| 				ProtectedBinary pbinUser = m_pwDatabase.MasterKey.GenerateKey32( | ||||
| 					m_pwDatabase.KdfParameters); | ||||
| 				Debug.Assert(pbinUser != null); | ||||
| 				if(pbinUser == null) | ||||
| 					throw new SecurityException(KLRes.InvalidCompositeKey); | ||||
| 				byte[] pUserKey32 = pbinUser.ReadData(); | ||||
| 				if((pUserKey32 == null) || (pUserKey32.Length != 32)) | ||||
| 					throw new SecurityException(KLRes.InvalidCompositeKey); | ||||
| 				Array.Copy(pUserKey32, 0, pbCmp, 32, 32); | ||||
| 				MemUtil.ZeroByteArray(pUserKey32); | ||||
|  | ||||
| 				pbCipherKey = CryptoUtil.ResizeKey(pbCmp, 0, 64, cbCipherKey); | ||||
|  | ||||
| 				pbCmp[64] = 1; | ||||
| 				using(SHA512Managed h = new SHA512Managed()) | ||||
| 				{ | ||||
| 					pbHmacKey64 = h.ComputeHash(pbCmp); | ||||
| 				} | ||||
| 			} | ||||
| 			finally { MemUtil.ZeroByteArray(pbCmp); } | ||||
| 		} | ||||
|  | ||||
| 		private ICipherEngine GetCipher(out int cbEncKey, out int cbEncIV) | ||||
| 		{ | ||||
| 			PwUuid pu = m_pwDatabase.DataCipherUuid; | ||||
| 			ICipherEngine iCipher = CipherPool.GlobalPool.GetCipher(pu); | ||||
| 			if(iCipher == null) // CryptographicExceptions are translated to "file corrupted" | ||||
| 				throw new Exception(KLRes.FileUnknownCipher + | ||||
| 					MessageService.NewParagraph + KLRes.FileNewVerOrPlgReq + | ||||
| 					MessageService.NewParagraph + "UUID: " + pu.ToHexString() + "."); | ||||
|  | ||||
| 			ICipherEngine2 iCipher2 = (iCipher as ICipherEngine2); | ||||
| 			if(iCipher2 != null) | ||||
| 			{ | ||||
| 				cbEncKey = iCipher2.KeyLength; | ||||
| 				if(cbEncKey < 0) throw new InvalidOperationException("EncKey.Length"); | ||||
|  | ||||
| 				cbEncIV = iCipher2.IVLength; | ||||
| 				if(cbEncIV < 0) throw new InvalidOperationException("EncIV.Length"); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				cbEncKey = 32; | ||||
| 				cbEncIV = 16; | ||||
| 			} | ||||
|  | ||||
| 			return iCipher; | ||||
| 		} | ||||
|  | ||||
| 		private Stream EncryptStream(Stream s, ICipherEngine iCipher, | ||||
| 			byte[] pbKey, int cbIV, bool bEncrypt) | ||||
| 		{ | ||||
| 			byte[] pbIV = (m_pbEncryptionIV ?? MemUtil.EmptyByteArray); | ||||
| 			if(pbIV.Length != cbIV) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new Exception(KLRes.FileCorrupted); | ||||
| 			} | ||||
|  | ||||
| 			if(bEncrypt) | ||||
| 				return iCipher.EncryptStream(s, pbKey, pbIV); | ||||
| 			return iCipher.DecryptStream(s, pbKey, pbIV); | ||||
| 		} | ||||
|  | ||||
| 		private byte[] ComputeHeaderHmac(byte[] pbHeader, byte[] pbKey) | ||||
| 		{ | ||||
| 			byte[] pbHeaderHmac; | ||||
| 			byte[] pbBlockKey = HmacBlockStream.GetHmacKey64( | ||||
| 				pbKey, ulong.MaxValue); | ||||
| 			using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) | ||||
| 			{ | ||||
| 				pbHeaderHmac = h.ComputeHash(pbHeader); | ||||
| 			} | ||||
| 			MemUtil.ZeroByteArray(pbBlockKey); | ||||
|  | ||||
| 			return pbHeaderHmac; | ||||
| 		} | ||||
|  | ||||
| 		private void CloseStreams(List<Stream> lStreams) | ||||
| 		{ | ||||
| 			if(lStreams == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			// Typically, closing a stream also closes its base | ||||
| 			// stream; however, there may be streams that do not | ||||
| 			// do this (e.g. some cipher plugin), thus for safety | ||||
| 			// we close all streams manually, from the innermost | ||||
| 			// to the outermost | ||||
|  | ||||
| 			for(int i = lStreams.Count - 1; i >= 0; --i) | ||||
| 			{ | ||||
| 				// Check for duplicates | ||||
| 				Debug.Assert((lStreams.IndexOf(lStreams[i]) == i) && | ||||
| 					(lStreams.LastIndexOf(lStreams[i]) == i)); | ||||
|  | ||||
| 				try { lStreams[i].Close(); } | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
| 			} | ||||
|  | ||||
| 			// Do not clear the list | ||||
| 		} | ||||
|  | ||||
| 		private void BinPoolBuild(PwGroup pgDataSource) | ||||
| 		{ | ||||
| 			m_dictBinPool = new Dictionary<string, ProtectedBinary>(); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,15 +19,13 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Text; | ||||
| using System.Xml.Serialization; | ||||
|  | ||||
| using System.Diagnostics; | ||||
|  | ||||
| namespace KeePassLib.Translation | ||||
| { | ||||
| 	public class ToolStripItemCollection | ||||
| 	{} | ||||
| 	public sealed class KPStringTable | ||||
| 	{ | ||||
| 		private string m_strName = string.Empty; | ||||
| @@ -69,9 +65,9 @@ namespace KeePassLib.Translation | ||||
|  | ||||
| 			return dict; | ||||
| 		} | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 		/*public void ApplyTo(ToolStripItemCollection tsic) | ||||
| 		/* | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 		public void ApplyTo(ToolStripItemCollection tsic) | ||||
| 		{ | ||||
| 			if(tsic == null) throw new ArgumentNullException("tsic"); | ||||
|  | ||||
| @@ -97,7 +93,7 @@ namespace KeePassLib.Translation | ||||
| 				if((tsmi != null) && (tsmi.DropDownItems != null)) | ||||
| 					this.ApplyTo(tsmi.DropDownItems); | ||||
| 			} | ||||
| 		}*/ | ||||
| #endif | ||||
| 		} | ||||
| #endif*/ | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -21,24 +19,22 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
| using System.Xml.Serialization; | ||||
|  | ||||
| using System.ComponentModel; | ||||
| using System.Drawing; | ||||
| using System.Diagnostics; | ||||
| #if KeePassLibSD | ||||
| using ICSharpCode.SharpZipLib.GZip; | ||||
| #else | ||||
| using System.IO.Compression; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Interfaces; | ||||
| using KeePassLib.Utility; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| #else | ||||
| using ICSharpCode.SharpZipLib.GZip; | ||||
| #endif | ||||
|  | ||||
| namespace KeePassLib.Translation | ||||
| { | ||||
| 	[XmlRoot("Translation")] | ||||
| @@ -66,7 +62,7 @@ namespace KeePassLib.Translation | ||||
| 				m_vStringTables = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/* | ||||
| 		private List<KPFormCustomization> m_vForms = new List<KPFormCustomization>(); | ||||
|  | ||||
| 		[XmlArrayItem("Form")] | ||||
| @@ -80,7 +76,7 @@ namespace KeePassLib.Translation | ||||
| 				m_vForms = value; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		*/ | ||||
| 		private string m_strUnusedText = string.Empty; | ||||
| 		[DefaultValue("")] | ||||
| 		public string UnusedText | ||||
| @@ -94,18 +90,25 @@ namespace KeePassLib.Translation | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static void SaveToFile(KPTranslation kpTrl, string strFileName, | ||||
| 		public static void Save(KPTranslation kpTrl, string strFileName, | ||||
| 			IXmlSerializerEx xs) | ||||
| 		{ | ||||
| 			using(FileStream fs = new FileStream(strFileName, FileMode.Create, | ||||
| 				FileAccess.Write, FileShare.None)) | ||||
| 			{ | ||||
| 				Save(kpTrl, fs, xs); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static void Save(KPTranslation kpTrl, Stream sOut, | ||||
| 			IXmlSerializerEx xs) | ||||
| 		{ | ||||
| 			if(xs == null) throw new ArgumentNullException("xs"); | ||||
|  | ||||
| 			FileStream fs = new FileStream(strFileName, FileMode.Create, | ||||
| 				FileAccess.Write, FileShare.None); | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 			GZipStream gz = new GZipStream(fs, CompressionMode.Compress); | ||||
| 			GZipStream gz = new GZipStream(sOut, CompressionMode.Compress); | ||||
| #else | ||||
| 			GZipOutputStream gz = new GZipOutputStream(fs); | ||||
| 			GZipOutputStream gz = new GZipOutputStream(sOut); | ||||
| #endif | ||||
|  | ||||
| 			XmlWriterSettings xws = new XmlWriterSettings(); | ||||
| @@ -120,27 +123,36 @@ namespace KeePassLib.Translation | ||||
|  | ||||
| 			xw.Close(); | ||||
| 			gz.Close(); | ||||
| 			fs.Close(); | ||||
| 			sOut.Close(); | ||||
| 		} | ||||
|  | ||||
| 		public static KPTranslation LoadFromFile(string strFile, | ||||
| 			IXmlSerializerEx xs) | ||||
| 		public static KPTranslation Load(string strFile, IXmlSerializerEx xs) | ||||
| 		{ | ||||
| 			KPTranslation kpTrl = null; | ||||
|  | ||||
| 			using(FileStream fs = new FileStream(strFile, FileMode.Open, | ||||
| 				FileAccess.Read, FileShare.Read)) | ||||
| 			{ | ||||
| 				kpTrl = Load(fs, xs); | ||||
| 			} | ||||
|  | ||||
| 			return kpTrl; | ||||
| 		} | ||||
|  | ||||
| 		public static KPTranslation Load(Stream s, IXmlSerializerEx xs) | ||||
| 		{ | ||||
| 			if(xs == null) throw new ArgumentNullException("xs"); | ||||
|  | ||||
| 			FileStream fs = new FileStream(strFile, FileMode.Open, | ||||
| 				FileAccess.Read, FileShare.Read); | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 			GZipStream gz = new GZipStream(fs, CompressionMode.Decompress); | ||||
| 			GZipStream gz = new GZipStream(s, CompressionMode.Decompress); | ||||
| #else | ||||
| 			GZipInputStream gz = new GZipInputStream(fs); | ||||
| 			GZipInputStream gz = new GZipInputStream(s); | ||||
| #endif | ||||
|  | ||||
| 			KPTranslation kpTrl = (xs.Deserialize(gz) as KPTranslation); | ||||
|  | ||||
| 			gz.Close(); | ||||
| 			fs.Close(); | ||||
| 			s.Close(); | ||||
| 			return kpTrl; | ||||
| 		} | ||||
|  | ||||
| @@ -154,9 +166,9 @@ namespace KeePassLib.Translation | ||||
|  | ||||
| 			return new Dictionary<string, string>(); | ||||
| 		} | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 		/*public void ApplyTo(Form form) | ||||
| 		/* | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 		public void ApplyTo(Form form) | ||||
| 		{ | ||||
| 			if(form == null) throw new ArgumentNullException("form"); | ||||
|  | ||||
| @@ -185,8 +197,8 @@ namespace KeePassLib.Translation | ||||
| 				try { RtlApplyToControls(form.Controls); } | ||||
| 				catch(Exception) { Debug.Assert(false); } | ||||
| 			} | ||||
| 		}*/ | ||||
| 		/* | ||||
| 		} | ||||
|  | ||||
| 		private static void RtlApplyToControls(Control.ControlCollection cc) | ||||
| 		{ | ||||
| 			foreach(Control c in cc) | ||||
| @@ -212,9 +224,9 @@ namespace KeePassLib.Translation | ||||
|  | ||||
| 				if((c is GroupBox) || (c is Panel)) RtlMoveChildControls(c); | ||||
| 			} | ||||
| 		}*/ | ||||
| 		} | ||||
|  | ||||
| 		/*private static void RtlMoveChildControls(Control cParent) | ||||
| 		private static void RtlMoveChildControls(Control cParent) | ||||
| 		{ | ||||
| 			int nParentWidth = cParent.Size.Width; | ||||
|  | ||||
| @@ -248,7 +260,7 @@ namespace KeePassLib.Translation | ||||
| 			} | ||||
|  | ||||
| 			if(kpst != null) kpst.ApplyTo(tsic); | ||||
| 		}*/ | ||||
| #endif | ||||
| 		} | ||||
| #endif*/ | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,9 +19,9 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.IO; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| @@ -38,8 +38,7 @@ namespace KeePassLib.Utility | ||||
|  | ||||
| 		public static void Open(string strPrefix) | ||||
| 		{ | ||||
| 			return; // Logging is not enabled in normal builds of KeePass! | ||||
|  | ||||
| 			// Logging is not enabled in normal builds of KeePass! | ||||
| 			/* | ||||
| 			AppLogEx.Close(); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,15 +19,15 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Security.Cryptography; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Text; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| using System.IO.Compression; | ||||
| #else | ||||
| #if KeePassLibSD | ||||
| using KeePassLibSD; | ||||
| #else | ||||
| using System.IO.Compression; | ||||
| #endif | ||||
|  | ||||
| namespace KeePassLib.Utility | ||||
| @@ -37,6 +37,8 @@ namespace KeePassLib.Utility | ||||
| 	/// </summary> | ||||
| 	public static class MemUtil | ||||
| 	{ | ||||
| 		internal static readonly byte[] EmptyByteArray = new byte[0]; | ||||
|  | ||||
| 		private static readonly uint[] m_vSBox = new uint[256] { | ||||
| 			0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230, | ||||
| 			0x3A321712, 0x06403DB1, 0xD2F84B95, 0xDF22A6E4, | ||||
| @@ -187,75 +189,211 @@ namespace KeePassLib.Utility | ||||
| 			return sb.ToString(); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Decode Base32 strings according to RFC 4648. | ||||
| 		/// </summary> | ||||
| 		public static byte[] ParseBase32(string str) | ||||
| 		{ | ||||
| 			if((str == null) || ((str.Length % 8) != 0)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				return null; | ||||
| 			} | ||||
|  | ||||
| 			ulong uMaxBits = (ulong)str.Length * 5UL; | ||||
| 			List<byte> l = new List<byte>((int)(uMaxBits / 8UL) + 1); | ||||
| 			Debug.Assert(l.Count == 0); | ||||
|  | ||||
| 			for(int i = 0; i < str.Length; i += 8) | ||||
| 			{ | ||||
| 				ulong u = 0; | ||||
| 				int nBits = 0; | ||||
|  | ||||
| 				for(int j = 0; j < 8; ++j) | ||||
| 				{ | ||||
| 					char ch = str[i + j]; | ||||
| 					if(ch == '=') break; | ||||
|  | ||||
| 					ulong uValue; | ||||
| 					if((ch >= 'A') && (ch <= 'Z')) | ||||
| 						uValue = (ulong)(ch - 'A'); | ||||
| 					else if((ch >= 'a') && (ch <= 'z')) | ||||
| 						uValue = (ulong)(ch - 'a'); | ||||
| 					else if((ch >= '2') && (ch <= '7')) | ||||
| 						uValue = (ulong)(ch - '2') + 26UL; | ||||
| 					else { Debug.Assert(false); return null; } | ||||
|  | ||||
| 					u <<= 5; | ||||
| 					u += uValue; | ||||
| 					nBits += 5; | ||||
| 				} | ||||
|  | ||||
| 				int nBitsTooMany = (nBits % 8); | ||||
| 				u >>= nBitsTooMany; | ||||
| 				nBits -= nBitsTooMany; | ||||
| 				Debug.Assert((nBits % 8) == 0); | ||||
|  | ||||
| 				int idxNewBytes = l.Count; | ||||
| 				while(nBits > 0) | ||||
| 				{ | ||||
| 					l.Add((byte)(u & 0xFF)); | ||||
| 					u >>= 8; | ||||
| 					nBits -= 8; | ||||
| 				} | ||||
| 				l.Reverse(idxNewBytes, l.Count - idxNewBytes); | ||||
| 			} | ||||
|  | ||||
| 			return l.ToArray(); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Set all bytes in a byte array to zero. | ||||
| 		/// </summary> | ||||
| 		/// <param name="pbArray">Input array. All bytes of this array will be set | ||||
| 		/// to zero.</param> | ||||
| 		/// <param name="pbArray">Input array. All bytes of this array | ||||
| 		/// will be set to zero.</param> | ||||
| #if KeePassLibSD | ||||
| 		[MethodImpl(MethodImplOptions.NoInlining)] | ||||
| #else | ||||
| 		[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] | ||||
| #endif | ||||
| 		public static void ZeroByteArray(byte[] pbArray) | ||||
| 		{ | ||||
| 			Debug.Assert(pbArray != null); if(pbArray == null) throw new ArgumentNullException("pbArray"); | ||||
|  | ||||
| 			// for(int i = 0; i < pbArray.Length; ++i) | ||||
| 			//	pbArray[i] = 0; | ||||
| 			Debug.Assert(pbArray != null); | ||||
| 			if(pbArray == null) throw new ArgumentNullException("pbArray"); | ||||
|  | ||||
| 			Array.Clear(pbArray, 0, pbArray.Length); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 2 bytes to a 16-bit unsigned integer using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Set all elements of an array to the default value. | ||||
| 		/// </summary> | ||||
| 		/// <param name="v">Input array.</param> | ||||
| #if KeePassLibSD | ||||
| 		[MethodImpl(MethodImplOptions.NoInlining)] | ||||
| #else | ||||
| 		[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)] | ||||
| #endif | ||||
| 		public static void ZeroArray<T>(T[] v) | ||||
| 		{ | ||||
| 			if(v == null) { Debug.Assert(false); throw new ArgumentNullException("v"); } | ||||
|  | ||||
| 			Array.Clear(v, 0, v.Length); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 2 bytes to a 16-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="pb">Input bytes. Array must contain at least 2 bytes.</param> | ||||
| 		/// <returns>16-bit unsigned integer.</returns> | ||||
| 		public static ushort BytesToUInt16(byte[] pb) | ||||
| 		{ | ||||
| 			Debug.Assert((pb != null) && (pb.Length == 2)); | ||||
| 			if(pb == null) throw new ArgumentNullException("pb"); | ||||
| 			if(pb.Length != 2) throw new ArgumentException(); | ||||
| 			if(pb.Length != 2) throw new ArgumentOutOfRangeException("pb"); | ||||
|  | ||||
| 			return (ushort)((ushort)pb[0] | ((ushort)pb[1] << 8)); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 4 bytes to a 32-bit unsigned integer using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Convert 2 bytes to a 16-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		public static ushort BytesToUInt16(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } | ||||
| 			if((iOffset < 0) || ((iOffset + 1) >= pb.Length)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			} | ||||
|  | ||||
| 			return (ushort)((ushort)pb[iOffset] | ((ushort)pb[iOffset + 1] << 8)); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 4 bytes to a 32-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="pb">Input bytes.</param> | ||||
| 		/// <returns>32-bit unsigned integer.</returns> | ||||
| 		public static uint BytesToUInt32(byte[] pb) | ||||
| 		{ | ||||
| 			Debug.Assert((pb != null) && (pb.Length == 4)); | ||||
| 			if(pb == null) throw new ArgumentNullException("pb"); | ||||
| 			if(pb.Length != 4) throw new ArgumentException("Input array must contain 4 bytes!"); | ||||
| 			if(pb.Length != 4) throw new ArgumentOutOfRangeException("pb"); | ||||
|  | ||||
| 			return (uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) | | ||||
| 				((uint)pb[3] << 24); | ||||
| 			return ((uint)pb[0] | ((uint)pb[1] << 8) | ((uint)pb[2] << 16) | | ||||
| 				((uint)pb[3] << 24)); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 8 bytes to a 64-bit unsigned integer using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Convert 4 bytes to a 32-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		public static uint BytesToUInt32(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } | ||||
| 			if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			} | ||||
|  | ||||
| 			return ((uint)pb[iOffset] | ((uint)pb[iOffset + 1] << 8) | | ||||
| 				((uint)pb[iOffset + 2] << 16) | ((uint)pb[iOffset + 3] << 24)); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert 8 bytes to a 64-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="pb">Input bytes.</param> | ||||
| 		/// <returns>64-bit unsigned integer.</returns> | ||||
| 		public static ulong BytesToUInt64(byte[] pb) | ||||
| 		{ | ||||
| 			Debug.Assert((pb != null) && (pb.Length == 8)); | ||||
| 			if(pb == null) throw new ArgumentNullException("pb"); | ||||
| 			if(pb.Length != 8) throw new ArgumentException(); | ||||
| 			if(pb.Length != 8) throw new ArgumentOutOfRangeException("pb"); | ||||
|  | ||||
| 			return (ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) | | ||||
| 			return ((ulong)pb[0] | ((ulong)pb[1] << 8) | ((ulong)pb[2] << 16) | | ||||
| 				((ulong)pb[3] << 24) | ((ulong)pb[4] << 32) | ((ulong)pb[5] << 40) | | ||||
| 				((ulong)pb[6] << 48) | ((ulong)pb[7] << 56); | ||||
| 				((ulong)pb[6] << 48) | ((ulong)pb[7] << 56)); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 16-bit unsigned integer to 2 bytes using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Convert 8 bytes to a 64-bit unsigned integer (little-endian). | ||||
| 		/// </summary> | ||||
| 		public static ulong BytesToUInt64(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } | ||||
| 			if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			} | ||||
|  | ||||
| 			// if(BitConverter.IsLittleEndian) | ||||
| 			//	return BitConverter.ToUInt64(pb, iOffset); | ||||
|  | ||||
| 			return ((ulong)pb[iOffset] | ((ulong)pb[iOffset + 1] << 8) | | ||||
| 				((ulong)pb[iOffset + 2] << 16) | ((ulong)pb[iOffset + 3] << 24) | | ||||
| 				((ulong)pb[iOffset + 4] << 32) | ((ulong)pb[iOffset + 5] << 40) | | ||||
| 				((ulong)pb[iOffset + 6] << 48) | ((ulong)pb[iOffset + 7] << 56)); | ||||
| 		} | ||||
|  | ||||
| 		public static int BytesToInt32(byte[] pb) | ||||
| 		{ | ||||
| 			return (int)BytesToUInt32(pb); | ||||
| 		} | ||||
|  | ||||
| 		public static int BytesToInt32(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			return (int)BytesToUInt32(pb, iOffset); | ||||
| 		} | ||||
|  | ||||
| 		public static long BytesToInt64(byte[] pb) | ||||
| 		{ | ||||
| 			return (long)BytesToUInt64(pb); | ||||
| 		} | ||||
|  | ||||
| 		public static long BytesToInt64(byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			return (long)BytesToUInt64(pb, iOffset); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 16-bit unsigned integer to 2 bytes (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="uValue">16-bit input word.</param> | ||||
| 		/// <returns>Two bytes representing the 16-bit value.</returns> | ||||
| 		public static byte[] UInt16ToBytes(ushort uValue) | ||||
| 		{ | ||||
| 			byte[] pb = new byte[2]; | ||||
| @@ -270,11 +408,8 @@ namespace KeePassLib.Utility | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 32-bit unsigned integer to 4 bytes using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Convert a 32-bit unsigned integer to 4 bytes (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="uValue">32-bit input word.</param> | ||||
| 		/// <returns>Four bytes representing the 32-bit value.</returns> | ||||
| 		public static byte[] UInt32ToBytes(uint uValue) | ||||
| 		{ | ||||
| 			byte[] pb = new byte[4]; | ||||
| @@ -291,11 +426,29 @@ namespace KeePassLib.Utility | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 64-bit unsigned integer to 8 bytes using Little-Endian | ||||
| 		/// encoding. | ||||
| 		/// Convert a 32-bit unsigned integer to 4 bytes (little-endian). | ||||
| 		/// </summary> | ||||
| 		public static void UInt32ToBytesEx(uint uValue, byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } | ||||
| 			if((iOffset < 0) || ((iOffset + 3) >= pb.Length)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			} | ||||
|  | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				pb[iOffset] = (byte)uValue; | ||||
| 				pb[iOffset + 1] = (byte)(uValue >> 8); | ||||
| 				pb[iOffset + 2] = (byte)(uValue >> 16); | ||||
| 				pb[iOffset + 3] = (byte)(uValue >> 24); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 64-bit unsigned integer to 8 bytes (little-endian). | ||||
| 		/// </summary> | ||||
| 		/// <param name="uValue">64-bit input word.</param> | ||||
| 		/// <returns>Eight bytes representing the 64-bit value.</returns> | ||||
| 		public static byte[] UInt64ToBytes(ulong uValue) | ||||
| 		{ | ||||
| 			byte[] pb = new byte[8]; | ||||
| @@ -315,6 +468,61 @@ namespace KeePassLib.Utility | ||||
| 			return pb; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Convert a 64-bit unsigned integer to 8 bytes (little-endian). | ||||
| 		/// </summary> | ||||
| 		public static void UInt64ToBytesEx(ulong uValue, byte[] pb, int iOffset) | ||||
| 		{ | ||||
| 			if(pb == null) { Debug.Assert(false); throw new ArgumentNullException("pb"); } | ||||
| 			if((iOffset < 0) || ((iOffset + 7) >= pb.Length)) | ||||
| 			{ | ||||
| 				Debug.Assert(false); | ||||
| 				throw new ArgumentOutOfRangeException("iOffset"); | ||||
| 			} | ||||
|  | ||||
| 			unchecked | ||||
| 			{ | ||||
| 				pb[iOffset] = (byte)uValue; | ||||
| 				pb[iOffset + 1] = (byte)(uValue >> 8); | ||||
| 				pb[iOffset + 2] = (byte)(uValue >> 16); | ||||
| 				pb[iOffset + 3] = (byte)(uValue >> 24); | ||||
| 				pb[iOffset + 4] = (byte)(uValue >> 32); | ||||
| 				pb[iOffset + 5] = (byte)(uValue >> 40); | ||||
| 				pb[iOffset + 6] = (byte)(uValue >> 48); | ||||
| 				pb[iOffset + 7] = (byte)(uValue >> 56); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] Int32ToBytes(int iValue) | ||||
| 		{ | ||||
| 			return UInt32ToBytes((uint)iValue); | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] Int64ToBytes(long lValue) | ||||
| 		{ | ||||
| 			return UInt64ToBytes((ulong)lValue); | ||||
| 		} | ||||
|  | ||||
| 		public static uint RotateLeft32(uint u, int nBits) | ||||
| 		{ | ||||
| 			return ((u << nBits) | (u >> (32 - nBits))); | ||||
| 		} | ||||
|  | ||||
| 		public static uint RotateRight32(uint u, int nBits) | ||||
| 		{ | ||||
| 			return ((u >> nBits) | (u << (32 - nBits))); | ||||
| 		} | ||||
|  | ||||
| 		public static ulong RotateLeft64(ulong u, int nBits) | ||||
| 		{ | ||||
| 			return ((u << nBits) | (u >> (64 - nBits))); | ||||
| 		} | ||||
|  | ||||
| 		public static ulong RotateRight64(ulong u, int nBits) | ||||
| 		{ | ||||
| 			return ((u >> nBits) | (u << (64 - nBits))); | ||||
| 		} | ||||
|  | ||||
| 		public static bool ArraysEqual(byte[] x, byte[] y) | ||||
| 		{ | ||||
| 			// Return false if one of them is null (not comparable)! | ||||
| @@ -330,19 +538,21 @@ namespace KeePassLib.Utility | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public static void XorArray(byte[] pbSource, int nSourceOffset, | ||||
| 			byte[] pbBuffer, int nBufferOffset, int nLength) | ||||
| 		public static void XorArray(byte[] pbSource, int iSourceOffset, | ||||
| 			byte[] pbBuffer, int iBufferOffset, int cb) | ||||
| 		{ | ||||
| 			if(pbSource == null) throw new ArgumentNullException("pbSource"); | ||||
| 			if(nSourceOffset < 0) throw new ArgumentException(); | ||||
| 			if(iSourceOffset < 0) throw new ArgumentOutOfRangeException("iSourceOffset"); | ||||
| 			if(pbBuffer == null) throw new ArgumentNullException("pbBuffer"); | ||||
| 			if(nBufferOffset < 0) throw new ArgumentException(); | ||||
| 			if(nLength < 0) throw new ArgumentException(); | ||||
| 			if((nSourceOffset + nLength) > pbSource.Length) throw new ArgumentException(); | ||||
| 			if((nBufferOffset + nLength) > pbBuffer.Length) throw new ArgumentException(); | ||||
| 			if(iBufferOffset < 0) throw new ArgumentOutOfRangeException("iBufferOffset"); | ||||
| 			if(cb < 0) throw new ArgumentOutOfRangeException("cb"); | ||||
| 			if(iSourceOffset > (pbSource.Length - cb)) | ||||
| 				throw new ArgumentOutOfRangeException("cb"); | ||||
| 			if(iBufferOffset > (pbBuffer.Length - cb)) | ||||
| 				throw new ArgumentOutOfRangeException("cb"); | ||||
|  | ||||
| 			for(int i = 0; i < nLength; ++i) | ||||
| 				pbBuffer[nBufferOffset + i] ^= pbSource[nSourceOffset + i]; | ||||
| 			for(int i = 0; i < cb; ++i) | ||||
| 				pbBuffer[iBufferOffset + i] ^= pbSource[iSourceOffset + i]; | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -421,7 +631,8 @@ namespace KeePassLib.Utility | ||||
| 			if(s == null) { Debug.Assert(false); return; } | ||||
| 			if(pbData == null) { Debug.Assert(false); return; } | ||||
|  | ||||
| 			s.Write(pbData, 0, pbData.Length); | ||||
| 			Debug.Assert(pbData.Length >= 0); | ||||
| 			if(pbData.Length > 0) s.Write(pbData, 0, pbData.Length); | ||||
| 		} | ||||
|  | ||||
| 		public static byte[] Compress(byte[] pbData) | ||||
| @@ -429,15 +640,21 @@ namespace KeePassLib.Utility | ||||
| 			if(pbData == null) throw new ArgumentNullException("pbData"); | ||||
| 			if(pbData.Length == 0) return pbData; | ||||
|  | ||||
| 			MemoryStream msCompressed = new MemoryStream(); | ||||
| 			GZipStream gz = new GZipStream(msCompressed, CompressionMode.Compress); | ||||
| 			MemoryStream msSource = new MemoryStream(pbData, false); | ||||
| 			MemUtil.CopyStream(msSource, gz); | ||||
| 			gz.Close(); | ||||
| 			msSource.Close(); | ||||
| 			byte[] pbCompressed; | ||||
| 			using(MemoryStream msSource = new MemoryStream(pbData, false)) | ||||
| 			{ | ||||
| 				using(MemoryStream msCompressed = new MemoryStream()) | ||||
| 				{ | ||||
| 					using(GZipStream gz = new GZipStream(msCompressed, | ||||
| 						CompressionMode.Compress)) | ||||
| 					{ | ||||
| 						MemUtil.CopyStream(msSource, gz); | ||||
| 					} | ||||
|  | ||||
| 					pbCompressed = msCompressed.ToArray(); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbCompressed = msCompressed.ToArray(); | ||||
| 			msCompressed.Close(); | ||||
| 			return pbCompressed; | ||||
| 		} | ||||
|  | ||||
| @@ -446,15 +663,21 @@ namespace KeePassLib.Utility | ||||
| 			if(pbCompressed == null) throw new ArgumentNullException("pbCompressed"); | ||||
| 			if(pbCompressed.Length == 0) return pbCompressed; | ||||
|  | ||||
| 			MemoryStream msCompressed = new MemoryStream(pbCompressed, false); | ||||
| 			GZipStream gz = new GZipStream(msCompressed, CompressionMode.Decompress); | ||||
| 			MemoryStream msData = new MemoryStream(); | ||||
| 			MemUtil.CopyStream(gz, msData); | ||||
| 			gz.Close(); | ||||
| 			msCompressed.Close(); | ||||
| 			byte[] pbData; | ||||
| 			using(MemoryStream msData = new MemoryStream()) | ||||
| 			{ | ||||
| 				using(MemoryStream msCompressed = new MemoryStream(pbCompressed, false)) | ||||
| 				{ | ||||
| 					using(GZipStream gz = new GZipStream(msCompressed, | ||||
| 						CompressionMode.Decompress)) | ||||
| 					{ | ||||
| 						MemUtil.CopyStream(gz, msData); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				pbData = msData.ToArray(); | ||||
| 			} | ||||
|  | ||||
| 			byte[] pbData = msData.ToArray(); | ||||
| 			msData.Close(); | ||||
| 			return pbData; | ||||
| 		} | ||||
|  | ||||
|   | ||||
							
								
								
									
										183
									
								
								src/KeePassLib2Android/Utility/MonoWorkarounds.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/KeePassLib2Android/Utility/MonoWorkarounds.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
|   the Free Software Foundation; either version 2 of the License, or | ||||
|   (at your option) any later version. | ||||
|  | ||||
|   This program is distributed in the hope that it will be useful, | ||||
|   but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|   GNU General Public License for more details. | ||||
|  | ||||
|   You should have received a copy of the GNU General Public License | ||||
|   along with this program; if not, write to the Free Software | ||||
|   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Reflection; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
|  | ||||
| using KeePassLib.Native; | ||||
|  | ||||
| namespace KeePassLib.Utility | ||||
| { | ||||
| 	public static class MonoWorkarounds | ||||
| 	{ | ||||
| 		private static Dictionary<uint, bool> m_dForceReq = new Dictionary<uint, bool>(); | ||||
|  | ||||
| 		private static bool? m_bReq = null; | ||||
| 		public static bool IsRequired() | ||||
| 		{ | ||||
| 			if(!m_bReq.HasValue) m_bReq = NativeLib.IsUnix(); | ||||
| 			return m_bReq.Value; | ||||
| 		} | ||||
|  | ||||
| 		// 1219: | ||||
| 		//   Mono prepends byte order mark (BOM) to StdIn. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1219/ | ||||
| 		// 1245: | ||||
| 		//   Key events not raised while Alt is down, and nav keys out of order. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1245/ | ||||
| 		// 1254: | ||||
| 		//   NumericUpDown bug: text is drawn below up/down buttons. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1254/ | ||||
| 		// 1354: | ||||
| 		//   Finalizer of NotifyIcon throws on Unity. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1354/ | ||||
| 		// 1358: | ||||
| 		//   FileDialog crashes when ~/.recently-used is invalid. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1358/ | ||||
| 		// 1366: | ||||
| 		//   Drawing bug when scrolling a RichTextBox. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1366/ | ||||
| 		// 1378: | ||||
| 		//   Mono doesn't implement Microsoft.Win32.SystemEvents events. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1378/ | ||||
| 		//   https://github.com/mono/mono/blob/master/mcs/class/System/Microsoft.Win32/SystemEvents.cs | ||||
| 		// 1418: | ||||
| 		//   Minimizing a form while loading it doesn't work. | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1418/ | ||||
| 		// 2139: | ||||
| 		//   Shortcut keys are ignored. | ||||
| 		//   https://sourceforge.net/p/keepass/feature-requests/2139/ | ||||
| 		// 2140: | ||||
| 		//   Explicit control focusing is ignored. | ||||
| 		//   https://sourceforge.net/p/keepass/feature-requests/2140/ | ||||
| 		// 5795: | ||||
| 		//   Text in input field is incomplete. | ||||
| 		//   https://bugzilla.xamarin.com/show_bug.cgi?id=5795 | ||||
| 		//   https://sourceforge.net/p/keepass/discussion/329220/thread/d23dc88b/ | ||||
| 		// 10163: | ||||
| 		//   WebRequest GetResponse call missing, breaks WebDAV due to no PUT. | ||||
| 		//   https://bugzilla.xamarin.com/show_bug.cgi?id=10163 | ||||
| 		//   https://sourceforge.net/p/keepass/bugs/1117/ | ||||
| 		//   https://sourceforge.net/p/keepass/discussion/329221/thread/9422258c/ | ||||
| 		//   https://github.com/mono/mono/commit/8e67b8c2fc7cb66bff7816ebf7c1039fb8cfc43b | ||||
| 		//   https://bugzilla.xamarin.com/show_bug.cgi?id=1512 | ||||
| 		//   https://sourceforge.net/p/keepass/patches/89/ | ||||
| 		// 12525: | ||||
| 		//   PictureBox not rendered when bitmap height >= control height. | ||||
| 		//   https://bugzilla.xamarin.com/show_bug.cgi?id=12525 | ||||
| 		//   https://sourceforge.net/p/keepass/discussion/329220/thread/54f61e9a/ | ||||
| 		// 586901: | ||||
| 		//   RichTextBox doesn't handle Unicode string correctly. | ||||
| 		//   https://bugzilla.novell.com/show_bug.cgi?id=586901 | ||||
| 		// 620618: | ||||
| 		//   ListView column headers not drawn. | ||||
| 		//   https://bugzilla.novell.com/show_bug.cgi?id=620618 | ||||
| 		// 649266: | ||||
| 		//   Calling Control.Hide doesn't remove the application from taskbar. | ||||
| 		//   https://bugzilla.novell.com/show_bug.cgi?id=649266 | ||||
| 		// 686017: | ||||
| 		//   Minimum sizes must be enforced. | ||||
| 		//   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=686017 | ||||
| 		// 801414: | ||||
| 		//   Mono recreates the main window incorrectly. | ||||
| 		//   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) | ||||
| 		{ | ||||
| 			if(!MonoWorkarounds.IsRequired()) return false; | ||||
|  | ||||
| 			bool bForce; | ||||
| 			if(m_dForceReq.TryGetValue(uBugID, out bForce)) return bForce; | ||||
|  | ||||
| 			ulong v = NativeLib.MonoVersion; | ||||
| 			if(v != 0) | ||||
| 			{ | ||||
| 				if(uBugID == 10163) | ||||
| 					return (v >= 0x0002000B00000000UL); // >= 2.11 | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		internal static void SetEnabled(string strIDs, bool bEnabled) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(strIDs)) return; | ||||
|  | ||||
| 			string[] vIDs = strIDs.Split(new char[] { ',' }); | ||||
| 			foreach(string strID in vIDs) | ||||
| 			{ | ||||
| 				if(string.IsNullOrEmpty(strID)) continue; | ||||
|  | ||||
| 				uint uID; | ||||
| 				if(StrUtil.TryParseUInt(strID.Trim(), out uID)) | ||||
| 					m_dForceReq[uID] = bEnabled; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Ensure that the file ~/.recently-used is valid (in order to | ||||
| 		/// prevent Mono's FileDialog from crashing). | ||||
| 		/// </summary> | ||||
| 		internal static void EnsureRecentlyUsedValid() | ||||
| 		{ | ||||
| 			if(!MonoWorkarounds.IsRequired(1358)) return; | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				string strFile = Environment.GetFolderPath( | ||||
| 					Environment.SpecialFolder.Personal); | ||||
| 				strFile = UrlUtil.EnsureTerminatingSeparator(strFile, false); | ||||
| 				strFile += ".recently-used"; | ||||
|  | ||||
| 				if(File.Exists(strFile)) | ||||
| 				{ | ||||
| 					try | ||||
| 					{ | ||||
| 						// Mono's WriteRecentlyUsedFiles method also loads the | ||||
| 						// XML file using XmlDocument | ||||
| 						XmlDocument xd = new XmlDocument(); | ||||
| 						xd.Load(strFile); | ||||
| 					} | ||||
| 					catch(Exception) // The XML file is invalid | ||||
| 					{ | ||||
| 						File.Delete(strFile); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
| } | ||||
| @@ -1,8 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|    | ||||
|   Modified to be used with Mono for Android. Changes Copyright (C) 2013 Philipp Crocoll | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -22,19 +20,21 @@ | ||||
| using System; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Text; | ||||
| using System.Drawing; | ||||
| using System.IO; | ||||
| using System.Text.RegularExpressions; | ||||
| using System.Security.Cryptography; | ||||
| using System.Globalization; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
| using System.Text.RegularExpressions; | ||||
|  | ||||
| #if !KeePassUAP | ||||
| using System.Drawing; | ||||
| using System.Security.Cryptography; | ||||
| #endif | ||||
|  | ||||
| using KeePassLib.Collections; | ||||
| using KeePassLib.Cryptography.PasswordGenerator; | ||||
| using KeePassLib.Native; | ||||
| using KeePassLib.Security; | ||||
| using KeePassLib.Resources; | ||||
|  | ||||
| namespace KeePassLib.Utility | ||||
| { | ||||
| @@ -221,8 +221,8 @@ namespace KeePassLib.Utility | ||||
| 				List<StrEncodingInfo> l = new List<StrEncodingInfo>(); | ||||
|  | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Default, | ||||
| #if KeePassRT | ||||
| 					StrUtil.Utf8.WebName, StrUtil.Utf8, 1, null)); | ||||
| #if KeePassUAP | ||||
| 					"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); | ||||
| #else | ||||
| #if !KeePassLibSD | ||||
| 					Encoding.Default.EncodingName, | ||||
| @@ -232,12 +232,11 @@ namespace KeePassLib.Utility | ||||
| 					Encoding.Default, | ||||
| 					(uint)Encoding.Default.GetBytes("a").Length, null)); | ||||
| #endif | ||||
| #if !KeePassRT | ||||
|  | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Ascii, | ||||
| 					"ASCII", Encoding.ASCII, 1, null)); | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Utf7, | ||||
| 					"Unicode (UTF-7)", Encoding.UTF7, 1, null)); | ||||
| #endif | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Utf8, | ||||
| 					"Unicode (UTF-8)", StrUtil.Utf8, 1, new byte[] { 0xEF, 0xBB, 0xBF })); | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Utf16LE, | ||||
| @@ -246,7 +245,8 @@ namespace KeePassLib.Utility | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Utf16BE, | ||||
| 					"Unicode (UTF-16 BE)", new UnicodeEncoding(true, false), | ||||
| 					2, new byte[] { 0xFE, 0xFF })); | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 				l.Add(new StrEncodingInfo(StrEncodingType.Utf32LE, | ||||
| 					"Unicode (UTF-32 LE)", new UTF32Encoding(false, false), | ||||
| 					4, new byte[] { 0xFF, 0xFE, 0x0, 0x0 })); | ||||
| @@ -315,7 +315,7 @@ namespace KeePassLib.Utility | ||||
| 			str = str.Replace("\'", @"'"); | ||||
|  | ||||
| 			str = NormalizeNewLines(str, false); | ||||
| 			str = str.Replace("\n", @"<br />"); | ||||
| 			str = str.Replace("\n", @"<br />\n" ); | ||||
|  | ||||
| 			return str; | ||||
| 		} | ||||
| @@ -358,9 +358,9 @@ namespace KeePassLib.Utility | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Split up a command-line into application and argument. | ||||
| 		/// Split up a command line into application and argument. | ||||
| 		/// </summary> | ||||
| 		/// <param name="strCmdLine">Command-line to split.</param> | ||||
| 		/// <param name="strCmdLine">Command line to split.</param> | ||||
| 		/// <param name="strApp">Application path.</param> | ||||
| 		/// <param name="strArgs">Arguments.</param> | ||||
| 		public static void SplitCommandLine(string strCmdLine, out string strApp, out string strArgs) | ||||
| @@ -487,53 +487,53 @@ namespace KeePassLib.Utility | ||||
| 		public static string FormatException(Exception excp) | ||||
| 		{ | ||||
| 			string strText = string.Empty; | ||||
| 			 | ||||
| 			string NewLine = "\n"; | ||||
| 			if(excp.Message != null) | ||||
| 				strText += excp.Message + MessageService.NewLine; | ||||
| 				strText += excp.Message + NewLine; | ||||
| #if !KeePassLibSD | ||||
| 			if(excp.Source != null) | ||||
| 				strText += excp.Source + MessageService.NewLine; | ||||
| 				strText += excp.Source + NewLine; | ||||
| #endif | ||||
| 			if(excp.StackTrace != null) | ||||
| 				strText += excp.StackTrace + MessageService.NewLine; | ||||
| 				strText += excp.StackTrace + NewLine; | ||||
| #if !KeePassLibSD | ||||
| #if !KeePassRT | ||||
| #if !KeePassUAP | ||||
| 			if(excp.TargetSite != null) | ||||
| 				strText += excp.TargetSite.ToString() + MessageService.NewLine; | ||||
| 				strText += excp.TargetSite.ToString() + NewLine; | ||||
| #endif | ||||
|  | ||||
| 			if(excp.Data != null) | ||||
| 			{ | ||||
| 				strText += MessageService.NewLine; | ||||
| 				strText += NewLine; | ||||
| 				foreach(DictionaryEntry de in excp.Data) | ||||
| 					strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" + | ||||
| 						MessageService.NewLine; | ||||
| 						NewLine; | ||||
| 			} | ||||
| #endif | ||||
|  | ||||
| 			if(excp.InnerException != null) | ||||
| 			{ | ||||
| 				strText += MessageService.NewLine + "Inner:" + MessageService.NewLine; | ||||
| 				strText += NewLine + "Inner:" + NewLine; | ||||
| 				if(excp.InnerException.Message != null) | ||||
| 					strText += excp.InnerException.Message + MessageService.NewLine; | ||||
| 					strText += excp.InnerException.Message + NewLine; | ||||
| #if !KeePassLibSD | ||||
| 				if(excp.InnerException.Source != null) | ||||
| 					strText += excp.InnerException.Source + MessageService.NewLine; | ||||
| 					strText += excp.InnerException.Source + NewLine; | ||||
| #endif | ||||
| 				if(excp.InnerException.StackTrace != null) | ||||
| 					strText += excp.InnerException.StackTrace + MessageService.NewLine; | ||||
| 					strText += excp.InnerException.StackTrace + NewLine; | ||||
| #if !KeePassLibSD | ||||
| #if !KeePassRT | ||||
| #if !KeePassUAP | ||||
| 				if(excp.InnerException.TargetSite != null) | ||||
| 					strText += excp.InnerException.TargetSite.ToString(); | ||||
| #endif | ||||
|  | ||||
| 				if(excp.InnerException.Data != null) | ||||
| 				{ | ||||
| 					strText += MessageService.NewLine; | ||||
| 					strText += NewLine; | ||||
| 					foreach(DictionaryEntry de in excp.InnerException.Data) | ||||
| 						strText += @"'" + de.Key + @"' -> '" + de.Value + @"'" + | ||||
| 							MessageService.NewLine; | ||||
| 							NewLine; | ||||
| 				} | ||||
| #endif | ||||
| 			} | ||||
| @@ -760,7 +760,7 @@ namespace KeePassLib.Utility | ||||
| 			return sb.ToString(); | ||||
| 		} | ||||
|  | ||||
| 		private static Regex m_rxNaturalSplit = null; | ||||
| 		/* private static Regex g_rxNaturalSplit = null; | ||||
| 		public static int CompareNaturally(string strX, string strY) | ||||
| 		{ | ||||
| 			Debug.Assert(strX != null); | ||||
| @@ -771,39 +771,31 @@ namespace KeePassLib.Utility | ||||
| 			if(NativeMethods.SupportsStrCmpNaturally) | ||||
| 				return NativeMethods.StrCmpNaturally(strX, strY); | ||||
|  | ||||
| 			strX = strX.ToLower(); // Case-insensitive comparison | ||||
| 			strY = strY.ToLower(); | ||||
| 			if(g_rxNaturalSplit == null) | ||||
| 				g_rxNaturalSplit = new Regex(@"([0-9]+)", RegexOptions.Compiled); | ||||
|  | ||||
| 			if(m_rxNaturalSplit == null) | ||||
| 				m_rxNaturalSplit = new Regex(@"([0-9]+)", | ||||
| #if KeePassRT | ||||
| 					RegexOptions.None); | ||||
| #else | ||||
| 					RegexOptions.Compiled); | ||||
| #endif | ||||
| 			string[] vPartsX = g_rxNaturalSplit.Split(strX); | ||||
| 			string[] vPartsY = g_rxNaturalSplit.Split(strY); | ||||
|  | ||||
| 			string[] vPartsX = m_rxNaturalSplit.Split(strX); | ||||
| 			string[] vPartsY = m_rxNaturalSplit.Split(strY); | ||||
|  | ||||
| 			for(int i = 0; i < Math.Min(vPartsX.Length, vPartsY.Length); ++i) | ||||
| 			int n = Math.Min(vPartsX.Length, vPartsY.Length); | ||||
| 			for(int i = 0; i < n; ++i) | ||||
| 			{ | ||||
| 				string strPartX = vPartsX[i], strPartY = vPartsY[i]; | ||||
| 				int iPartCompare; | ||||
|  | ||||
| #if KeePassLibSD | ||||
| 				ulong uX = 0, uY = 0; | ||||
| 				try | ||||
| 				{ | ||||
| 					uX = ulong.Parse(strPartX); | ||||
| 					uY = ulong.Parse(strPartY); | ||||
| 					ulong uX = ulong.Parse(strPartX); | ||||
| 					ulong uY = ulong.Parse(strPartY); | ||||
| 					iPartCompare = uX.CompareTo(uY); | ||||
| 				} | ||||
| 				catch(Exception) { iPartCompare = strPartX.CompareTo(strPartY); } | ||||
| 				catch(Exception) { iPartCompare = string.Compare(strPartX, strPartY, true); } | ||||
| #else | ||||
| 				ulong uX, uY; | ||||
| 				if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY)) | ||||
| 					iPartCompare = uX.CompareTo(uY); | ||||
| 				else iPartCompare = strPartX.CompareTo(strPartY); | ||||
| 				else iPartCompare = string.Compare(strPartX, strPartY, true); | ||||
| #endif | ||||
|  | ||||
| 				if(iPartCompare != 0) return iPartCompare; | ||||
| @@ -812,6 +804,106 @@ namespace KeePassLib.Utility | ||||
| 			if(vPartsX.Length == vPartsY.Length) return 0; | ||||
| 			if(vPartsX.Length < vPartsY.Length) return -1; | ||||
| 			return 1; | ||||
| 		} */ | ||||
|  | ||||
| 		public static int CompareNaturally(string strX, string strY) | ||||
| 		{ | ||||
| 			Debug.Assert(strX != null); | ||||
| 			if(strX == null) throw new ArgumentNullException("strX"); | ||||
| 			Debug.Assert(strY != null); | ||||
| 			if(strY == null) throw new ArgumentNullException("strY"); | ||||
|  | ||||
| 			if(NativeMethods.SupportsStrCmpNaturally) | ||||
| 				return NativeMethods.StrCmpNaturally(strX, strY); | ||||
|  | ||||
| 			int cX = strX.Length; | ||||
| 			int cY = strY.Length; | ||||
| 			if(cX == 0) return ((cY == 0) ? 0 : -1); | ||||
| 			if(cY == 0) return 1; | ||||
|  | ||||
| 			char chFirstX = strX[0]; | ||||
| 			char chFirstY = strY[0]; | ||||
| 			bool bExpNum = ((chFirstX >= '0') && (chFirstX <= '9')); | ||||
| 			bool bExpNumY = ((chFirstY >= '0') && (chFirstY <= '9')); | ||||
| 			if(bExpNum != bExpNumY) return string.Compare(strX, strY, true); | ||||
|  | ||||
| 			int pX = 0; | ||||
| 			int pY = 0; | ||||
| 			while((pX < cX) && (pY < cY)) | ||||
| 			{ | ||||
| 				Debug.Assert(((strX[pX] >= '0') && (strX[pX] <= '9')) == bExpNum); | ||||
| 				Debug.Assert(((strY[pY] >= '0') && (strY[pY] <= '9')) == bExpNum); | ||||
|  | ||||
| 				int pExclX = pX + 1; | ||||
| 				while(pExclX < cX) | ||||
| 				{ | ||||
| 					char ch = strX[pExclX]; | ||||
| 					bool bChNum = ((ch >= '0') && (ch <= '9')); | ||||
| 					if(bChNum != bExpNum) break; | ||||
| 					++pExclX; | ||||
| 				} | ||||
|  | ||||
| 				int pExclY = pY + 1; | ||||
| 				while(pExclY < cY) | ||||
| 				{ | ||||
| 					char ch = strY[pExclY]; | ||||
| 					bool bChNum = ((ch >= '0') && (ch <= '9')); | ||||
| 					if(bChNum != bExpNum) break; | ||||
| 					++pExclY; | ||||
| 				} | ||||
|  | ||||
| 				string strPartX = strX.Substring(pX, pExclX - pX); | ||||
| 				string strPartY = strY.Substring(pY, pExclY - pY); | ||||
|  | ||||
| 				bool bStrCmp = true; | ||||
| 				if(bExpNum) | ||||
| 				{ | ||||
| 					// 2^64 - 1 = 18446744073709551615 has length 20 | ||||
| 					if((strPartX.Length <= 19) && (strPartY.Length <= 19)) | ||||
| 					{ | ||||
| 						ulong uX, uY; | ||||
| 						if(ulong.TryParse(strPartX, out uX) && ulong.TryParse(strPartY, out uY)) | ||||
| 						{ | ||||
| 							if(uX < uY) return -1; | ||||
| 							if(uX > uY) return 1; | ||||
|  | ||||
| 							bStrCmp = false; | ||||
| 						} | ||||
| 						else { Debug.Assert(false); } | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						double dX, dY; | ||||
| 						if(double.TryParse(strPartX, out dX) && double.TryParse(strPartY, out dY)) | ||||
| 						{ | ||||
| 							if(dX < dY) return -1; | ||||
| 							if(dX > dY) return 1; | ||||
|  | ||||
| 							bStrCmp = false; | ||||
| 						} | ||||
| 						else { Debug.Assert(false); } | ||||
| 					} | ||||
| 				} | ||||
| 				if(bStrCmp) | ||||
| 				{ | ||||
| 					int c = string.Compare(strPartX, strPartY, true); | ||||
| 					if(c != 0) return c; | ||||
| 				} | ||||
|  | ||||
| 				bExpNum = !bExpNum; | ||||
| 				pX = pExclX; | ||||
| 				pY = pExclY; | ||||
| 			} | ||||
|  | ||||
| 			if(pX >= cX) | ||||
| 			{ | ||||
| 				Debug.Assert(pX == cX); | ||||
| 				if(pY >= cY) { Debug.Assert(pY == cY); return 0; } | ||||
| 				return -1; | ||||
| 			} | ||||
|  | ||||
| 			Debug.Assert(pY == cY); | ||||
| 			return 1; | ||||
| 		} | ||||
|  | ||||
| 		public static string RemoveAccelerator(string strMenuText) | ||||
| @@ -835,6 +927,40 @@ namespace KeePassLib.Utility | ||||
| 			return str; | ||||
| 		} | ||||
|  | ||||
| 		public static string AddAccelerator(string strMenuText, | ||||
| 			List<char> lAvailKeys) | ||||
| 		{ | ||||
| 			if(strMenuText == null) { Debug.Assert(false); return null; } | ||||
| 			if(lAvailKeys == null) { Debug.Assert(false); return strMenuText; } | ||||
|  | ||||
| 			int xa = -1, xs = 0; | ||||
| 			for(int i = 0; i < strMenuText.Length; ++i) | ||||
| 			{ | ||||
| 				char ch = strMenuText[i]; | ||||
|  | ||||
| #if KeePassLibSD | ||||
| 				char chUpper = char.ToUpper(ch); | ||||
| #else | ||||
| 				char chUpper = char.ToUpperInvariant(ch); | ||||
| #endif | ||||
| 				xa = lAvailKeys.IndexOf(chUpper); | ||||
| 				if(xa >= 0) { xs = i; break; } | ||||
|  | ||||
| #if KeePassLibSD | ||||
| 				char chLower = char.ToLower(ch); | ||||
| #else | ||||
| 				char chLower = char.ToLowerInvariant(ch); | ||||
| #endif | ||||
| 				xa = lAvailKeys.IndexOf(chLower); | ||||
| 				if(xa >= 0) { xs = i; break; } | ||||
| 			} | ||||
|  | ||||
| 			if(xa < 0) return strMenuText; | ||||
|  | ||||
| 			lAvailKeys.RemoveAt(xa); | ||||
| 			return strMenuText.Insert(xs, @"&"); | ||||
| 		} | ||||
|  | ||||
| 		public static string EncodeMenuText(string strText) | ||||
| 		{ | ||||
| 			if(strText == null) throw new ArgumentNullException("strText"); | ||||
| @@ -852,13 +978,12 @@ namespace KeePassLib.Utility | ||||
| 		public static bool IsHexString(string str, bool bStrict) | ||||
| 		{ | ||||
| 			if(str == null) throw new ArgumentNullException("str"); | ||||
| 			if(str.Length == 0) return true; | ||||
|  | ||||
| 			foreach(char ch in str) | ||||
| 			{ | ||||
| 				if((ch >= '0') && (ch <= '9')) continue; | ||||
| 				if((ch >= 'a') && (ch <= 'z')) continue; | ||||
| 				if((ch >= 'A') && (ch <= 'Z')) continue; | ||||
| 				if((ch >= 'a') && (ch <= 'f')) continue; | ||||
| 				if((ch >= 'A') && (ch <= 'F')) continue; | ||||
|  | ||||
| 				if(bStrict) return false; | ||||
|  | ||||
| @@ -871,8 +996,31 @@ namespace KeePassLib.Utility | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		public static bool IsHexString(byte[] pbUtf8, bool bStrict) | ||||
| 		{ | ||||
| 			if(pbUtf8 == null) throw new ArgumentNullException("pbUtf8"); | ||||
|  | ||||
| 			for(int i = 0; i < pbUtf8.Length; ++i) | ||||
| 			{ | ||||
| 				byte bt = pbUtf8[i]; | ||||
| 				if((bt >= (byte)'0') && (bt <= (byte)'9')) continue; | ||||
| 				if((bt >= (byte)'a') && (bt <= (byte)'f')) continue; | ||||
| 				if((bt >= (byte)'A') && (bt <= (byte)'F')) continue; | ||||
|  | ||||
| 				if(bStrict) return false; | ||||
|  | ||||
| 				if((bt == (byte)' ') || (bt == (byte)'\t') || | ||||
| 					(bt == (byte)'\r') || (bt == (byte)'\n')) | ||||
| 					continue; | ||||
|  | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 		private static readonly char[] m_vPatternPartsSep = new char[]{ '*' }; | ||||
| 		private static readonly char[] m_vPatternPartsSep = new char[] { '*' }; | ||||
| 		public static bool SimplePatternMatch(string strPattern, string strText, | ||||
| 			StringComparison sc) | ||||
| 		{ | ||||
| @@ -997,6 +1145,36 @@ namespace KeePassLib.Utility | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static string GetNewLineSeq(string str) | ||||
| 		{ | ||||
| 			if(str == null) { Debug.Assert(false); return "\n"; } | ||||
|  | ||||
| 			int n = str.Length, nLf = 0, nCr = 0, nCrLf = 0; | ||||
| 			char chLast = char.MinValue; | ||||
| 			for(int i = 0; i < n; ++i) | ||||
| 			{ | ||||
| 				char ch = str[i]; | ||||
|  | ||||
| 				if(ch == '\r') ++nCr; | ||||
| 				else if(ch == '\n') | ||||
| 				{ | ||||
| 					++nLf; | ||||
| 					if(chLast == '\r') ++nCrLf; | ||||
| 				} | ||||
|  | ||||
| 				chLast = ch; | ||||
| 			} | ||||
|  | ||||
| 			nCr -= nCrLf; | ||||
| 			nLf -= nCrLf; | ||||
|  | ||||
| 			int nMax = Math.Max(nCrLf, Math.Max(nCr, nLf)); | ||||
| 			if(nMax == 0) return "\n"; | ||||
|  | ||||
| 			if(nCrLf == nMax) return "\r\n"; | ||||
| 			return ((nLf == nMax) ? "\n" : "\r"); | ||||
| 		} | ||||
|  | ||||
| 		public static string AlphaNumericOnly(string str) | ||||
| 		{ | ||||
| 			if(string.IsNullOrEmpty(str)) return str; | ||||
| @@ -1074,37 +1252,44 @@ namespace KeePassLib.Utility | ||||
|  | ||||
| 		public static string VersionToString(ulong uVersion) | ||||
| 		{ | ||||
| 			return VersionToString(uVersion, false); | ||||
| 			return VersionToString(uVersion, 1U); | ||||
| 		} | ||||
|  | ||||
| 		[Obsolete] | ||||
| 		public static string VersionToString(ulong uVersion, | ||||
| 			bool bEnsureAtLeastTwoComp) | ||||
| 		{ | ||||
| 			string str = string.Empty; | ||||
| 			bool bMultiComp = false; | ||||
| 			return VersionToString(uVersion, (bEnsureAtLeastTwoComp ? 2U : 1U)); | ||||
| 		} | ||||
|  | ||||
| 		public static string VersionToString(ulong uVersion, uint uMinComp) | ||||
| 		{ | ||||
| 			StringBuilder sb = new StringBuilder(); | ||||
| 			uint uComp = 0; | ||||
|  | ||||
| 			for(int i = 0; i < 4; ++i) | ||||
| 			{ | ||||
| 				ushort us = (ushort)(uVersion & 0xFFFFUL); | ||||
| 				if(uVersion == 0UL) break; | ||||
|  | ||||
| 				if((us != 0) || (str.Length > 0)) | ||||
| 				{ | ||||
| 					if(str.Length > 0) | ||||
| 					{ | ||||
| 						str = "." + str; | ||||
| 						bMultiComp = true; | ||||
| 					} | ||||
| 				ushort us = (ushort)(uVersion >> 48); | ||||
|  | ||||
| 					str = us.ToString(NumberFormatInfo.InvariantInfo) + str; | ||||
| 				} | ||||
| 				if(sb.Length > 0) sb.Append('.'); | ||||
|  | ||||
| 				uVersion >>= 16; | ||||
| 				sb.Append(us.ToString(NumberFormatInfo.InvariantInfo)); | ||||
| 				++uComp; | ||||
|  | ||||
| 				uVersion <<= 16; | ||||
| 			} | ||||
|  | ||||
| 			if(bEnsureAtLeastTwoComp && !bMultiComp && (str.Length > 0)) | ||||
| 				str += ".0"; | ||||
| 			while(uComp < uMinComp) | ||||
| 			{ | ||||
| 				if(sb.Length > 0) sb.Append('.'); | ||||
|  | ||||
| 			return str; | ||||
| 				sb.Append('0'); | ||||
| 				++uComp; | ||||
| 			} | ||||
|  | ||||
| 			return sb.ToString(); | ||||
| 		} | ||||
|  | ||||
| 		private static readonly byte[] m_pbOptEnt = { 0xA5, 0x74, 0x2E, 0xEC }; | ||||
| @@ -1169,7 +1354,7 @@ namespace KeePassLib.Utility | ||||
| 			return v; | ||||
| 		} | ||||
|  | ||||
| 		private static readonly char[] m_vTagSep = new char[]{ ',', ';', ':' }; | ||||
| 		private static readonly char[] m_vTagSep = new char[] { ',', ';', ':' }; | ||||
| 		public static string TagsToString(List<string> vTags, bool bForDisplay) | ||||
| 		{ | ||||
| 			if(vTags == null) throw new ArgumentNullException("vTags"); | ||||
| @@ -1222,7 +1407,7 @@ namespace KeePassLib.Utility | ||||
| 			Array.Reverse(pb); | ||||
| 			for(int i = 0; i < pb.Length; ++i) pb[i] = (byte)(pb[i] ^ 0x65); | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			return Convert.ToBase64String(pb, Base64FormattingOptions.None); | ||||
| #else | ||||
| 			return Convert.ToBase64String(pb); | ||||
| @@ -1382,7 +1567,7 @@ namespace KeePassLib.Utility | ||||
|  | ||||
| 			if(strMimeType == null) strMimeType = "application/octet-stream"; | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			return ("data:" + strMimeType + ";base64," + Convert.ToBase64String( | ||||
| 				pbData, Base64FormattingOptions.None)); | ||||
| #else | ||||
| @@ -1412,12 +1597,7 @@ namespace KeePassLib.Utility | ||||
| 			if(bBase64) return Convert.FromBase64String(strData); | ||||
|  | ||||
| 			MemoryStream ms = new MemoryStream(); | ||||
|  | ||||
| #if KeePassRT | ||||
| 			Encoding enc = StrUtil.Utf8; | ||||
| #else | ||||
| 			Encoding enc = Encoding.ASCII; | ||||
| #endif | ||||
|  | ||||
| 			string[] v = strData.Split('%'); | ||||
| 			byte[] pb = enc.GetBytes(v[0]); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -18,7 +18,10 @@ | ||||
| */ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Diagnostics; | ||||
| using System.Globalization; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Interfaces; | ||||
|  | ||||
| @@ -35,9 +38,29 @@ namespace KeePassLib.Utility | ||||
| 		/// </summary> | ||||
| 		public const int PwTimeLength = 7; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 		private static string m_strDtfStd = null; | ||||
| 		private static string m_strDtfDate = null; | ||||
| #endif | ||||
| 		/// <summary> | ||||
| 		private static DateTime? m_odtUnixRoot = null; | ||||
| 		public static DateTime UnixRoot | ||||
| 		{ | ||||
| 			get | ||||
| 			{ | ||||
| 				if(m_odtUnixRoot.HasValue) return m_odtUnixRoot.Value; | ||||
| 		/// Pack a <c>DateTime</c> object into 5 bytes. Layout: 2 zero bits, | ||||
| 				DateTime dtRoot = (new DateTime(1970, 1, 1, 0, 0, 0, 0, | ||||
| 					DateTimeKind.Utc)).ToLocalTime(); | ||||
| 		/// year 12 bits, month 4 bits, day 5 bits, hour 5 bits, minute 6 | ||||
| 				m_odtUnixRoot = dtRoot; | ||||
| 				return dtRoot; | ||||
| 			} | ||||
| 		} | ||||
| 		/// bits, second 6 bits. | ||||
| 		/// </summary> | ||||
| 		/// <param name="dt"></param> | ||||
| 		/// <returns></returns> | ||||
| 		/// bits, second 6 bits. | ||||
| 		/// </summary> | ||||
| 		/// <param name="dt"></param> | ||||
| @@ -140,17 +163,118 @@ namespace KeePassLib.Utility | ||||
| 		{ | ||||
| 			DateTime dt; | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 			if(DateTime.TryParse(strDisplay, out dt)) return dt; | ||||
| #else | ||||
| #if KeePassLibSD | ||||
| 			try { dt = DateTime.Parse(strDisplay); return dt; } | ||||
| 			catch(Exception) { } | ||||
| #else | ||||
| 			if(DateTime.TryParse(strDisplay, out dt)) return dt; | ||||
|  | ||||
| 			// For some custom formats specified using the Control Panel, | ||||
| 			// DateTime.ToString returns the correct string, but | ||||
| 			// DateTime.TryParse fails (e.g. for "//dd/MMM/yyyy"); | ||||
| 			// https://sourceforge.net/p/keepass/discussion/329221/thread/3a225b29/?limit=25&page=1#c6ae | ||||
| 			if((m_strDtfStd == null) || (m_strDtfDate == null)) | ||||
| 			{ | ||||
| 				DateTime dtUni = new DateTime(2111, 3, 4, 5, 6, 7); | ||||
| 				m_strDtfStd = DeriveCustomFormat(ToDisplayString(dtUni), dtUni); | ||||
| 				m_strDtfDate = DeriveCustomFormat(ToDisplayStringDateOnly(dtUni), dtUni); | ||||
| 			} | ||||
| 			const DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces; | ||||
| 			if(DateTime.TryParseExact(strDisplay, m_strDtfStd, null, dts, out dt)) | ||||
| 				return dt; | ||||
| 			if(DateTime.TryParseExact(strDisplay, m_strDtfDate, null, dts, out dt)) | ||||
| 				return dt; | ||||
| #endif | ||||
|  | ||||
| 			Debug.Assert(false); | ||||
| 			return DateTime.Now; | ||||
| 		} | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 		private static string DeriveCustomFormat(string strDT, DateTime dt) | ||||
| 		{ | ||||
| 			string[] vPlh = new string[] { | ||||
| 				// Names, sorted by length | ||||
| 				"MMMM", "dddd", | ||||
| 				"MMM", "ddd", | ||||
| 				"gg", "g", | ||||
|  | ||||
| 				// Numbers, the ones with prefix '0' first | ||||
| 				"yyyy", "yyy", "yy", "y", | ||||
| 				"MM", "M", | ||||
| 				"dd", "d", | ||||
| 				"HH", "hh", "H", "h", | ||||
| 				"mm", "m", | ||||
| 				"ss", "s", | ||||
|  | ||||
| 				"tt", "t" | ||||
| 			}; | ||||
|  | ||||
| 			List<string> lValues = new List<string>(); | ||||
| 			foreach(string strPlh in vPlh) | ||||
| 			{ | ||||
| 				string strEval = strPlh; | ||||
| 				if(strEval.Length == 1) strEval = @"%" + strPlh; // Make custom | ||||
|  | ||||
| 				lValues.Add(dt.ToString(strEval)); | ||||
| 			} | ||||
|  | ||||
| 			StringBuilder sbAll = new StringBuilder(); | ||||
| 			sbAll.Append("dfFghHKmMstyz:/\"\'\\%"); | ||||
| 			sbAll.Append(strDT); | ||||
| 			foreach(string strVEnum in lValues) { sbAll.Append(strVEnum); } | ||||
|  | ||||
| 			List<char> lCodes = new List<char>(); | ||||
| 			for(int i = 0; i < vPlh.Length; ++i) | ||||
| 			{ | ||||
| 				char ch = StrUtil.GetUnusedChar(sbAll.ToString()); | ||||
| 				lCodes.Add(ch); | ||||
| 				sbAll.Append(ch); | ||||
| 			} | ||||
|  | ||||
| 			string str = strDT; | ||||
| 			for(int i = 0; i < vPlh.Length; ++i) | ||||
| 			{ | ||||
| 				string strValue = lValues[i]; | ||||
| 				if(string.IsNullOrEmpty(strValue)) continue; | ||||
|  | ||||
| 				str = str.Replace(strValue, new string(lCodes[i], 1)); | ||||
| 			} | ||||
|  | ||||
| 			StringBuilder sbFmt = new StringBuilder(); | ||||
| 			bool bInLiteral = false; | ||||
| 			foreach(char ch in str) | ||||
| 			{ | ||||
| 				int iCode = lCodes.IndexOf(ch); | ||||
|  | ||||
| 				// The escape character doesn't work correctly (e.g. | ||||
| 				// "dd\\.MM\\.yyyy\\ HH\\:mm\\:ss" doesn't work, but | ||||
| 				// "dd'.'MM'.'yyyy' 'HH':'mm':'ss" does); use '' instead | ||||
|  | ||||
| 				// if(iCode >= 0) sbFmt.Append(vPlh[iCode]); | ||||
| 				// else // Literal | ||||
| 				// { | ||||
| 				//	sbFmt.Append('\\'); | ||||
| 				//	sbFmt.Append(ch); | ||||
| 				// } | ||||
|  | ||||
| 				if(iCode >= 0) | ||||
| 				{ | ||||
| 					if(bInLiteral) { sbFmt.Append('\''); bInLiteral = false; } | ||||
| 					sbFmt.Append(vPlh[iCode]); | ||||
| 				} | ||||
| 				else // Literal | ||||
| 				{ | ||||
| 					if(!bInLiteral) { sbFmt.Append('\''); bInLiteral = true; } | ||||
| 					sbFmt.Append(ch); | ||||
| 				} | ||||
| 			} | ||||
| 			if(bInLiteral) sbFmt.Append('\''); | ||||
|  | ||||
| 			return sbFmt.ToString(); | ||||
| 		} | ||||
| #endif | ||||
|  | ||||
| 		public static string SerializeUtc(DateTime dt) | ||||
| 		{ | ||||
| 			string str = dt.ToUniversalTime().ToString("s"); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* | ||||
|   KeePass Password Safe - The Open-Source Password Manager | ||||
|   Copyright (C) 2003-2013 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|   Copyright (C) 2003-2016 Dominik Reichl <dominik.reichl@t-online.de> | ||||
|  | ||||
|   This program is free software; you can redistribute it and/or modify | ||||
|   it under the terms of the GNU General Public License as published by | ||||
| @@ -19,10 +19,9 @@ | ||||
|  | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Runtime.InteropServices; | ||||
| using System.Text; | ||||
| using System.Diagnostics; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| using KeePassLib.Native; | ||||
|  | ||||
| @@ -41,17 +40,14 @@ namespace KeePassLib.Utility | ||||
|  | ||||
| 		public static char LocalDirSepChar | ||||
| 		{ | ||||
| #if KeePassRT | ||||
| 			get { return '\\'; } | ||||
| #else | ||||
| 			get { return Path.DirectorySeparatorChar; } | ||||
| #endif | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| 		/// Get the directory (path) of a file name. The returned string is | ||||
| 		/// Get the directory (path) of a file name. The returned string may be | ||||
| 		/// terminated by a directory separator character. Example: | ||||
| 		/// passing <c>C:\\My Documents\\My File.kdb</c> in <paramref name="strFile" /> | ||||
| 		/// and <c>true</c> to <paramref name="bAppendTerminatingChar"/> | ||||
| 		/// would produce this string: <c>C:\\My Documents\\</c>. | ||||
| 		/// </summary> | ||||
| 		/// <param name="strFile">Full path of a file.</param> | ||||
| @@ -62,8 +58,7 @@ namespace KeePassLib.Utility | ||||
| 		/// of <c>X:</c>, overriding <paramref name="bAppendTerminatingChar" />). | ||||
| 		/// This should only be set to <c>true</c>, if the returned path is directly | ||||
| 		/// passed to some directory API.</param> | ||||
| 		/// <returns>Directory of the file. The return value is an empty string | ||||
| 		/// (<c>""</c>) if the input parameter is <c>null</c>.</returns> | ||||
| 		/// <returns>Directory of the file.</returns> | ||||
| 		public static string GetFileDirectory(string strFile, bool bAppendTerminatingChar, | ||||
| 			bool bEnsureValidDirSpec) | ||||
| 		{ | ||||
| @@ -71,14 +66,15 @@ namespace KeePassLib.Utility | ||||
| 			if(strFile == null) throw new ArgumentNullException("strFile"); | ||||
|  | ||||
| 			int nLastSep = strFile.LastIndexOfAny(m_vDirSeps); | ||||
| 			if(nLastSep < 0) return strFile; // None | ||||
| 			if(nLastSep < 0) return string.Empty; // No directory | ||||
|  | ||||
| 			if(bEnsureValidDirSpec && (nLastSep == 2) && (strFile[1] == ':') && | ||||
| 				(strFile[2] == '\\')) // Length >= 3 and Windows root directory | ||||
| 				bAppendTerminatingChar = true; | ||||
|  | ||||
| 			if(!bAppendTerminatingChar) return strFile.Substring(0, nLastSep); | ||||
| 			return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), false); | ||||
| 			return EnsureTerminatingSeparator(strFile.Substring(0, nLastSep), | ||||
| 				(strFile[nLastSep] == '/')); | ||||
| 		} | ||||
|  | ||||
| 		/// <summary> | ||||
| @@ -317,10 +313,11 @@ namespace KeePassLib.Utility | ||||
| 					return strTargetFile; | ||||
| 			} | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			if(NativeLib.IsUnix()) | ||||
| #endif | ||||
| 			{ | ||||
|  | ||||
| 				bool bBaseUnc = IsUncPath(strBaseFile); | ||||
| 				bool bTargetUnc = IsUncPath(strTargetFile); | ||||
| 				if((!bBaseUnc && bTargetUnc) || (bBaseUnc && !bTargetUnc)) | ||||
| @@ -348,9 +345,9 @@ namespace KeePassLib.Utility | ||||
| 				} | ||||
|  | ||||
| 				return sbRel.ToString(); | ||||
| #if (!KeePassLibSD && !KeePassUAP) | ||||
| 			} | ||||
|  | ||||
| #if (!KeePassLibSD && !KeePassRT) | ||||
| 			try // Windows | ||||
| 			{ | ||||
| 				const int nMaxPath = NativeMethods.MAX_PATH * 2; | ||||
| @@ -624,7 +621,7 @@ namespace KeePassLib.Utility | ||||
| 			string strDir; | ||||
| 			if(NativeLib.IsUnix()) | ||||
| 				strDir = NativeMethods.GetUserRuntimeDir(); | ||||
| #if KeePassRT | ||||
| #if KeePassUAP | ||||
| 			else strDir = Windows.Storage.ApplicationData.Current.TemporaryFolder.Path; | ||||
| #else | ||||
| 			else strDir = Path.GetTempPath(); | ||||
| @@ -632,8 +629,7 @@ namespace KeePassLib.Utility | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				if(Directory.Exists(strDir) == false) | ||||
| 					Directory.CreateDirectory(strDir); | ||||
| 				if(!Directory.Exists(strDir)) Directory.CreateDirectory(strDir); | ||||
| 			} | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Philipp Crocoll
					Philipp Crocoll