diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-02-03 23:14:10 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-02-03 23:14:10 +0700 |
commit | 26c0d3e4de498a9b7c8b6712bb765d693fb93de3 (patch) | |
tree | bfa0c30f149dc3e089eda4ab3ad35142394ded86 /crypto/test/src | |
parent | Implement RFC 7685 in TLS (diff) | |
download | BouncyCastle.NET-ed25519-26c0d3e4de498a9b7c8b6712bb765d693fb93de3.tar.xz |
Port bcrypt from Java API
- Requested in BMA-143
Diffstat (limited to 'crypto/test/src')
-rw-r--r-- | crypto/test/src/crypto/test/BCryptTest.cs | 161 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/OpenBsdBCryptTest.cs | 147 | ||||
-rw-r--r-- | crypto/test/src/crypto/test/RegressionTest.cs | 11 |
3 files changed, 313 insertions, 6 deletions
diff --git a/crypto/test/src/crypto/test/BCryptTest.cs b/crypto/test/src/crypto/test/BCryptTest.cs new file mode 100644 index 000000000..2d9771d17 --- /dev/null +++ b/crypto/test/src/crypto/test/BCryptTest.cs @@ -0,0 +1,161 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + /* + * bcrypt test vectors + */ + [TestFixture] + public class BCryptTest + : SimpleTest + { + // Raw test vectors based on crypt style test vectors + // Cross checked with JBCrypt + private static readonly object[][] TestVectorData = { + new object[]{"", "144b3d691a7b4ecf39cf735c7fa7a79c", 6, "557e94f34bf286e8719a26be94ac1e16d95ef9f819dee092"}, + new object[]{"00", "144b3d691a7b4ecf39cf735c7fa7a79c", 6, "557e94f34bf286e8719a26be94ac1e16d95ef9f819dee092"}, + new object[]{"00", "26c63033c04f8bcba2fe24b574db6274", 8, "56701b26164d8f1bc15225f46234ac8ac79bf5bc16bf48ba"}, + new object[]{"00", "9b7c9d2ada0fd07091c915d1517701d6", 10, "7b2e03106a43c9753821db688b5cc7590b18fdf9ba544632"}, + new object[]{"6100", "a3612d8c9a37dac2f99d94da03bd4521", 6, "e6d53831f82060dc08a2e8489ce850ce48fbf976978738f3"}, + new object[]{"6100", "7a17b15dfe1c4be10ec6a3ab47818386", 8, "a9f3469a61cbff0a0f1a1445dfe023587f38b2c9c40570e1"}, + new object[]{"6100", "9bef4d04e1f8f92f3de57323f8179190", 10, "5169fd39606d630524285147734b4c981def0ee512c3ace1"}, + new object[]{"61626300", "2a1f1dc70a3d147956a46febe3016017", 6, "d9a275b493bcbe1024b0ff80d330253cfdca34687d8f69e5"}, + new object[]{"61626300", "4ead845a142c9bc79918c8797f470ef5", 8, "8d4131a723bfbbac8a67f2e035cae08cc33b69f37331ea91"}, + new object[]{"61626300", "631c554493327c32f9c26d9be7d18e4c", 10, "8cd0b863c3ff0860e31a2b42427974e0283b3af7142969a6"}, + new object[]{"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "02d1176d74158ee29cffdac6150cf123", 6, "4d38b523ce9dc6f2f6ff9fb3c2cd71dfe7f96eb4a3baf19f"}, + new object[]{"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "715b96caed2ac92c354ed16c1e19e38a", 8, "98bf9ffc1f5be485f959e8b1d526392fbd4ed2d5719f506b"}, + new object[]{"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "85727e838f9049397fbec90566ede0df", 10, "cebba53f67bd28af5a44c6707383c231ac4ef244a6f5fb2b"}, + new object[]{"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "8512ae0d0fac4ec9a5978f79b6171028", 6, "26f517fe5345ad575ba7dfb8144f01bfdb15f3d47c1e146a"}, + new object[]{"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "1ace2de8807df18c79fced54678f388f", 8, "d51d7cdf839b91a25758b80141e42c9f896ae80fd6cd561f"}, + new object[]{"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "36285a6267751b14ba2dc989f6d43126", 10, "db4fab24c1ff41c1e2c966f8b3d6381c76e86f52da9e15a9"}, + new object[]{"c2a300", "144b3d691a7b4ecf39cf735c7fa7a79c", 6, "5a6c4fedb23980a7da9217e0442565ac6145b687c7313339"}, + }; + + public override string Name + { + get { return "BCrypt"; } + } + + public override void PerformTest() + { + DoTestParameters(); + DoTestShortKeys(); + DoTestVectors(); + } + + private void DoTestShortKeys() + { + byte[] salt = new byte[16]; + + // Check BCrypt with empty key pads to zero byte key + byte[] hashEmpty = BCrypt.Generate(new byte[0], salt, 4); + byte[] hashZero1 = BCrypt.Generate(new byte[1], salt, 4); + + if (!Arrays.AreEqual(hashEmpty, hashZero1)) + { + Fail("Hash for empty password should equal zeroed key", Hex.ToHexString(hashEmpty), + Hex.ToHexString(hashZero1)); + } + + // Check zeroed byte key of min Blowfish length is equivalent + byte[] hashZero4 = BCrypt.Generate(new byte[4], salt, 4); + if (!Arrays.AreEqual(hashEmpty, hashZero4)) + { + Fail("Hash for empty password should equal zeroed key[4]", Hex.ToHexString(hashEmpty), + Hex.ToHexString(hashZero4)); + } + + // Check BCrypt isn't padding too small (32 bit) keys + byte[] hashA = BCrypt.Generate(new byte[]{(byte)'a'}, salt, 4); + byte[] hashA0 = BCrypt.Generate(new byte[]{(byte)'a', (byte)0}, salt, 4); + if (Arrays.AreEqual(hashA, hashA0)) + { + Fail("Small keys should not be 0 padded."); + } + } + + public void DoTestParameters() + { + CheckOK("Empty key", new byte[0], new byte[16], 4); + CheckOK("Minimal values", new byte[1], new byte[16], 4); + //CheckOK("Max cost", new byte[1], new byte[16], 31); + CheckOK("Max passcode", new byte[72], new byte[16], 4); + CheckIllegal("Null password", null, new byte[16], 4); + CheckIllegal("Null salt", new byte[1], null, 4); + CheckIllegal("Salt too small", new byte[1], new byte[15], 4); + CheckIllegal("Salt too big", new byte[1], new byte[17], 4); + CheckIllegal("Cost too low", new byte[16], new byte[16], 3); + CheckIllegal("Cost too high", new byte[16], new byte[16], 32); + CheckIllegal("Passcode too long", new byte[73], new byte[16], 32); + } + + private void CheckOK(string msg, byte[] pass, byte[] salt, int cost) + { + try + { + BCrypt.Generate(pass, salt, cost); + } + catch (ArgumentException e) + { + Console.Error.WriteLine(e.StackTrace); + Fail(msg); + } + } + + private void CheckIllegal(String msg, byte[] pass, byte[] salt, int cost) + { + try + { + BCrypt.Generate(pass, salt, cost); + Fail(msg); + } + catch (ArgumentException) + { + // Expected + } + } + + public void DoTestVectors() + { + foreach (object[] v in TestVectorData) + { + byte[] password = Hex.Decode((string)v[0]); + byte[] salt = Hex.Decode((string)v[1]); + int cost = (int)v[2]; + byte[] expected = Hex.Decode((string)v[3]); + + DoTest(password, salt, cost, expected); + } + + } + + private void DoTest(byte[] password, byte[] salt, int cost, byte[] expected) + { + byte[] hash = BCrypt.Generate(password, salt, cost); + if (!Arrays.AreEqual(hash, expected)) + { + Fail("Hash for " + Hex.ToHexString(password), Hex.ToHexString(expected), Hex.ToHexString(hash)); + } + } + + public static void Main(string[] args) + { + RunTest(new BCryptTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs b/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs new file mode 100644 index 000000000..8501588ee --- /dev/null +++ b/crypto/test/src/crypto/test/OpenBsdBCryptTest.cs @@ -0,0 +1,147 @@ +using System; + +using NUnit.Framework; + +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tests +{ + [TestFixture] + public class OpenBsdBCryptTest + : SimpleTest + { + private static readonly string[][] BCryptTest1 = // vectors from http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/crypt_blowfish/wrapper.c?rev=HEAD + { + new string[]{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", "U*U"}, + new string[]{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", "U*U*"}, + new string[]{"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", "U*U*U"}, + new string[]{"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", ""}, + new string[]{"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", + "0123456789abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + "chars after 72 are ignored"}, + }; + + private static readonly string[] BCryptTest2 = { // from: http://openwall.info/wiki/john/sample-hashes + "$2a$05$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe", "password" + }; + + private static readonly string[] BCryptTest2b = { // from: http://stackoverflow.com/questions/11654684/verifying-a-bcrypt-hash + "$2a$10$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle", "ππππππππ" + }; + + private static readonly string[][] BCryptTest3 = // from: https://bitbucket.org/vadim/bcrypt.net/src/464c41416dc9/BCrypt.Net.Test/TestBCrypt.cs - plain - salt - expected + { + new string[]{"", "$2a$06$DCq7YPn5Rq63x1Lad4cll.", "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s."}, + new string[]{"", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye"}, + new string[]{"", "$2a$10$k1wbIrmNyFAPwPVPSVa/ze", "$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW"}, + new string[]{"", "$2a$12$k42ZFHFWqBp3vWli.nIn8u", "$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO"}, + new string[]{"a", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe"}, + new string[]{"a", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfe", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V."}, + new string[]{"a", "$2a$10$k87L/MF28Q673VKh8/cPi.", "$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u"}, + new string[]{"a", "$2a$12$8NJH3LsPrANStV6XtBakCe", "$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS"}, + new string[]{"abc", "$2a$06$If6bvum7DFjUnE9p2uDeDu", "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i"}, + new string[]{"abc", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7O", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm"}, + new string[]{"abc", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi"}, + new string[]{"abc", "$2a$12$EXRkfkdmXn2gzds2SSitu.", "$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q"}, + new string[]{"abcdefghijklmnopqrstuvwxyz", "$2a$06$.rCVZVOThsIa97pEDOxvGu", "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC"}, + new string[]{"abcdefghijklmnopqrstuvwxyz", "$2a$08$aTsUwsyowQuzRrDqFflhge", "$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz."}, + new string[]{"abcdefghijklmnopqrstuvwxyz", "$2a$10$fVH8e28OQRj9tqiDXs1e1u", "$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq"}, + new string[]{"abcdefghijklmnopqrstuvwxyz", "$2a$12$D4G5f18o7aMMfwasBL7Gpu", "$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG"}, + new string[]{"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$06$fPIsBO8qRqkjj273rfaOI.", "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO"}, + new string[]{"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$08$Eq2r4G/76Wv39MzSX262hu", "$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW"}, + new string[]{"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS"}, + new string[]{"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$12$WApznUOJfkEGSmYRfnkrPO", "$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC"}, + }; + + private static readonly string[][] BCryptTest4 = { // from: https://github.com/ChrisMcKee/cryptsharp/blob/master/Tests/vectors/BCrypt.txt + new string[]{"n6HyjrYTo/r4lgjvM7L<`iM", "$2a$07$XPrYfnqc5ankSHnRfmPVu.A0trKq3VdczdbJjKaWIksKF.GfFCxv."}, + new string[]{"~s0quB/K8zRtRT:QtZr`s|^O", "$2a$07$5zzz8omiaStXwOetWwlmuePPRwUt0jhNBPYGGgAMcUDvqsGVqv9Cy"}, + new string[]{"r>8y3uE}6<7nI34?Q2rR0JEw", "$2a$07$k5AH9bO9aplPYdZMZ155qOcY1FewMXcupWewW6fViUtsVQ2Umg6LS"}, + new string[]{">l_7}xxH3|Cr{dCR[HTUN@k~", "$2a$05$24xz81ZZsMUMm940bbWMCeHsO.s6A3MG0JZzm4y3.Ti6P96bz6RN6"}, + new string[]{"D`lCFYTe9_8IW6nEB:oPjEk/S", "$2a$05$bA1xkp4NqFvDmtQJtDO9CugW0INxQLpMZha8AaHmBj9Zg9HlfQtBa"}, + new string[]{"UBGYU6|a|RpA:bp[;}p.ZY4f1", "$2a$08$gu4KBnkla.bEqHiwaJ8.z.0ixfzE1Q0/iPfmpfRmUA.NUhUdZboxa"}, + new string[]{"O9X[kP6{63F3rXKtN>n?zh2_", "$2a$04$yRZW9xEsqN9DL19jveqFyO1bljZ0r5KNCYqQzMqYpDB7XHWqDWNGC"}, + new string[]{":Sa:BknepsG}\\5dOj>kh0KAk", "$2a$04$KhDTFUlakUsPNuLQSgyr7.xQZxkTSIvo0nFw0XyjvrH6n5kZkYDLG"},// extra escape sequence added + new string[]{"2_9J6k:{z?SSjCzL/GT/5CMgc", "$2a$05$eN1jCXDxN9HmuIARJlwH4ewsEyYbAmq7Cw99gEHqGRXtWyrRNLScy"}, + + new string[]{"2KNy`Kodau14?s8XVru<IIw0eDw|.64MM^Wtv;3sfZt~3`2QN6/U]0^1HtETqWHt<lMfD-LX::zo7AcNLQ.Q.@.g5kX`j7hRi", "$2a$04$xUNE1aUuNlpNwSOuz1VpjuBgW95ImLccIquQxyGLeinucvokg2Ale"}, + new string[]{"0yWE>E;h/kdCRd@T]fQiv`Vz]KC0zaIAIeyY4zcooQ0^DfP{hHsw9?atO}CxbkbnK-LxUe;|FiBEluVqO@ysHhXQDdXPt0p", "$2a$07$pNHi/IxrSUohtsD5/eIv4O324ZPGfJE7mUAaNpIPkpyxjW9kqIk76"}, + new string[]{"ilWj~2mLBa1Pq`sxrW8fNNq:XF0@KP5RLW9u?[E_wwkROmCSWudYoS5I2HGI-1-?Pd0zVxTIeNbF;nLDUGtce{8dHmx90:;N<8", "$2a$07$ePVgkQl8QKSG2Xv6o0bnOe4SZp4ejag5CP44tjxfmY17F5VzRgwF6"}, + new string[]{"dj~OsXmQGj6FXnPGgwg9]G@75~L@G[|e<hgh2vaNqIyYZPh@M;I1DTgZS/~Q:i[6d]oei:hBw4}{}y7k9K^4SoN}wb8mrg[", "$2a$04$BZT7YoAYAgtNkD0/BOl.jOi0dDni7WtmB8.wAebHeHkOs.TpRgml."}, + new string[]{"7;PjW]RYJoZXf.r2M^Mm1jVIe0wJ=Kdd2iUBuu1v3HGI1-S[TB6yg{0~:nbpeA08dysS5d}@Oxbrpj[~i-60mpq1WZqQmSVpnR", "$2a$07$fa9NDzoPKiSWC67cP/tj2OqE0PqvGwzRoJiCKj.czyqKyvpdtVpKe"}, + new string[]{"8nv;PAN~-FQ]Emh@.TKG=^.t8R0EQC0T?x9|9g4xzxYmSbBO1qDx8kv-ehh0IBv>3KWhz.Z~jUF0tt8[5U@8;5:=[v6pf.IEJ", "$2a$08$eXo9KDc1BZyybBgMurpcD.GA1/ch3XhgBnIH10Xvjc2ogZaGg3t/m"}, + }; + + public override string Name + { + get { return "OpenBsdBCrypt"; } + } + + public override void PerformTest() + { + string encoded, password; + + for (int i = 0; i < BCryptTest1.Length; i++) + { + string[] testString = BCryptTest1[i]; + encoded = testString[0]; + password = testString[1]; + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("test1 mismatch: " + "[" + i + "] " + password); + } + } + + encoded = BCryptTest2[0]; + password = BCryptTest2[1]; + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("bcryptTest2 mismatch: " + password); + } + + encoded = BCryptTest2b[0]; + password = BCryptTest2b[1]; + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("bcryptTest2b mismatch: " + password); + } + + for (int i = 0; i < BCryptTest3.Length; i++) + { + string[] testString = BCryptTest3[i]; + encoded = testString[2]; + password = testString[0]; + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("test3 mismatch: " + "[" + i + "] " + password); + } + } + + for (int i = 0; i < BCryptTest4.Length; i++) + { + string[] testString = BCryptTest4[i]; + encoded = testString[1]; + password = testString[0]; + if (!OpenBsdBCrypt.CheckPassword(encoded, password.ToCharArray())) + { + Fail("test4 mismatch: " + "[" + i + "] " + password); + } + } + } + + public static void Main(string[] args) + { + RunTest(new OpenBsdBCryptTest()); + } + + [Test] + public void TestFunction() + { + string resultText = Perform().ToString(); + + Assert.AreEqual(Name + ": Okay", resultText); + } + } +} diff --git a/crypto/test/src/crypto/test/RegressionTest.cs b/crypto/test/src/crypto/test/RegressionTest.cs index ea9fd84f2..3611e4e63 100644 --- a/crypto/test/src/crypto/test/RegressionTest.cs +++ b/crypto/test/src/crypto/test/RegressionTest.cs @@ -122,19 +122,18 @@ namespace Org.BouncyCastle.Crypto.Tests new NonMemoableDigestTest(), new StreamCipherResetTest(), new SM3DigestTest(), + new BCryptTest(), + new OpenBsdBCryptTest(), new X931SignerTest(), new KeccakDigestTest(), new ShakeDigestTest(), }; - public static void Main( - string[] args) + public static void Main(string[] args) { - for (int i = 0; i != tests.Length; i++) + foreach (ITest test in tests) { - ITestResult result = tests[i].Perform(); - - Console.WriteLine(result); + SimpleTest.RunTest(test); } } } |