public void TestAesKdf() { // Up to KeePass 2.34, the OtpKeyProv plugin used the public // CompositeKey.TransformKeyManaged method (and a finalizing // SHA-256 computation), which became an internal method of // the AesKdf class in KeePass 2.35, thus OtpKeyProv now // uses the AesKdf class; here we ensure that the results // are the same var r = CryptoRandom.NewWeakRandom(); var pbKey = new byte[32]; r.NextBytes(pbKey); var pbSeed = new byte[32]; r.NextBytes(pbSeed); var uRounds = (ulong)r.Next(1, 0x7FFF); var pbMan = new byte[pbKey.Length]; Array.Copy(pbKey, pbMan, pbKey.Length); Assert.True(AesKdf.TransformKeyManaged(pbMan, pbSeed, uRounds)); pbMan = CryptoUtil.HashSha256(pbMan); var kdf = new AesKdf(); var p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, uRounds); p.SetByteArray(AesKdf.ParamSeed, pbSeed); var pbKdf = kdf.Transform(pbKey, p); Assert.True(MemUtil.ArraysEqual(pbMan, pbKdf)); }
public void BasicReferenceTest() { byte[] key = new byte[32]; byte[] info = new byte[32]; var derived = new AesKdf(Common.AesFactory).GenerateBytes(key, info, 32); }
private static void TestNativeKeyTransform() { #if DEBUG byte[] pbOrgKey = CryptoRandom.Instance.GetRandomBytes(32); byte[] pbSeed = CryptoRandom.Instance.GetRandomBytes(32); ulong uRounds = (ulong)((new Random()).Next(1, 0x3FFF)); byte[] pbManaged = new byte[32]; Array.Copy(pbOrgKey, pbManaged, 32); if (!AesKdf.TransformKeyManaged(pbManaged, pbSeed, uRounds)) { throw new SecurityException("AES-KDF-1"); } byte[] pbNative = new byte[32]; Array.Copy(pbOrgKey, pbNative, 32); if (!NativeLib.TransformKey256(pbNative, pbSeed, uRounds)) { return; // Native library not available ("success") } if (!MemUtil.ArraysEqual(pbManaged, pbNative)) { throw new SecurityException("AES-KDF-2"); } #endif }
private uint GetMinKdbxVersion() { if(m_uForceVersion != 0) return m_uForceVersion; // See also KeePassKdb2x3.Export (KDBX 3.1 export module) 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 }
public void TestGenerateKey32() { var originalKey = new byte[32]; var expectedKey = new byte[] { 0xF0, 0xED, 0x57, 0xD5, 0xF0, 0xDA, 0xF3, 0x47, 0x90, 0xD0, 0xDB, 0x43, 0x25, 0xC6, 0x81, 0x2C, 0x81, 0x6A, 0x0D, 0x94, 0x96, 0xA9, 0x03, 0xE1, 0x20, 0xD4, 0x3A, 0x3E, 0x45, 0xAD, 0x02, 0x65 }; const ulong rounds = 1; var composite = new CompositeKey(); AesKdf kdf = new AesKdf(); KdfParameters p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, rounds); p.SetByteArray(AesKdf.ParamSeed, originalKey); var key = composite.GenerateKey32(p); Assert.NotNull(key); var keyData = key.ReadData(); Assert.True(MemUtil.ArraysEqual(keyData, expectedKey)); }
private uint GetMinKdbxVersion() { if (m_uForceVersion != 0) { return(m_uForceVersion); } // See also KeePassKdb2x3.Export (KDBX 3.1 export module) uint minVersionForKeys = m_pwDatabase.MasterKey.UserKeys.Select(key => key.GetMinKdbxVersion()).Max(); AesKdf kdfAes = new AesKdf(); if (!kdfAes.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) { return(Math.Max(FileVersion32, minVersionForKeys)); } if (m_pwDatabase.PublicCustomData.Count > 0) { return(Math.Max(FileVersion32, minVersionForKeys)); } 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(Math.Max(FileVersion32, minVersionForKeys)); } return(Math.Max(FileVersion32_3, minVersionForKeys));; // KDBX 3.1 is sufficient }
public void VariableLengthInfoTest(int infoLength) { byte[] key = new byte[32]; byte[] info = new byte[infoLength]; r.NextBytes(key); r.NextBytes(info); var derived = new AesKdf(Common.AesFactory).GenerateBytes(key, info, 32); }
/// <summary> /// Generates 32 bit 2nd Key based on key option selected /// </summary> /// <param name="MasterSeed">Seed used to generate the key from m_2Key</param> /// <param name="TransformSeed">Seed for key transformation</param> /// <param name="NumRounds">Iteration count of transformation</param> /// <returns></returns> public byte[] Get2ndKey32(byte[] Hash, byte[] MasterSeed, byte[] TransformSeed) { byte[] GeneratedKey = new byte[32]; byte[] HashBuffer = new byte[32 + 32 + 32]; // MasterSeed + DualKey + FirstStreamHash byte[] Key256Bits = null; byte[] pKey32 = null; try { Array.Copy(MasterSeed, 0, HashBuffer, 0, 32); KdfParameters KdfParams = new AesKdf().GetDefaultParameters(); KdfParams.SetUInt64(AesKdf.ParamRounds, Key2Transformations); KdfParams.SetByteArray(AesKdf.ParamSeed, TransformSeed); var Key2nd = Get2ndKey(); if (Key2nd == null) { throw new SecurityException("Invalid 2nd Key"); } ProtectedBinary pbinKey = Key2nd.GenerateKey32(KdfParams); if (pbinKey == null) { throw new SecurityException("Invalid Key"); } pKey32 = pbinKey.ReadData(); if ((pKey32 == null) || (pKey32.Length != 32)) { throw new SecurityException("Invalid Key Data"); } Array.Copy(pKey32, 0, HashBuffer, 32, 32); Array.Copy(Hash, 0, HashBuffer, 64, 32); SHA256Managed sha = new SHA256Managed(); Key256Bits = sha.ComputeHash(HashBuffer); Array.Copy(Key256Bits, GeneratedKey, 32); } finally { MemUtil.ZeroByteArray(HashBuffer); if (Key256Bits != null) { MemUtil.ZeroByteArray(Key256Bits); } if (pKey32 != null) { MemUtil.ZeroByteArray(pKey32); } } return(GeneratedKey); }
public void VariableLengthOutputTest(int outputLength) { byte[] key = new byte[32]; byte[] info = new byte[32]; r.NextBytes(key); r.NextBytes(info); var derived = new AesKdf(Common.AesFactory).GenerateBytes(key, info, outputLength); }
public void RandomReferenceTest(int i) { byte[] key = new byte[32]; byte[] info = new byte[32]; key[0] = (byte)i; // just to get rid of a warning r.NextBytes(key); r.NextBytes(info); var derived = new AesKdf(Common.AesFactory).GenerateBytes(key, info, 32); }
private byte[] GetKey() { byte[] ThreeDESKey = new byte[24]; MemoryStream ms = new MemoryStream(); ms.Write(m_MasterSeed, 0, 32); KdfParameters kdf = new AesKdf().GetDefaultParameters(); kdf.SetUInt64(AesKdf.ParamRounds, m_NumRounds); kdf.SetByteArray(AesKdf.ParamSeed, m_TransformSeed); ProtectedBinary pbinKey = m_2Key.GenerateKey32(kdf); if (pbinKey == null) { throw new SecurityException("Invalid Key"); } byte[] pKey32 = pbinKey.ReadData(); if ((pKey32 == null) || (pKey32.Length != 32)) { throw new SecurityException("Invalid Key Data"); } ms.Write(pKey32, 0, 32); byte[] sRandom = m_hash.Hash; ms.Write(sRandom, 0, sRandom.Length); SHA256Managed sha = new SHA256Managed(); byte[] Key256 = sha.ComputeHash(ms.ToArray()); Array.Copy(Key256, ThreeDESKey, ThreeDESKey.Length); ms.Close(); Array.Clear(pKey32, 0, 32); Array.Clear(Key256, 0, 32); return(ThreeDESKey); }
private static byte[] HashAndTransform(byte[] pbData, byte[] pbTrfKey32, ulong uTrfRounds) { SHA256Managed sha256 = new SHA256Managed(); byte[] pbHash = sha256.ComputeHash(pbData); sha256.Clear(); if (!AesKdf.TransformKeyManaged(pbHash, pbTrfKey32, uTrfRounds)) { return(null); } sha256 = new SHA256Managed(); pbHash = sha256.ComputeHash(pbHash); sha256.Clear(); return(pbHash); }
public void TestTransformKeyManaged() { var originalKey = new byte[32]; var expectedKey = new byte[32] { 0xDC, 0x95, 0xC0, 0x78, 0xA2, 0x40, 0x89, 0x89, 0xAD, 0x48, 0xA2, 0x14, 0x92, 0x84, 0x20, 0x87, 0xDC, 0x95, 0xC0, 0x78, 0xA2, 0x40, 0x89, 0x89, 0xAD, 0x48, 0xA2, 0x14, 0x92, 0x84, 0x20, 0x87 }; var seed = new byte[32]; const ulong rounds = 1; var managedKey = (byte[])originalKey.Clone(); var success = AesKdf.TransformKeyManaged(managedKey, seed, rounds); Assert.That(success, Is.True); Assert.That(managedKey, Is.EqualTo(expectedKey)); }
public ProtectedBinary GenerateKey32(byte[] pbKeySeed32, ulong uNumRounds) { Debug.Assert(pbKeySeed32 != null); if (pbKeySeed32 == null) { throw new ArgumentNullException("pbKeySeed32"); } Debug.Assert(pbKeySeed32.Length == 32); if (pbKeySeed32.Length != 32) { throw new ArgumentException("pbKeySeed32"); } AesKdf kdf = new AesKdf(); KdfParameters p = kdf.GetDefaultParameters(); p.SetUInt64(AesKdf.ParamRounds, uNumRounds); p.SetByteArray(AesKdf.ParamSeed, pbKeySeed32); return(GenerateKey32(p)); }
public override bool Export(PwExportInfo pwExportInfo, Stream sOutput, IStatusLogger slLogger) { PwDatabase pd = pwExportInfo.ContextDatabase; PwGroup pgRoot = pwExportInfo.DataGroup; // Remove everything that requires KDBX 4 or higher; // see also KdbxFile.GetMinKdbxVersion PwUuid puCipher = pd.DataCipherUuid; if (puCipher.Equals(ChaCha20Engine.ChaCha20Uuid)) { pd.DataCipherUuid = StandardAesEngine.AesUuid; } KdfParameters pKdf = pd.KdfParameters; AesKdf kdfAes = new AesKdf(); if (!pKdf.KdfUuid.Equals(kdfAes.Uuid)) { pd.KdfParameters = kdfAes.GetDefaultParameters(); } VariantDictionary vdPublic = pd.PublicCustomData; pd.PublicCustomData = new VariantDictionary(); List <PwGroup> lCustomGK = new List <PwGroup>(); List <StringDictionaryEx> lCustomGV = new List <StringDictionaryEx>(); List <PwEntry> lCustomEK = new List <PwEntry>(); List <StringDictionaryEx> lCustomEV = new List <StringDictionaryEx>(); GroupHandler gh = delegate(PwGroup pg) { if (pg == null) { Debug.Assert(false); return(true); } if (pg.CustomData.Count > 0) { lCustomGK.Add(pg); lCustomGV.Add(pg.CustomData); pg.CustomData = new StringDictionaryEx(); } return(true); }; EntryHandler eh = delegate(PwEntry pe) { if (pe == null) { Debug.Assert(false); return(true); } if (pe.CustomData.Count > 0) { lCustomEK.Add(pe); lCustomEV.Add(pe.CustomData); pe.CustomData = new StringDictionaryEx(); } return(true); }; gh(pgRoot); pgRoot.TraverseTree(TraversalMethod.PreOrder, gh, eh); try { KdbxFile kdbx = new KdbxFile(pd); kdbx.ForceVersion = KdbxFile.FileVersion32_3_1; kdbx.Save(sOutput, pgRoot, KdbxFormat.Default, slLogger); } finally { // Restore pd.DataCipherUuid = puCipher; pd.KdfParameters = pKdf; pd.PublicCustomData = vdPublic; for (int i = 0; i < lCustomGK.Count; ++i) { lCustomGK[i].CustomData = lCustomGV[i]; } for (int i = 0; i < lCustomEK.Count; ++i) { lCustomEK[i].CustomData = lCustomEV[i]; } } return(true); }
private bool ReadHeaderField(BinaryReaderEx brSource) { Debug.Assert(brSource != null); if (brSource == null) { throw new ArgumentNullException("brSource"); } byte btFieldID = brSource.ReadByte(); int cbSize; Debug.Assert(m_uFileVersion > 0); if (m_uFileVersion < FileVersion32_4) { 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) { pbData = brSource.ReadBytes(cbSize); } bool bResult = true; KdbxHeaderFieldID kdbID = (KdbxHeaderFieldID)btFieldID; switch (kdbID) { case KdbxHeaderFieldID.EndOfHeader: bResult = false; // Returning false indicates end of header break; case KdbxHeaderFieldID.CipherID: SetCipher(pbData); break; case KdbxHeaderFieldID.CompressionFlags: SetCompressionFlags(pbData); break; case KdbxHeaderFieldID.MasterSeed: m_pbMasterSeed = pbData; CryptoRandom.Instance.AddEntropy(pbData); break; // Obsolete; for backward compatibility only case KdbxHeaderFieldID.TransformSeed: Debug.Assert(m_uFileVersion < FileVersion32_4); 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: Debug.Assert(m_uFileVersion < FileVersion32_4); 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: m_pbEncryptionIV = pbData; break; case KdbxHeaderFieldID.InnerRandomStreamKey: Debug.Assert(m_uFileVersion < FileVersion32_4); Debug.Assert(m_pbInnerRandomStreamKey == null); m_pbInnerRandomStreamKey = pbData; CryptoRandom.Instance.AddEntropy(pbData); break; case KdbxHeaderFieldID.StreamStartBytes: Debug.Assert(m_uFileVersion < FileVersion32_4); m_pbStreamStartBytes = pbData; break; case KdbxHeaderFieldID.InnerRandomStreamID: Debug.Assert(m_uFileVersion < FileVersion32_4); 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) { m_slLogger.SetText(KLRes.UnknownHeaderId + ": " + kdbID.ToString() + "!", LogStatusType.Warning); } break; } return(bResult); }
private uint GetMinKdbxVersion() { if (m_uForceVersion != 0) { return(m_uForceVersion); } // See also KeePassKdb2x3.Export (KDBX 3.1 export module) uint uMin = 0; GroupHandler gh = delegate(PwGroup pg) { if (pg == null) { Debug.Assert(false); return(true); } if (pg.Tags.Count != 0) { uMin = Math.Max(uMin, FileVersion32_4_1); } if (pg.CustomData.Count != 0) { uMin = Math.Max(uMin, FileVersion32_4); } return(true); }; EntryHandler eh = delegate(PwEntry pe) { if (pe == null) { Debug.Assert(false); return(true); } if (!pe.QualityCheck) { uMin = Math.Max(uMin, FileVersion32_4_1); } if (pe.CustomData.Count != 0) { uMin = Math.Max(uMin, FileVersion32_4); } return(true); }; gh(m_pwDatabase.RootGroup); m_pwDatabase.RootGroup.TraverseTree(TraversalMethod.PreOrder, gh, eh); if (uMin >= FileVersion32_4_1) { return(uMin); // All below is <= 4.1 } foreach (PwCustomIcon ci in m_pwDatabase.CustomIcons) { if ((ci.Name.Length != 0) || ci.LastModificationTime.HasValue) { return(FileVersion32_4_1); } } foreach (KeyValuePair <string, string> kvp in m_pwDatabase.CustomData) { DateTime?odt = m_pwDatabase.CustomData.GetLastModificationTime(kvp.Key); if (odt.HasValue) { return(FileVersion32_4_1); } } if (uMin >= FileVersion32_4) { return(uMin); // All below is <= 4 } if (m_pwDatabase.DataCipherUuid.Equals(ChaCha20Engine.ChaCha20Uuid)) { return(FileVersion32_4); } AesKdf kdfAes = new AesKdf(); if (!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfAes.Uuid)) { return(FileVersion32_4); } if (m_pwDatabase.PublicCustomData.Count != 0) { return(FileVersion32_4); } return(FileVersion32_3_1); // KDBX 3.1 is sufficient }
public void ReferenceTest(byte[] key, byte[] info, byte[] expected) { var output = new AesKdf(Common.AesFactory).GenerateBytes(key, info, expected.Length); Assert.Equal(expected, output); }
public void Save(PwDatabase kpDatabase, Stream stream) { PwDatabaseV3 db = new PwDatabaseV3(); KcpPassword pwd = kpDatabase.MasterKey.GetUserKey <KcpPassword>(); string password = pwd != null?pwd.Password.ReadString() : ""; KcpKeyFile keyfile = kpDatabase.MasterKey.GetUserKey <KcpKeyFile>(); Stream keyfileContents = null; if (keyfile != null) { keyfileContents = new MemoryStream(keyfile.RawFileData.ReadData()); } db.SetMasterKey(password, keyfileContents); AesKdf kdf = new AesKdf(); if (!kdf.Uuid.Equals(kpDatabase.KdfParameters.KdfUuid)) { db.NumRounds = (uint)PwDefs.DefaultKeyEncryptionRounds; } else { ulong uRounds = kpDatabase.KdfParameters.GetUInt64( AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds); uRounds = Math.Min(uRounds, 0xFFFFFFFEUL); db.NumRounds = (uint)uRounds; } db.Name = kpDatabase.Name; if (kpDatabase.DataCipherUuid.Equals(StandardAesEngine.AesUuid)) { db.Algorithm = PwEncryptionAlgorithm.Rjindal; } else { db.Algorithm = PwEncryptionAlgorithm.Twofish; } //create groups db.Groups.Clear(); var fromGroups = kpDatabase.RootGroup.GetGroups(true); Dictionary <int, PwGroupV3> groupV3s = new Dictionary <int, PwGroupV3>(fromGroups.Count()); foreach (PwGroup g in fromGroups) { if (g == kpDatabase.RootGroup) { continue; } PwGroupV3 groupV3 = ConvertGroup(g, db); db.Groups.Add(groupV3); groupV3s[groupV3.Id.Id] = groupV3; } //traverse again and assign parents db.RootGroup = ConvertGroup(kpDatabase.RootGroup, db); db.RootGroup.Level = -1; AssignParent(kpDatabase.RootGroup, db, groupV3s); foreach (PwEntry e in kpDatabase.RootGroup.GetEntries(true)) { PwEntryV3 entryV3 = ConvertEntry(e, db); entryV3.Parent = groupV3s[_groupData[e.ParentGroup.Uuid].Id]; entryV3.Parent.ChildEntries.Add(entryV3); entryV3.GroupId = entryV3.Parent.Id.Id; db.Entries.Add(entryV3); } //add meta stream entries: if (db.Groups.Any()) { foreach (var metaEntry in _metaStreams) { metaEntry.GroupId = db.Groups.First().Id.Id; db.Entries.Add(metaEntry); } } HashingStreamEx hashedStream = new HashingStreamEx(stream, true, null); PwDbV3Output output = new PwDbV3Output(db, hashedStream); output.Output(); hashedStream.Close(); HashOfLastStream = hashedStream.Hash; kpDatabase.HashOfLastIO = kpDatabase.HashOfFileOnDisk = HashOfLastStream; stream.Close(); }
private uint GetMinKdbxVersion() { if (m_uForceVersion != 0) { return(m_uForceVersion); } // See also KeePassKdb2x3.Export (KDBX 3.1 export module) foreach (KeyValuePair <string, string> kvp in m_pwDatabase.CustomData) { DateTime?odt = m_pwDatabase.CustomData.GetLastModificationTime(kvp.Key); if (odt.HasValue) { return(FileVersion32_4_1); } } if (m_pwDatabase.DataCipherUuid.Equals(ChaCha20Engine.ChaCha20Uuid)) { return(FileVersion32_4); } AesKdf kdfAes = new AesKdf(); if (!m_pwDatabase.KdfParameters.KdfUuid.Equals(kdfAes.Uuid)) { return(FileVersion32_4); } if (m_pwDatabase.PublicCustomData.Count > 0) { return(FileVersion32_4); } 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_4); } return(FileVersion32_3_1); // KDBX 3.1 is sufficient }
static void Main(string[] args) { int messageCount = 1000000; double clientDropChance = 0.0; double serverDropChance = 0.0; var defaultServices = new BouncyCastleServices(KeyGeneration.GeneratePrivateKey()); Random r = new Random(); RandomNumberGenerator rng = new RandomNumberGenerator(); Stopwatch sw = new Stopwatch(); Console.WriteLine("Generating data..."); byte[] keys = new byte[16 * 1000000]; byte[] blocks = new byte[16 * 1000000]; byte[] output = new byte[32 * 1000000]; rng.Generate(keys); rng.Generate(blocks); Thread.Sleep(1000); { var poly = new Poly(defaultServices.AesFactory); poly.Init(new ArraySegment <byte>(keys, 0, 32), new ArraySegment <byte>(blocks, 0, 16), 16); poly.Init(new ArraySegment <byte>(keys, 1000, 32), new ArraySegment <byte>(blocks, 1000, 16), 16); Console.WriteLine("Doing Pol1305 MACs"); sw.Reset(); sw.Start(); for (int i = 0; i < keys.Length; i += 32) { poly.Process(blocks, i, 16); poly.Process(blocks, i, 16); poly.Process(blocks, i, 16); poly.Process(blocks, i, 16); poly.Compute(new ArraySegment <byte>(output, i, 16)); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 32) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var sha = System.Security.Cryptography.SHA256.Create(); sha.ComputeHash(blocks, 10000, 16); Console.WriteLine("Doing SHA256 hashes (dotnet)"); sw.Reset(); sw.Start(); for (int i = 0; i < blocks.Length; i += 16) { sha.ComputeHash(blocks, i, 16); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var sha = new Org.BouncyCastle.Crypto.Digests.Sha256Digest(); sha.BlockUpdate(blocks, 10000, 16); sha.DoFinal(output, 10000); Console.WriteLine("Doing SHA256 hashes (bc)"); sw.Reset(); sw.Start(); for (int i = 0; i < blocks.Length; i += 16) { sha.BlockUpdate(blocks, i, 16); sha.DoFinal(output, i * 2); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var aes = System.Security.Cryptography.Aes.Create(); aes.Mode = System.Security.Cryptography.CipherMode.ECB; var key = new byte[16]; Array.Copy(keys, 10000, key, 0, 16); aes.CreateEncryptor(key, null); Console.WriteLine("Calculating AES keys (dotnet)"); sw.Reset(); sw.Start(); for (int i = 0; i < keys.Length; i += 16) { Array.Copy(keys, i, key, 0, 16); aes.CreateEncryptor(key, null); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var aes = System.Security.Cryptography.Aes.Create(); aes.Mode = System.Security.Cryptography.CipherMode.ECB; var key = new byte[16]; Array.Copy(keys, key, 16); var enc = aes.CreateEncryptor(key, null); enc.TransformBlock(blocks, 10000, 16, output, 10000); Console.WriteLine("Processing AES blocks (dotnet"); sw.Reset(); sw.Start(); for (int i = 0; i < blocks.Length; i += 16) { enc.TransformBlock(blocks, i, 16, output, i); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { Org.BouncyCastle.Crypto.Engines.AesEngine aes = new Org.BouncyCastle.Crypto.Engines.AesEngine(); aes.Init(true, new KeyParameter(keys, 10000, 16)); aes.Init(true, new KeyParameter(keys, 20000, 16)); Console.WriteLine("Calculating AES keys (bc)"); sw.Reset(); sw.Start(); for (int i = 0; i < keys.Length; i += 16) { aes.Init(true, new KeyParameter(keys, i, 16)); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { Org.BouncyCastle.Crypto.Engines.AesEngine aes = new Org.BouncyCastle.Crypto.Engines.AesEngine(); aes.Init(true, new KeyParameter(keys, 12300, 16)); aes.ProcessBlock(blocks, 10000, output, 10000); Console.WriteLine("Processing AES blocks (bc)"); sw.Reset(); sw.Start(); for (int i = 0; i < blocks.Length; i += 16) { aes.ProcessBlock(blocks, i, output, i); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var aes = new Org.BouncyCastle.Crypto.Engines.AesLightEngine(); aes.Init(true, new KeyParameter(keys, 10000, 16)); aes.Init(true, new KeyParameter(keys, 20000, 16)); Console.WriteLine("Calculating AES keys (bc light)"); sw.Reset(); sw.Start(); for (int i = 0; i < keys.Length; i += 16) { aes.Init(true, new KeyParameter(keys, i, 16)); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { var aes = new Org.BouncyCastle.Crypto.Engines.AesLightEngine(); aes.Init(true, new KeyParameter(keys, 12340, 16)); aes.ProcessBlock(blocks, 10000, output, 10000); Console.WriteLine("Processing AES blocks (bc light)"); sw.Reset(); sw.Start(); for (int i = 0; i < blocks.Length; i += 16) { aes.ProcessBlock(blocks, i, output, i); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(keys.Length / 16) / sw.Elapsed.TotalSeconds:F0}/s)"); } Thread.Sleep(1000); { SymmetricRacthet sr = new SymmetricRacthet(); var(client, server) = CreateAndInitialize(); var kdf = new AesKdf(client.Services.AesFactory); sr.Initialize(rng.Generate(32)); Console.WriteLine("Testing Symmetric Ratchet Speed"); sr.RatchetForSending(kdf); sr.RatchetForSending(kdf); sr.RatchetForSending(kdf); sr.RatchetForSending(kdf); sw.Reset(); sw.Start(); int cnt = 1000000; for (int i = 0; i < cnt; i++) { sr.RatchetForSending(kdf); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({cnt / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"It would take { (double)int.MaxValue / 2 / (cnt / sw.Elapsed.TotalSeconds) / 60:F0} minutes to do 2^32 ratchets"); } Thread.Sleep(1000); { Console.WriteLine("Testing one way message send speed (small: 16 bytes)..."); var(client, server) = CreateAndInitialize(); var messagesToSend = Enumerable.Range(0, messageCount).Select(_ => rng.Generate(16)).ToArray(); var messagesSent = new List <byte[]>(messageCount); var m1 = client.Send(new byte[16]); var m2 = client.Send(new byte[16]); var m3 = client.Send(new byte[16]); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { messagesSent.Add(client.Send(messagesToSend[i])); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); Thread.Sleep(1000); Console.WriteLine("Testing one way message receive speed (small: 16 bytes)..."); server.Receive(m1); server.Receive(m2); server.Receive(m3); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { server.Receive(messagesSent[i]); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); } Thread.Sleep(2000); { Console.WriteLine("Testing one way message send speed (large: 64 bytes)..."); var(client, server) = CreateAndInitialize(); var messagesToSend = Enumerable.Range(0, messageCount).Select(_ => rng.Generate(64)).ToArray(); var messagesSent = new List <byte[]>(messageCount); var m1 = client.Send(new byte[16]); var m2 = client.Send(new byte[16]); var m3 = client.Send(new byte[16]); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { messagesSent.Add(client.Send(messagesToSend[i])); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); Thread.Sleep(1000); Console.WriteLine("Testing one way message receive speed (large: 64 bytes)..."); server.Receive(m1); server.Receive(m2); server.Receive(m3); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { server.Receive(messagesSent[i]); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); } messageCount /= 10; Thread.Sleep(2000); { Console.WriteLine("Testing one way message send speed (IP: 1350 bytes)..."); var(client, server) = CreateAndInitialize(1350); var messagesToSend = Enumerable.Range(0, messageCount).Select(_ => rng.Generate(1300)).ToArray(); var messagesSent = new List <byte[]>(messageCount); var m1 = client.Send(new byte[16]); var m2 = client.Send(new byte[16]); var m3 = client.Send(new byte[16]); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { messagesSent.Add(client.Send(messagesToSend[i])); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); Thread.Sleep(1000); Console.WriteLine("Testing one way message receive speed (IP: 1350 bytes)..."); server.Receive(m1); server.Receive(m2); server.Receive(m3); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount; i++) { server.Receive(messagesSent[i]); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({messageCount / sw.Elapsed.TotalSeconds:F0}/s)"); Console.WriteLine($"Bandwidth: { messagesToSend.Sum(x => x.Length * 8) / sw.Elapsed.TotalSeconds / (1024 * 1024):F0} Mbps"); } Thread.Sleep(1000); { Console.WriteLine("Testing ECDHratchet speed..."); var(client, server) = CreateAndInitialize(1350); var messagesToSend = Enumerable.Range(0, messageCount / 4000).Select(_ => rng.Generate(32)).ToArray(); server.Receive(client.Send(new byte[32])); client.Receive(server.Send(new byte[32])); sw.Reset(); sw.Start(); for (int i = 0; i < messageCount / 4000; i++) { var m1 = client.Send(messagesToSend[i]); server.Receive(m1); var m2 = server.Send(messagesToSend[i]); client.Receive(m2); } sw.Stop(); Console.WriteLine($"Took {sw.Elapsed.TotalSeconds:F2}s ({(messageCount / 2000) / sw.Elapsed.TotalSeconds:F0}/s)"); } messageCount *= 10; Thread.Sleep(1000); { var(client, server) = CreateAndInitialize(); var clientMessages = new HashSet <byte[]>(Enumerable.Range(0, messageCount).Select(_ => rng.Generate(32))); var serverMessages = new HashSet <byte[]>(Enumerable.Range(0, messageCount).Select(_ => rng.Generate(32))); Queue <byte[]> clientMessagesToSend = new Queue <byte[]>(clientMessages); Queue <byte[]> serverMessagesToSend = new Queue <byte[]>(serverMessages); var messagesSentFromClient = new Queue <byte[]>(); var messagesSentFromServer = new Queue <byte[]>(); HashSet <byte[]> messagesReceivedByClient = new HashSet <byte[]>(); HashSet <byte[]> messagesReceivedByServer = new HashSet <byte[]>(); byte[] DoubleInSize(byte[] payload) => payload.Concat(payload).ToArray(); int clientSent = 0, serverSent = 0, clientReceived = 0, serverReceived = 0, clientDropped = 0, serverDropped = 0; Console.WriteLine($"Sending {messageCount}/{clientDropChance:P0} and {messageCount}/{serverDropChance:P0}"); sw.Reset(); sw.Start(); double oldTime = 0; int oldCnt = 0; for (int i = 0; ; i++) { bool anyMessagesToReceive = messagesSentFromClient.TryPeek(out var _) || messagesSentFromServer.TryPeek(out var _); bool anyMessagesToSend = clientMessagesToSend.TryPeek(out var _) || serverMessagesToSend.TryPeek(out var _); if (!anyMessagesToReceive && !anyMessagesToSend) { break; } if (i % 1000 == 0) { var totalReceived = clientReceived + serverReceived + clientDropped + serverDropped; var totalAll = messageCount + messageCount; var percentage = (double)totalReceived / totalAll; var newTime = sw.Elapsed.TotalSeconds; var deltaTime = newTime - oldTime; var deltaCnt = totalReceived - oldCnt; double perSecond = 0; if (oldTime != 0) { perSecond = deltaCnt / deltaTime; } Console.Write($"\r{percentage:P0} - c: {clientSent}/{clientDropped} -> {serverReceived} s: {serverSent}/{serverDropped} -> {clientReceived} ({perSecond:F0}/s) "); oldCnt = totalReceived; oldTime = newTime; } var clientOrServer = r.Next(2); var sendOrReceive = r.Next(2); double ratio = (double)messageCount / messageCount; int maxClient = 100; int maxServer = (int)(100 / ratio); var maxMessages = r.Next(clientOrServer == 0 ? maxClient : maxServer) + 1; if (anyMessagesToSend && (sendOrReceive == 0 || !anyMessagesToReceive)) { if (clientOrServer == 0) // send from client { while (maxMessages-- > 0) { clientMessagesToSend.TryDequeue(out var payload); if (payload != null) { payload = r.Next(10) > 7 ? DoubleInSize(payload) : payload; var message = client.Send(payload); if (r.NextDouble() > clientDropChance) { clientSent++; messagesSentFromClient.Enqueue(message); } else { clientDropped++; } } } } else { while (maxMessages-- > 0) { serverMessagesToSend.TryDequeue(out var payload); if (payload != null) { payload = r.Next(10) > 7 ? DoubleInSize(payload) : payload; var message = server.Send(payload); if (r.NextDouble() > serverDropChance) { serverSent++; messagesSentFromServer.Enqueue(message); } else { serverDropped++; } } } } } else { if (clientOrServer != 0) // receive by client { while (maxMessages-- > 0) { messagesSentFromServer.TryDequeue(out var message); if (message != null) { var payload = client.Receive(message).Payload; messagesReceivedByClient.Add(payload); clientReceived++; } } } else // receive by server { while (maxMessages-- > 0) { messagesSentFromClient.TryDequeue(out var message); if (message != null) { var payload = server.Receive(message).Payload; messagesReceivedByServer.Add(payload); serverReceived++; } } } } } Console.WriteLine("Done"); } }
/// <summary> /// Save the contents of the current <c>PwDatabase</c> to a KDB file. /// </summary> /// <param name="strSaveToFile">Location to save the KDB file to.</param> public void Save(string strSaveToFile, PwGroup pgDataSource) { Debug.Assert(strSaveToFile != null); if (strSaveToFile == null) { throw new ArgumentNullException("strSaveToFile"); } using (KdbManager mgr = new KdbManager()) { KdbErrorCode e = KdbFile.SetDatabaseKey(mgr, m_pwDatabase.MasterKey); if (e != KdbErrorCode.Success) { Debug.Assert(false); throw new Exception(KLRes.InvalidCompositeKey); } if (m_slLogger != null) { if (m_pwDatabase.MasterKey.ContainsType(typeof(KcpUserAccount))) { m_slLogger.SetText(KPRes.KdbWUA, LogStatusType.Warning); } if (m_pwDatabase.Name.Length != 0) { m_slLogger.SetText(KdbPrefix + KPRes.FormatNoDatabaseName, LogStatusType.Warning); } if (m_pwDatabase.Description.Length != 0) { m_slLogger.SetText(KdbPrefix + KPRes.FormatNoDatabaseDesc, LogStatusType.Warning); } } // Set properties AesKdf kdf = new AesKdf(); if (!kdf.Uuid.Equals(m_pwDatabase.KdfParameters.KdfUuid)) { mgr.KeyTransformationRounds = (uint)PwDefs.DefaultKeyEncryptionRounds; } else { ulong uRounds = m_pwDatabase.KdfParameters.GetUInt64( AesKdf.ParamRounds, PwDefs.DefaultKeyEncryptionRounds); uRounds = Math.Min(uRounds, 0xFFFFFFFEUL); mgr.KeyTransformationRounds = (uint)uRounds; } PwGroup pgRoot = (pgDataSource ?? m_pwDatabase.RootGroup); // Write groups and entries Dictionary <PwGroup, UInt32> dictGroups = WriteGroups(mgr, pgRoot); WriteEntries(mgr, dictGroups, pgRoot); e = mgr.SaveDatabase(strSaveToFile); if (e != KdbErrorCode.Success) { throw new Exception(KLRes.FileSaveFailed); } } }