diff --git a/ModernKeePass/Common/DatabaseHelper.cs b/ModernKeePass/Common/DatabaseHelper.cs index fe6a42d..afa5d44 100644 --- a/ModernKeePass/Common/DatabaseHelper.cs +++ b/ModernKeePass/Common/DatabaseHelper.cs @@ -4,6 +4,7 @@ using Windows.UI.Xaml.Controls; using ModernKeePass.ViewModels; using ModernKeePassLib; using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Cryptography.KeyDerivation; using ModernKeePassLib.Interfaces; using ModernKeePassLib.Keys; using ModernKeePassLib.Serialization; @@ -118,7 +119,8 @@ namespace ModernKeePass.Common /// public void Save() { - if (_pwDatabase == null || !_pwDatabase.IsOpen) return; + // TODO: Save is disabled for now for Argon2Kdf because it corrupts DB (read works) + if (_pwDatabase == null || !_pwDatabase.IsOpen /*|| KdfPool.Get(_pwDatabase.KdfParameters.KdfUuid) is Argon2Kdf*/) return; _pwDatabase.Save(new NullStatusLogger()); } diff --git a/ModernKeePass/ModernKeePass.csproj b/ModernKeePass/ModernKeePass.csproj index c2833aa..d416f66 100644 --- a/ModernKeePass/ModernKeePass.csproj +++ b/ModernKeePass/ModernKeePass.csproj @@ -352,7 +352,6 @@ ModernKeePassLib - 12.0 diff --git a/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs b/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs new file mode 100644 index 0000000..433aab5 --- /dev/null +++ b/ModernKeePassLib.Test/Cryptography/Cipher/Chacha20Tests.cs @@ -0,0 +1,205 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Security; +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.Cipher; +using ModernKeePassLib.Utility; +using NUnit.Framework; + +namespace ModernKeePassLib.Test.Cryptography.Cipher +{ + [TestFixture] + public class Chacha20Tests + { + [Test] + public void TestChacha20() + { + // ====================================================== + // Test vector from RFC 7539, section 2.3.2 + + byte[] pbKey = new byte[32]; + for (int i = 0; i < 32; ++i) pbKey[i] = (byte)i; + + byte[] pbIV = new byte[12]; + pbIV[3] = 0x09; + pbIV[7] = 0x4A; + + byte[] pbExpc = new byte[64] { + 0x10, 0xF1, 0xE7, 0xE4, 0xD1, 0x3B, 0x59, 0x15, + 0x50, 0x0F, 0xDD, 0x1F, 0xA3, 0x20, 0x71, 0xC4, + 0xC7, 0xD1, 0xF4, 0xC7, 0x33, 0xC0, 0x68, 0x03, + 0x04, 0x22, 0xAA, 0x9A, 0xC3, 0xD4, 0x6C, 0x4E, + 0xD2, 0x82, 0x64, 0x46, 0x07, 0x9F, 0xAA, 0x09, + 0x14, 0xC2, 0xD7, 0x05, 0xD9, 0x8B, 0x02, 0xA2, + 0xB5, 0x12, 0x9C, 0xD1, 0xDE, 0x16, 0x4E, 0xB9, + 0xCB, 0xD0, 0x83, 0xE8, 0xA2, 0x50, 0x3C, 0x4E + }; + + byte[] pb = new byte[64]; + + using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) + { + c.Seek(64, SeekOrigin.Begin); // Skip first block + c.Encrypt(pb, 0, pb.Length); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + } + +#if DEBUG + // ====================================================== + // Test vector from RFC 7539, section 2.4.2 + + pbIV[3] = 0; + + pb = StrUtil.Utf8.GetBytes("Ladies and Gentlemen of the clas" + + @"s of '99: If I could offer you only one tip for " + + @"the future, sunscreen would be it."); + + pbExpc = new byte[] { + 0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80, + 0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81, + 0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2, + 0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B, + 0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB, + 0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57, + 0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB, + 0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8, + 0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61, + 0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E, + 0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06, + 0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36, + 0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6, + 0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42, + 0x87, 0x4D + }; + + byte[] pb64 = new byte[64]; + + using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV)) + { + c.Encrypt(pb64, 0, pb64.Length); // Skip first block + c.Encrypt(pb, 0, pb.Length); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + } + + // ====================================================== + // Test vector from RFC 7539, appendix A.2 #2 + + Array.Clear(pbKey, 0, pbKey.Length); + pbKey[31] = 1; + + Array.Clear(pbIV, 0, pbIV.Length); + pbIV[11] = 2; + + pb = StrUtil.Utf8.GetBytes("Any submission to the IETF inten" + + "ded by the Contributor for publication as all or" + + " part of an IETF Internet-Draft or RFC and any s" + + "tatement made within the context of an IETF acti" + + "vity is considered an \"IETF Contribution\". Such " + + "statements include oral statements in IETF sessi" + + "ons, as well as written and electronic communica" + + "tions made at any time or place, which are addressed to"); + + pbExpc = MemUtil.HexStringToByteArray( + "A3FBF07DF3FA2FDE4F376CA23E82737041605D9F4F4F57BD8CFF2C1D4B7955EC" + + "2A97948BD3722915C8F3D337F7D370050E9E96D647B7C39F56E031CA5EB6250D" + + "4042E02785ECECFA4B4BB5E8EAD0440E20B6E8DB09D881A7C6132F420E527950" + + "42BDFA7773D8A9051447B3291CE1411C680465552AA6C405B7764D5E87BEA85A" + + "D00F8449ED8F72D0D662AB052691CA66424BC86D2DF80EA41F43ABF937D3259D" + + "C4B2D0DFB48A6C9139DDD7F76966E928E635553BA76C5C879D7B35D49EB2E62B" + + "0871CDAC638939E25E8A1E0EF9D5280FA8CA328B351C3C765989CBCF3DAA8B6C" + + "CC3AAF9F3979C92B3720FC88DC95ED84A1BE059C6499B9FDA236E7E818B04B0B" + + "C39C1E876B193BFE5569753F88128CC08AAA9B63D1A16F80EF2554D7189C411F" + + "5869CA52C5B83FA36FF216B9C1D30062BEBCFD2DC5BCE0911934FDA79A86F6E6" + + "98CED759C3FF9B6477338F3DA4F9CD8514EA9982CCAFB341B2384DD902F3D1AB" + + "7AC61DD29C6F21BA5B862F3730E37CFDC4FD806C22F221"); + + using (MemoryStream msEnc = new MemoryStream()) + { + using (ChaCha20Stream c = new ChaCha20Stream(msEnc, true, pbKey, pbIV)) + { + Random r = CryptoRandom.NewWeakRandom(); + r.NextBytes(pb64); + c.Write(pb64, 0, pb64.Length); // Skip first block + + int p = 0; + while (p < pb.Length) + { + int cb = r.Next(1, pb.Length - p + 1); + c.Write(pb, p, cb); + p += cb; + } + Debug.Assert(p == pb.Length); + } + + byte[] pbEnc0 = msEnc.ToArray(); + byte[] pbEnc = MemUtil.Mid(pbEnc0, 64, pbEnc0.Length - 64); + Assert.That(MemUtil.ArraysEqual(pbEnc, pbExpc), Is.True); + + using (MemoryStream msCT = new MemoryStream(pbEnc0, false)) + { + using (ChaCha20Stream cDec = new ChaCha20Stream(msCT, false, + pbKey, pbIV)) + { + byte[] pbPT = MemUtil.Read(cDec, pbEnc0.Length); + + Assert.That(cDec.ReadByte(), Is.LessThan(0)); + Assert.That(MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 0, 64), pb64), Is.True); + Assert.That(MemUtil.ArraysEqual(MemUtil.Mid(pbPT, 64, pbEnc.Length), pb), Is.True); + } + } + } + + // ====================================================== + // Test vector TC8 from RFC draft by J. Strombergson: + // https://tools.ietf.org/html/draft-strombergson-chacha-test-vectors-01 + + pbKey = new byte[32] { + 0xC4, 0x6E, 0xC1, 0xB1, 0x8C, 0xE8, 0xA8, 0x78, + 0x72, 0x5A, 0x37, 0xE7, 0x80, 0xDF, 0xB7, 0x35, + 0x1F, 0x68, 0xED, 0x2E, 0x19, 0x4C, 0x79, 0xFB, + 0xC6, 0xAE, 0xBE, 0xE1, 0xA6, 0x67, 0x97, 0x5D + }; + + // The first 4 bytes are set to zero and a large counter + // is used; this makes the RFC 7539 version of ChaCha20 + // compatible with the original specification by + // D. J. Bernstein. + pbIV = new byte[12] { 0x00, 0x00, 0x00, 0x00, + 0x1A, 0xDA, 0x31, 0xD5, 0xCF, 0x68, 0x82, 0x21 + }; + + pb = new byte[128]; + + pbExpc = new byte[128] { + 0xF6, 0x3A, 0x89, 0xB7, 0x5C, 0x22, 0x71, 0xF9, + 0x36, 0x88, 0x16, 0x54, 0x2B, 0xA5, 0x2F, 0x06, + 0xED, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2B, 0x00, + 0xB5, 0xE8, 0xF8, 0x0A, 0xE9, 0xA4, 0x73, 0xAF, + 0xC2, 0x5B, 0x21, 0x8F, 0x51, 0x9A, 0xF0, 0xFD, + 0xD4, 0x06, 0x36, 0x2E, 0x8D, 0x69, 0xDE, 0x7F, + 0x54, 0xC6, 0x04, 0xA6, 0xE0, 0x0F, 0x35, 0x3F, + 0x11, 0x0F, 0x77, 0x1B, 0xDC, 0xA8, 0xAB, 0x92, + + 0xE5, 0xFB, 0xC3, 0x4E, 0x60, 0xA1, 0xD9, 0xA9, + 0xDB, 0x17, 0x34, 0x5B, 0x0A, 0x40, 0x27, 0x36, + 0x85, 0x3B, 0xF9, 0x10, 0xB0, 0x60, 0xBD, 0xF1, + 0xF8, 0x97, 0xB6, 0x29, 0x0F, 0x01, 0xD1, 0x38, + 0xAE, 0x2C, 0x4C, 0x90, 0x22, 0x5B, 0xA9, 0xEA, + 0x14, 0xD5, 0x18, 0xF5, 0x59, 0x29, 0xDE, 0xA0, + 0x98, 0xCA, 0x7A, 0x6C, 0xCF, 0xE6, 0x12, 0x27, + 0x05, 0x3C, 0x84, 0xE4, 0x9A, 0x4A, 0x33, 0x32 + }; + + using (ChaCha20Cipher c = new ChaCha20Cipher(pbKey, pbIV, true)) + { + c.Decrypt(pb, 0, pb.Length); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + } +#endif + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs b/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs index cb78604..cd775f5 100644 --- a/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs +++ b/ModernKeePassLib.Test/Cryptography/Cipher/StandardAesEngineTests.cs @@ -14,7 +14,7 @@ using NUnit.Framework; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Parameters; -namespace ModernKeePassLib.Test.Shared.Cryptography.Cipher +namespace ModernKeePassLib.Test.Cryptography.Cipher { [TestFixture()] public class StandardAesEngineTests diff --git a/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs b/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs index 39ff6a0..75d3937 100644 --- a/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs +++ b/ModernKeePassLib.Test/Cryptography/CryptoRandomStreamTests.cs @@ -7,7 +7,7 @@ using KeePassLib.Cryptography; using ModernKeePassLib.Cryptography; #endif -namespace ModernKeePassLib.Test.Shared.Cryptography +namespace ModernKeePassLib.Test.Cryptography { [TestFixture ()] public class CryptoRandomStreamTests diff --git a/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs b/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs index c94b3b6..32c6c2b 100644 --- a/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs +++ b/ModernKeePassLib.Test/Cryptography/CryptoRandomTests.cs @@ -7,7 +7,7 @@ using KeePassLib.Cryptography; using ModernKeePassLib.Cryptography; #endif -namespace ModernKeePassLib.Test.Shared.Cryptography +namespace ModernKeePassLib.Test.Cryptography { [TestFixture ()] public class CryptoRandomTests diff --git a/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs b/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs new file mode 100644 index 0000000..a91591e --- /dev/null +++ b/ModernKeePassLib.Test/Cryptography/Hash/Blake2bTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Text; +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.Hash; +using ModernKeePassLib.Utility; +using NUnit.Framework; + +namespace ModernKeePassLib.Test.Cryptography.Hash +{ + [TestFixture] + public class Blake2bTests + { + [Test] + public void TestBlake2b() + { + Blake2b h = new Blake2b(); + + // ====================================================== + // From https://tools.ietf.org/html/rfc7693 + + byte[] pbData = StrUtil.Utf8.GetBytes("abc"); + byte[] pbExpc = new byte[64] { + 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, + 0x6A, 0x27, 0x97, 0xB6, 0x9F, 0x12, 0xF6, 0xE9, + 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, 0xC4, 0xB7, + 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1, + 0x7D, 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, + 0xC2, 0x52, 0xD5, 0xDE, 0x45, 0x33, 0xCC, 0x95, + 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, 0x5A, + 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23 + }; + + byte[] pbC = h.ComputeHash(pbData); + Assert.That(MemUtil.ArraysEqual(pbC, pbExpc), Is.True); + + // ====================================================== + // Computed using the official b2sum tool + + pbExpc = new byte[64] { + 0x78, 0x6A, 0x02, 0xF7, 0x42, 0x01, 0x59, 0x03, + 0xC6, 0xC6, 0xFD, 0x85, 0x25, 0x52, 0xD2, 0x72, + 0x91, 0x2F, 0x47, 0x40, 0xE1, 0x58, 0x47, 0x61, + 0x8A, 0x86, 0xE2, 0x17, 0xF7, 0x1F, 0x54, 0x19, + 0xD2, 0x5E, 0x10, 0x31, 0xAF, 0xEE, 0x58, 0x53, + 0x13, 0x89, 0x64, 0x44, 0x93, 0x4E, 0xB0, 0x4B, + 0x90, 0x3A, 0x68, 0x5B, 0x14, 0x48, 0xB7, 0x55, + 0xD5, 0x6F, 0x70, 0x1A, 0xFE, 0x9B, 0xE2, 0xCE + }; + + pbC = h.ComputeHash(MemUtil.EmptyByteArray); + Assert.That(MemUtil.ArraysEqual(pbC, pbExpc), Is.True); + + // ====================================================== + // Computed using the official b2sum tool + + string strS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;_-\r\n"; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 1000; ++i) sb.Append(strS); + pbData = StrUtil.Utf8.GetBytes(sb.ToString()); + + pbExpc = new byte[64] { + 0x59, 0x69, 0x8D, 0x3B, 0x83, 0xF4, 0x02, 0x4E, + 0xD8, 0x99, 0x26, 0x0E, 0xF4, 0xE5, 0x9F, 0x20, + 0xDC, 0x31, 0xEE, 0x5B, 0x45, 0xEA, 0xBB, 0xFC, + 0x1C, 0x0A, 0x8E, 0xED, 0xAA, 0x7A, 0xFF, 0x50, + 0x82, 0xA5, 0x8F, 0xBC, 0x4A, 0x46, 0xFC, 0xC5, + 0xEF, 0x44, 0x4E, 0x89, 0x80, 0x7D, 0x3F, 0x1C, + 0xC1, 0x94, 0x45, 0xBB, 0xC0, 0x2C, 0x95, 0xAA, + 0x3F, 0x08, 0x8A, 0x93, 0xF8, 0x75, 0x91, 0xB0 + }; + + Random r = CryptoRandom.NewWeakRandom(); + int p = 0; + while (p < pbData.Length) + { + int cb = r.Next(1, pbData.Length - p + 1); + h.TransformBlock(pbData, p, cb, pbData, p); + p += cb; + } + Assert.That(p, Is.EqualTo(pbData.Length)); + + h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); + + Assert.That(MemUtil.ArraysEqual(h.Hash, pbExpc), Is.True); + + h.Clear(); + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs b/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs new file mode 100644 index 0000000..ebcd198 --- /dev/null +++ b/ModernKeePassLib.Test/Cryptography/Hash/HmacTests.cs @@ -0,0 +1,82 @@ +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.Hash; +using ModernKeePassLib.Utility; +using NUnit.Framework; + +namespace ModernKeePassLib.Test.Cryptography.Hash +{ + [TestFixture] + public class HmacTests + { + [Test] + public void TestHmac1() + { + // Test vectors from RFC 4231 + + var pbKey = new byte[20]; + for (var i = 0; i < pbKey.Length; ++i) pbKey[i] = 0x0B; + var pbMsg = StrUtil.Utf8.GetBytes("Hi There"); + var pbExpc = new byte[] + { + 0xB0, 0x34, 0x4C, 0x61, 0xD8, 0xDB, 0x38, 0x53, + 0x5C, 0xA8, 0xAF, 0xCE, 0xAF, 0x0B, 0xF1, 0x2B, + 0x88, 0x1D, 0xC2, 0x00, 0xC9, 0x83, 0x3D, 0xA7, + 0x26, 0xE9, 0x37, 0x6C, 0x2E, 0x32, 0xCF, 0xF7 + }; + HmacEval(pbKey, pbMsg, pbExpc); + } + + [Test] + public void TestHmac2() + { + var pbKey = new byte[131]; + for (var i = 0; i < pbKey.Length; ++i) pbKey[i] = 0xAA; + var pbMsg = StrUtil.Utf8.GetBytes( + "This is a test using a larger than block-size key and " + + "a larger than block-size data. The key needs to be " + + "hashed before being used by the HMAC algorithm."); + var pbExpc = new byte[] { + 0x9B, 0x09, 0xFF, 0xA7, 0x1B, 0x94, 0x2F, 0xCB, + 0x27, 0x63, 0x5F, 0xBC, 0xD5, 0xB0, 0xE9, 0x44, + 0xBF, 0xDC, 0x63, 0x64, 0x4F, 0x07, 0x13, 0x93, + 0x8A, 0x7F, 0x51, 0x53, 0x5C, 0x3A, 0x35, 0xE2 + }; + HmacEval(pbKey, pbMsg, pbExpc); + } + + [Test] + public void TestHmacOtp() + { + var pbSecret = StrUtil.Utf8.GetBytes("12345678901234567890"); + var vExp = new []{ "755224", "287082", "359152", + "969429", "338314", "254676", "287922", "162583", "399871", + "520489" }; + + for (var i = 0; i < vExp.Length; ++i) + { + Assert.That(HmacOtp.Generate(pbSecret, (ulong)i, 6, false, -1), Is.EqualTo(vExp[i])); + } + } + + private static void HmacEval(byte[] pbKey, byte[] pbMsg, + byte[] pbExpc) + { + using (var h = new HMACSHA256(pbKey)) + { + h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); + h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); + + byte[] pbHash = h.Hash; + Assert.That(MemUtil.ArraysEqual(pbHash, pbExpc), Is.True); + + // Reuse the object + h.Initialize(); + h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); + h.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); + + pbHash = h.Hash; + Assert.That(MemUtil.ArraysEqual(pbHash, pbExpc), Is.True); + } + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs b/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs index 59c4980..7fd746d 100644 --- a/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs +++ b/ModernKeePassLib.Test/Cryptography/HashingStreamExTests.cs @@ -9,7 +9,7 @@ using KeePassLib.Cryptography; using ModernKeePassLib.Cryptography; #endif -namespace ModernKeePassLib.Test.Shared.Cryptography +namespace ModernKeePassLib.Test.Cryptography { [TestFixture ()] public class HashingStreamExTests diff --git a/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs b/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs index 894b979..0892c6d 100644 --- a/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs +++ b/ModernKeePassLib.Test/Cryptography/HmacOtpTests.cs @@ -8,7 +8,7 @@ using KeePassLib.Cryptography; using ModernKeePassLib.Cryptography; #endif -namespace ModernKeePassLib.Test.Shared.Cryptography +namespace ModernKeePassLib.Test.Cryptography { [TestFixture ()] public class HmacOtpTests diff --git a/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs b/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs new file mode 100644 index 0000000..b43aa71 --- /dev/null +++ b/ModernKeePassLib.Test/Cryptography/KeyDerivation/AesKdfTests.cs @@ -0,0 +1,42 @@ +using System; +using ModernKeePassLib.Cryptography; +using ModernKeePassLib.Cryptography.KeyDerivation; +using ModernKeePassLib.Utility; +using NUnit.Framework; + +namespace ModernKeePassLib.Test.Cryptography.KeyDerivation +{ + [TestFixture] + public class AesKdfTests + { + [Test] + 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.That(AesKdf.TransformKeyManaged(pbMan, pbSeed, uRounds), Is.True); + 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.That(MemUtil.ArraysEqual(pbMan, pbKdf), Is.True); + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs b/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs new file mode 100644 index 0000000..44c34ff --- /dev/null +++ b/ModernKeePassLib.Test/Cryptography/KeyDerivation/Argon2Tests.cs @@ -0,0 +1,145 @@ +using ModernKeePassLib.Cryptography.KeyDerivation; +using ModernKeePassLib.Utility; +using NUnit.Framework; + +namespace ModernKeePassLib.Test.Cryptography.KeyDerivation +{ + [TestFixture] + public class Argon2Tests + { + [Test] + public void TestArgon2() + { + Argon2Kdf kdf = new Argon2Kdf(); + + // ====================================================== + // From the official Argon2 1.3 reference code package + // (test vector for Argon2d 1.3); also on + // https://tools.ietf.org/html/draft-irtf-cfrg-argon2-00 + + var p = kdf.GetDefaultParameters(); + kdf.Randomize(p); + + Assert.That(p.GetUInt32(Argon2Kdf.ParamVersion, 0), Is.EqualTo(0x13U)); + + byte[] pbMsg = new byte[32]; + for (int i = 0; i < pbMsg.Length; ++i) pbMsg[i] = 1; + + p.SetUInt64(Argon2Kdf.ParamMemory, 32 * 1024); + p.SetUInt64(Argon2Kdf.ParamIterations, 3); + p.SetUInt32(Argon2Kdf.ParamParallelism, 4); + + byte[] pbSalt = new byte[16]; + for (int i = 0; i < pbSalt.Length; ++i) pbSalt[i] = 2; + p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); + + byte[] pbKey = new byte[8]; + for (int i = 0; i < pbKey.Length; ++i) pbKey[i] = 3; + p.SetByteArray(Argon2Kdf.ParamSecretKey, pbKey); + + byte[] pbAssoc = new byte[12]; + for (int i = 0; i < pbAssoc.Length; ++i) pbAssoc[i] = 4; + p.SetByteArray(Argon2Kdf.ParamAssocData, pbAssoc); + + byte[] pbExpc = new byte[32] { + 0x51, 0x2B, 0x39, 0x1B, 0x6F, 0x11, 0x62, 0x97, + 0x53, 0x71, 0xD3, 0x09, 0x19, 0x73, 0x42, 0x94, + 0xF8, 0x68, 0xE3, 0xBE, 0x39, 0x84, 0xF3, 0xC1, + 0xA1, 0x3A, 0x4D, 0xB9, 0xFA, 0xBE, 0x4A, 0xCB + }; + + byte[] pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + + // ====================================================== + // From the official Argon2 1.3 reference code package + // (test vector for Argon2d 1.0) + + p.SetUInt32(Argon2Kdf.ParamVersion, 0x10); + + pbExpc = new byte[32] { + 0x96, 0xA9, 0xD4, 0xE5, 0xA1, 0x73, 0x40, 0x92, + 0xC8, 0x5E, 0x29, 0xF4, 0x10, 0xA4, 0x59, 0x14, + 0xA5, 0xDD, 0x1F, 0x5C, 0xBF, 0x08, 0xB2, 0x67, + 0x0D, 0xA6, 0x8A, 0x02, 0x85, 0xAB, 0xF3, 0x2B + }; + + pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + + // ====================================================== + // From the official 'phc-winner-argon2-20151206.zip' + // (test vector for Argon2d 1.0) + + p.SetUInt64(Argon2Kdf.ParamMemory, 16 * 1024); + + pbExpc = new byte[32] { + 0x57, 0xB0, 0x61, 0x3B, 0xFD, 0xD4, 0x13, 0x1A, + 0x0C, 0x34, 0x88, 0x34, 0xC6, 0x72, 0x9C, 0x2C, + 0x72, 0x29, 0x92, 0x1E, 0x6B, 0xBA, 0x37, 0x66, + 0x5D, 0x97, 0x8C, 0x4F, 0xE7, 0x17, 0x5E, 0xD2 + }; + + pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + + // ====================================================== + // Computed using the official 'argon2' application + // (test vectors for Argon2d 1.3) + + p = kdf.GetDefaultParameters(); + + pbMsg = StrUtil.Utf8.GetBytes("ABC1234"); + + p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 11) * 1024); // 2 MB + p.SetUInt64(Argon2Kdf.ParamIterations, 2); + p.SetUInt32(Argon2Kdf.ParamParallelism, 2); + + pbSalt = StrUtil.Utf8.GetBytes("somesalt"); + p.SetByteArray(Argon2Kdf.ParamSalt, pbSalt); + + pbExpc = new byte[32] { + 0x29, 0xCB, 0xD3, 0xA1, 0x93, 0x76, 0xF7, 0xA2, + 0xFC, 0xDF, 0xB0, 0x68, 0xAC, 0x0B, 0x99, 0xBA, + 0x40, 0xAC, 0x09, 0x01, 0x73, 0x42, 0xCE, 0xF1, + 0x29, 0xCC, 0xA1, 0x4F, 0xE1, 0xC1, 0xB7, 0xA3 + }; + + pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + + p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 10) * 1024); // 1 MB + p.SetUInt64(Argon2Kdf.ParamIterations, 3); + + pbExpc = new byte[32] { + 0x7A, 0xBE, 0x1C, 0x1C, 0x8D, 0x7F, 0xD6, 0xDC, + 0x7C, 0x94, 0x06, 0x3E, 0xD8, 0xBC, 0xD8, 0x1C, + 0x2F, 0x87, 0x84, 0x99, 0x12, 0x83, 0xFE, 0x76, + 0x00, 0x64, 0xC4, 0x58, 0xA4, 0xDA, 0x35, 0x70 + }; + + pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + + p.SetUInt64(Argon2Kdf.ParamMemory, (1 << 20) * 1024); // 1 GB + p.SetUInt64(Argon2Kdf.ParamIterations, 2); + p.SetUInt32(Argon2Kdf.ParamParallelism, 3); + + pbExpc = new byte[32] { + 0xE6, 0xE7, 0xCB, 0xF5, 0x5A, 0x06, 0x93, 0x05, + 0x32, 0xBA, 0x86, 0xC6, 0x1F, 0x45, 0x17, 0x99, + 0x65, 0x41, 0x77, 0xF9, 0x30, 0x55, 0x9A, 0xE8, + 0x3D, 0x21, 0x48, 0xC6, 0x2D, 0x0C, 0x49, 0x11 + }; + + pb = kdf.Transform(pbMsg, p); + + Assert.That(MemUtil.ArraysEqual(pb, pbExpc), Is.True); + } + } +} \ No newline at end of file diff --git a/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs b/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs index 8afb827..ed5118c 100644 --- a/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs +++ b/ModernKeePassLib.Test/Keys/CompositeKeyTests.cs @@ -2,7 +2,7 @@ using ModernKeePassLib.Cryptography.KeyDerivation; using ModernKeePassLib.Keys; -namespace ModernKeePassLib.Test.Shared.Keys +namespace ModernKeePassLib.Test.Keys { [TestFixture ()] public class CompositeKeyTests diff --git a/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs b/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs index 0df7709..ecacde5 100644 --- a/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs +++ b/ModernKeePassLib.Test/Keys/KcpCustomKeyTests.cs @@ -7,7 +7,7 @@ using KeePassLib.Keys; using ModernKeePassLib.Keys; #endif -namespace ModernKeePassLib.Test.Shared.Keys +namespace ModernKeePassLib.Test.Keys { [TestFixture ()] public class KcpCustomKeyTests diff --git a/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs b/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs index f00ee71..06e4c75 100644 --- a/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs +++ b/ModernKeePassLib.Test/Keys/KcpKeyFileTests.cs @@ -8,7 +8,7 @@ using KeePassLib.Keys; using ModernKeePassLib.Keys; #endif -namespace ModernKeePassLib.Test.Shared.Keys +namespace ModernKeePassLib.Test.Keys { [TestFixture ()] public class KcpKeyFileTests diff --git a/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs b/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs index 4dc794b..4fbc4a7 100644 --- a/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs +++ b/ModernKeePassLib.Test/Keys/KcpPasswordTests.cs @@ -7,7 +7,7 @@ using KeePassLib.Keys; using ModernKeePassLib.Keys; #endif -namespace ModernKeePassLib.Test.Shared.Keys +namespace ModernKeePassLib.Test.Keys { [TestFixture ()] public class KcpPasswordTests diff --git a/ModernKeePassLib.Test/ModernKeePassLib.Test.csproj b/ModernKeePassLib.Test/ModernKeePassLib.Test.csproj index 702570f..30b8dfe 100644 --- a/ModernKeePassLib.Test/ModernKeePassLib.Test.csproj +++ b/ModernKeePassLib.Test/ModernKeePassLib.Test.csproj @@ -54,11 +54,16 @@ + + + + + diff --git a/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs b/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs index 926e91a..e26d2ec 100644 --- a/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs +++ b/ModernKeePassLib.Test/Serialization/HashedBlockStreamTests.cs @@ -8,7 +8,7 @@ using KeePassLib.Serialization; using ModernKeePassLib.Serialization; #endif -namespace ModernKeePassLib.Test.Shared.Serialization +namespace ModernKeePassLib.Test.Serialization { [TestFixture ()] public class HashedBlockStreamTests diff --git a/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs b/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs index 2cd995e..3e29219 100644 --- a/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs +++ b/ModernKeePassLib.Test/Serialization/KdbxFileTests.cs @@ -20,7 +20,7 @@ using ModernKeePassLib.Serialization; using ModernKeePassLib.Collections; #endif -namespace ModernKeePassLib.Test.Shared.Serialization +namespace ModernKeePassLib.Test.Serialization { [TestFixture()] public class KdbxFileTests diff --git a/ModernKeePassLib.Test/Utility/GfxUtilTests.cs b/ModernKeePassLib.Test/Utility/GfxUtilTests.cs index 70a551e..64da5ab 100644 --- a/ModernKeePassLib.Test/Utility/GfxUtilTests.cs +++ b/ModernKeePassLib.Test/Utility/GfxUtilTests.cs @@ -8,7 +8,7 @@ using Splat; using ModernKeePassLib.Utility; #endif -namespace ModernKeePassLib.Test.Shared.Utility +namespace ModernKeePassLib.Test.Utility { [TestFixture ()] public class GfxUtilTests diff --git a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs b/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs index 7b8a26c..4f1a1e9 100644 --- a/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs +++ b/ModernKeePassLib/Cryptography/Cipher/ChaCha20Engine.cs @@ -69,7 +69,7 @@ namespace ModernKeePassLib.Cryptography.Cipher } } - internal sealed class ChaCha20Stream : Stream + public sealed class ChaCha20Stream : Stream { private Stream m_sBase; private readonly bool m_bWriting; diff --git a/ModernKeePassLib/Cryptography/Hash/DigestManaged.cs b/ModernKeePassLib/Cryptography/Hash/DigestManaged.cs index 6c20e84..9622e09 100644 --- a/ModernKeePassLib/Cryptography/Hash/DigestManaged.cs +++ b/ModernKeePassLib/Cryptography/Hash/DigestManaged.cs @@ -5,7 +5,17 @@ namespace ModernKeePassLib.Cryptography.Hash { public abstract class DigestManaged: IDisposable { - protected IDigest Hash; + protected IDigest Digest; + + public byte[] Hash + { + get + { + var result = new byte[Digest.GetDigestSize()]; + Digest.DoFinal(result, 0); + return result; + } + } public byte[] ComputeHash(byte[] value) { @@ -16,16 +26,29 @@ namespace ModernKeePassLib.Cryptography.Hash { if (value == null) throw new ArgumentNullException(nameof(value)); - byte[] resBuf = new byte[Hash.GetDigestSize()]; - Hash.BlockUpdate(value, 0, length); - Hash.DoFinal(resBuf, 0); + byte[] resBuf = new byte[Digest.GetDigestSize()]; + Digest.BlockUpdate(value, 0, length); + Digest.DoFinal(resBuf, 0); return resBuf; } + + public void TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + Digest.BlockUpdate(inputBuffer, inputOffset, inputCount); + if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))) + Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); + } + + public void TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) + { + Digest.BlockUpdate(inputBuffer, inputOffset, inputCount); + } + public void Dispose() { - Hash.Reset(); + Digest.Reset(); } } } diff --git a/ModernKeePassLib/Cryptography/Hash/HMAC.cs b/ModernKeePassLib/Cryptography/Hash/HMAC.cs index 5e931b4..10c8c9b 100644 --- a/ModernKeePassLib/Cryptography/Hash/HMAC.cs +++ b/ModernKeePassLib/Cryptography/Hash/HMAC.cs @@ -5,7 +5,17 @@ namespace ModernKeePassLib.Cryptography.Hash { public class HMAC : IDisposable { - protected HMac _hmac; + protected HMac Hmac; + + public byte[] Hash + { + get + { + var result = new byte[Hmac.GetMacSize()]; + Hmac.DoFinal(result, 0); + return result; + } + } public byte[] ComputeHash(byte[] value) { @@ -16,16 +26,33 @@ namespace ModernKeePassLib.Cryptography.Hash { if (value == null) throw new ArgumentNullException(nameof(value)); - byte[] resBuf = new byte[_hmac.GetMacSize()]; - _hmac.BlockUpdate(value, 0, length); - _hmac.DoFinal(resBuf, 0); + byte[] resBuf = new byte[Hmac.GetMacSize()]; + Hmac.BlockUpdate(value, 0, length); + Hmac.DoFinal(resBuf, 0); return resBuf; } + public void TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + Hmac.BlockUpdate(inputBuffer, inputOffset, inputCount); + if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))) + Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount); + } + + public void TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) + { + Hmac.BlockUpdate(inputBuffer, inputOffset, inputCount); + } + + public void Initialize() + { + Hmac.Reset(); + } + public void Dispose() { - _hmac.Reset(); + Hmac.Reset(); } } } diff --git a/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs b/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs index ac298d4..c720caa 100644 --- a/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs +++ b/ModernKeePassLib/Cryptography/Hash/HMACSHA1.cs @@ -8,8 +8,8 @@ namespace ModernKeePassLib.Cryptography.Hash { public HMACSHA1(byte[] key) { - _hmac = new HMac(new Sha1Digest()); - _hmac.Init(new KeyParameter(key)); + Hmac = new HMac(new Sha1Digest()); + Hmac.Init(new KeyParameter(key)); } } } diff --git a/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs b/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs index 65cbaeb..d0d5703 100644 --- a/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs +++ b/ModernKeePassLib/Cryptography/Hash/HMACSHA256.cs @@ -8,23 +8,8 @@ namespace ModernKeePassLib.Cryptography.Hash { public HMACSHA256(byte[] key) { - _hmac = new HMac(new Sha256Digest()); - _hmac.Init(new KeyParameter(key)); + Hmac = new HMac(new Sha256Digest()); + Hmac.Init(new KeyParameter(key)); } - - /*internal void TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) - { - _hmac.BlockUpdate(inputBuffer, inputOffset, inputCount); - } - - internal void TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) - { - _hmac.DoFinal(inputBuffer, inputOffset); - } - - internal void Initialize() - { - _hmac.Reset(); - }*/ } } diff --git a/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs b/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs index 55d1cbd..c5323e4 100644 --- a/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs +++ b/ModernKeePassLib/Cryptography/Hash/SHA256Managed.cs @@ -6,7 +6,7 @@ namespace ModernKeePassLib.Cryptography.Hash { public SHA256Managed() { - Hash = new Sha256Digest(); + Digest = new Sha256Digest(); } } } diff --git a/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs b/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs index d98ba77..f9d5ad6 100644 --- a/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs +++ b/ModernKeePassLib/Cryptography/Hash/SHA512Managed.cs @@ -6,7 +6,7 @@ namespace ModernKeePassLib.Cryptography.Hash { public SHA512Managed() { - Hash = new Sha512Digest(); + Digest = new Sha512Digest(); } } } diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs b/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs index 9abf6da..91b7ca6 100644 --- a/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs +++ b/ModernKeePassLib/Cryptography/KeyDerivation/AesKdf.cs @@ -134,7 +134,7 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation return null; } - internal static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, + public static bool TransformKeyManaged(byte[] pbNewKey32, byte[] pbKeySeed32, ulong uNumRounds) { #if ModernKeePassLib || KeePassUAP diff --git a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs b/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs index 1edefa8..c4b6356 100644 --- a/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs +++ b/ModernKeePassLib/Cryptography/KeyDerivation/Argon2Kdf.Core.cs @@ -34,7 +34,7 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; using System.Threading; - +using System.Threading.Tasks; using ModernKeePassLib.Cryptography.Hash; using ModernKeePassLib.Utility; @@ -465,7 +465,10 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation ti.Pass = r; ti.Lane = (ulong)l; ti.Slice = s; -#if !ModernKeePassLib + +#if ModernKeePassLib + Task.Factory.StartNew(FillSegmentThr, ti); +#else if(!ThreadPool.QueueUserWorkItem(FillSegmentThr, ti)) { Debug.Assert(false); @@ -483,8 +486,8 @@ namespace ModernKeePassLib.Cryptography.KeyDerivation } } } - - private static void FillSegmentThr(object o) + + private static void FillSegmentThr(object o) { Argon2ThreadInfo ti = (o as Argon2ThreadInfo); if(ti == null) { Debug.Assert(false); return; } diff --git a/ModernKeePassLib/Cryptography/SelfTest.cs b/ModernKeePassLib/Cryptography/SelfTest.cs index 420c02a..4e7f627 100644 --- a/ModernKeePassLib/Cryptography/SelfTest.cs +++ b/ModernKeePassLib/Cryptography/SelfTest.cs @@ -417,7 +417,7 @@ namespace ModernKeePassLib.Cryptography private static void TestBlake2b(Random r) { -#if !ModernKeePassLib && DEBUG +#if DEBUG Blake2b h = new Blake2b(); // ====================================================== @@ -676,35 +676,6 @@ namespace ModernKeePassLib.Cryptography private static void HmacEval(byte[] pbKey, byte[] pbMsg, byte[] pbExpc, string strID) { -#if ModernKeePassLib - /* - // WinRT - var h = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256).CreateHash(CryptographicBuffer.CreateFromByteArray(pbKey)); - h.Append(CryptographicBuffer.CreateFromByteArray(pbMsg)); - var pbHash = h.GetValueAndReset().ToArray(); - if (!MemUtil.ArraysEqual(pbHash, pbExpc)) - throw new SecurityException("HMAC-SHA-256-" + strID); - - h.Append(CryptographicBuffer.CreateFromByteArray(pbMsg)); - pbHash = h.GetValueAndReset().ToArray(); - if (!MemUtil.ArraysEqual(pbHash, pbExpc)) - throw new SecurityException("HMAC-SHA-256-" + strID + "-R"); - - // BouncyCastle - // var h = new HMac(new Sha256Digest()); - //h.BlockUpdate(pbMsg, 0, pbMsg.Length); - //byte[] pbHash = MemUtil.EmptyByteArray; - //h.DoFinal(pbHash, 0); - //if (!MemUtil.ArraysEqual(pbHash, pbExpc)) - // throw new SecurityException("HMAC-SHA-256-" + strID); - - // h.Reset(); - //h.BlockUpdate(pbMsg, 0, pbMsg.Length); - //h.DoFinal(pbHash, 0); - //if (!MemUtil.ArraysEqual(pbHash, pbExpc)) - // throw new SecurityException("HMAC-SHA-256-" + strID + "-R");*/ -#else - // Original using(HMACSHA256 h = new HMACSHA256(pbKey)) { h.TransformBlock(pbMsg, 0, pbMsg.Length, pbMsg, 0); @@ -723,7 +694,6 @@ namespace ModernKeePassLib.Cryptography if(!MemUtil.ArraysEqual(pbHash, pbExpc)) throw new SecurityException("HMAC-SHA-256-" + strID + "-R"); } -#endif } #endif diff --git a/ModernKeePassLib/ModernKeePassLib.nuspec b/ModernKeePassLib/ModernKeePassLib.nuspec index 099270b..7c8113f 100644 --- a/ModernKeePassLib/ModernKeePassLib.nuspec +++ b/ModernKeePassLib/ModernKeePassLib.nuspec @@ -10,7 +10,7 @@ https://github.com/wismna/ModernKeePass false Portable KeePass Password Management Library that targets .Net Standard and WinRT. Allows reading, editing and writing to KeePass 2.x databases. - HMAC and Blake2B re-implemented. + KDBX 4 file format supported Copyright © 2017 Geoffroy Bonneville KeePass KeePassLib Portable PCL NetStandard diff --git a/ModernKeePassLib/Serialization/HmacBlockStream.cs b/ModernKeePassLib/Serialization/HmacBlockStream.cs index 70f80d6..a64a203 100644 --- a/ModernKeePassLib/Serialization/HmacBlockStream.cs +++ b/ModernKeePassLib/Serialization/HmacBlockStream.cs @@ -22,14 +22,15 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; -using Windows.Security.Cryptography; -using Windows.Security.Cryptography.Core; + +#if ModernKeePassLib using ModernKeePassLib.Cryptography.Hash; +#elif !KeePassUAP +using System.Security.Cryptography; +#endif + using ModernKeePassLib.Resources; using ModernKeePassLib.Utility; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Macs; -using Org.BouncyCastle.Crypto.Parameters; namespace ModernKeePassLib.Serialization { @@ -149,15 +150,7 @@ namespace ModernKeePassLib.Serialization // 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) -#if ModernKeePassLib - byte[] pbBlockKey = MemUtil.EmptyByteArray; - byte[] pbIndex = MemUtil.UInt64ToBytes(uBlockIndex); - var h = new Sha512Digest(); - h.BlockUpdate(pbIndex, 0, pbIndex.Length); - h.BlockUpdate(pbKey, 0, pbKey.Length); - h.DoFinal(pbBlockKey, 0); - h.Reset(); -#else + byte[] pbBlockKey; using(SHA512Managed h = new SHA512Managed()) { @@ -169,7 +162,6 @@ namespace ModernKeePassLib.Serialization pbBlockKey = h.Hash; } -#endif #if DEBUG byte[] pbZero = new byte[64]; @@ -244,18 +236,6 @@ namespace ModernKeePassLib.Serialization { byte[] pbCmpHmac; byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); - -#if ModernKeePassLib - var h = new HMac(new Sha256Digest()); - h.Init(new KeyParameter(pbBlockKey)); - h.BlockUpdate(pbBlockIndex, 0, pbBlockIndex.Length); - h.BlockUpdate(pbBlockSize, 0, pbBlockSize.Length); - if (m_pbBuffer.Length > 0) - h.BlockUpdate(m_pbBuffer, 0, m_pbBuffer.Length); - pbCmpHmac = MemUtil.EmptyByteArray; - h.DoFinal(pbCmpHmac, 0); - h.Reset(); -#else using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) { h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, @@ -271,7 +251,6 @@ namespace ModernKeePassLib.Serialization pbCmpHmac = h.Hash; } -#endif MemUtil.ZeroByteArray(pbBlockKey); if(!MemUtil.ArraysEqual(pbCmpHmac, pbStoredHmac)) @@ -318,19 +297,6 @@ namespace ModernKeePassLib.Serialization byte[] pbBlockHmac; byte[] pbBlockKey = GetHmacKey64(m_pbKey, m_uBlockIndex); - -#if ModernKeePassLib - var h = new HMac(new Sha256Digest()); - h.Init(new KeyParameter(pbBlockKey)); - h.BlockUpdate(pbBlockIndex, 0, pbBlockIndex.Length); - h.BlockUpdate(pbBlockSize, 0, pbBlockSize.Length); - if (cbBlockSize > 0) - h.BlockUpdate(m_pbBuffer, 0, cbBlockSize); - - pbBlockHmac = MemUtil.EmptyByteArray; - h.DoFinal(pbBlockHmac, 0); - h.Reset(); -#else using(HMACSHA256 h = new HMACSHA256(pbBlockKey)) { h.TransformBlock(pbBlockIndex, 0, pbBlockIndex.Length, @@ -345,7 +311,6 @@ namespace ModernKeePassLib.Serialization pbBlockHmac = h.Hash; } -#endif MemUtil.ZeroByteArray(pbBlockKey); MemUtil.Write(m_sBase, pbBlockHmac); diff --git a/ModernKeePassLib/Utility/MemUtil.cs b/ModernKeePassLib/Utility/MemUtil.cs index 28a9ec1..18ea610 100644 --- a/ModernKeePassLib/Utility/MemUtil.cs +++ b/ModernKeePassLib/Utility/MemUtil.cs @@ -37,7 +37,7 @@ namespace ModernKeePassLib.Utility /// public static class MemUtil { - internal static readonly byte[] EmptyByteArray = new byte[0]; + public static readonly byte[] EmptyByteArray = new byte[0]; private static readonly uint[] m_vSBox = new uint[256] { 0xCD2FACB3, 0xE78A7F5C, 0x6F0803FC, 0xBCF6E230,