summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2018-04-08 17:15:10 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2018-04-08 17:15:10 +0700
commit9c25e41a757608e97edc0a0cb9443816de9d6b35 (patch)
tree024fffabcb309cf8b65e959ce752410d7237f005
parentLatest DSTU7624 updates from Java (diff)
downloadBouncyCastle.NET-ed25519-9c25e41a757608e97edc0a0cb9443816de9d6b35.tar.xz
Latest scrypt updates from bc-java
-rw-r--r--crypto/src/crypto/generators/SCrypt.cs42
-rw-r--r--crypto/test/src/crypto/test/SCryptTest.cs56
2 files changed, 86 insertions, 12 deletions
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
index efa74d735..64a36df63 100644
--- a/crypto/src/crypto/generators/SCrypt.cs
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -8,12 +8,46 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
 {
-	public class SCrypt
+    /// <summary>Implementation of the scrypt a password-based key derivation function.</summary>
+    /// <remarks>
+    /// Scrypt was created by Colin Percival and is specified in
+    /// <a href="http://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01">draft-josefsson-scrypt-kd</a>.
+    /// </remarks>
+    public class SCrypt
 	{
-		// TODO Validate arguments
-		public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
+        /// <summary>Generate a key using the scrypt key derivation function.</summary>
+        /// <param name="P">the bytes of the pass phrase.</param>
+        /// <param name="S">the salt to use for this invocation.</param>
+        /// <param name="N">CPU/Memory cost parameter. Must be larger than 1, a power of 2 and less than
+        ///     <code>2^(128 * r / 8)</code>.</param>
+        /// <param name="r">the block size, must be >= 1.</param>
+        /// <param name="p">Parallelization parameter. Must be a positive integer less than or equal to
+        ///     <code>Int32.MaxValue / (128 * r * 8)</code>.</param>
+        /// <param name="dkLen">the length of the key to generate.</param>
+        /// <returns>the generated key.</returns>
+        public static byte[] Generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
 		{
-			return MFcrypt(P, S, N, r, p, dkLen);
+            if (P == null)
+                throw new ArgumentNullException("Passphrase P must be provided.");
+            if (S == null)
+                throw new ArgumentNullException("Salt S must be provided.");
+            if (N <= 1)
+                throw new ArgumentException("Cost parameter N must be > 1.");
+            // Only value of r that cost (as an int) could be exceeded for is 1
+            if (r == 1 && N >= 65536)
+                throw new ArgumentException("Cost parameter N must be > 1 and < 65536.");
+            if (r < 1)
+                throw new ArgumentException("Block size r must be >= 1.");
+            int maxParallel = Int32.MaxValue / (128 * r * 8);
+            if (p < 1 || p > maxParallel)
+            {
+                throw new ArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
+                    + " (based on block size r of " + r + ")");
+            }
+            if (dkLen < 1)
+                throw new ArgumentException("Generated key length dkLen must be >= 1.");
+
+            return MFcrypt(P, S, N, r, p, dkLen);
 		}
 
 		private static byte[] MFcrypt(byte[] P, byte[] S, int N, int r, int p, int dkLen)
diff --git a/crypto/test/src/crypto/test/SCryptTest.cs b/crypto/test/src/crypto/test/SCryptTest.cs
index c055ab718..82bc60880 100644
--- a/crypto/test/src/crypto/test/SCryptTest.cs
+++ b/crypto/test/src/crypto/test/SCryptTest.cs
@@ -26,6 +26,54 @@ namespace Org.BouncyCastle.Crypto.Tests
 
 		public override void PerformTest()
 		{
+            TestParameters();
+            TestVectors();
+        }
+
+        [Test]
+        public void TestParameters()
+        {
+            CheckOK("Minimal values", new byte[0], new byte[0], 2, 1, 1, 1);
+            CheckIllegal("Cost parameter must be > 1", new byte[0], new byte[0], 1, 1, 1, 1);
+            CheckOK("Cost parameter 32768 OK for r == 1", new byte[0], new byte[0], 32768, 1, 1, 1);
+            CheckIllegal("Cost parameter must < 65536 for r == 1", new byte[0], new byte[0], 65536, 1, 1, 1);
+            CheckIllegal("Block size must be >= 1", new byte[0], new byte[0], 2, 0, 2, 1);
+            CheckIllegal("Parallelisation parameter must be >= 1", new byte[0], new byte[0], 2, 1, 0, 1);
+            // CheckOK("Parallelisation parameter 65535 OK for r = 4", new byte[0], new byte[0], 2, 32, 65535, 1);
+            CheckIllegal("Parallelisation parameter must be < 65535 for r = 4", new byte[0], new byte[0], 2, 32, 65536, 1);
+
+            CheckIllegal("Len parameter must be > 1", new byte[0], new byte[0], 2, 1, 1, 0);
+        }
+
+        private void CheckOK(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len)
+        {
+            try
+            {
+                SCrypt.Generate(pass, salt, N, r, p, len);
+            }
+            catch (ArgumentException e)
+            {
+                Console.Error.WriteLine(e.StackTrace);
+                Fail(msg);
+            }
+        }
+
+        private void CheckIllegal(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len)
+        {
+            try
+            {
+                SCrypt.Generate(pass, salt, N, r, p, len);
+                Fail(msg);
+            }
+            catch (ArgumentException e)
+            {
+                //Console.Error.WriteLine(e.StackTrace);
+            }
+        }
+
+        [Test]
+        public void TestVectors()
+        {
 			using (StreamReader sr = new StreamReader(SimpleTest.GetTestDataAsStream("scrypt.TestVectors.txt")))
 			{
 				int count = 0;
@@ -91,13 +139,5 @@ namespace Org.BouncyCastle.Crypto.Tests
 		{
 			RunTest(new SCryptTest());
 		}
-
-		[Test]
-		public void TestFunction()
-		{
-			string resultText = Perform().ToString();
-
-			Assert.AreEqual(Name + ": Okay", resultText);
-		}
 	}
 }