diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/SCrypt.java b/core/src/main/java/org/bouncycastle/crypto/generators/SCrypt.java index da22fa48cc..815544ee8a 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/SCrypt.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/SCrypt.java @@ -7,11 +7,62 @@ import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +/** + * Implementation of the scrypt a password-based key derivation function. + *
+ * Scrypt was created by Colin Percival and is specified in draft-josefsson-scrypt-kd
+ *
+ */
public class SCrypt
{
- // TODO Validate arguments
+ /**
+ * Generate a key using the scrypt key derivation function.
+ *
+ * @param P the bytes of the pass phrase.
+ * @param S the salt to use for this invocation.
+ * @param N CPU/Memory cost parameter. Must be larger than 1, a power of 2 and less than
+ * 2^(128 * r / 8).
+ * @param r the block size, must be >= 1.
+ * @param p Parallelization parameter. Must be a positive integer less than or equal to
+ * Integer.MAX_VALUE / (128 * r * 8).
+ *
+ * @param dkLen the length of the key to generate.
+ * @return the generated key.
+ */
public static byte[] generate(byte[] P, byte[] S, int N, int r, int p, int dkLen)
{
+ if (P== null)
+ {
+ throw new IllegalArgumentException("Passphrase P must be provided.");
+ }
+ if (S == null)
+ {
+ throw new IllegalArgumentException("Salt S must be provided.");
+ }
+ if (N <= 1)
+ {
+ throw new IllegalArgumentException("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 IllegalArgumentException("Cost parameter N must be > 1 and < 65536.");
+ }
+ if (r < 1)
+ {
+ throw new IllegalArgumentException("Block size r must be >= 1.");
+ }
+ int maxParallel = Integer.MAX_VALUE / (128 * r * 8);
+ if (p < 1 || p > maxParallel)
+ {
+ throw new IllegalArgumentException("Parallelisation parameter p must be >= 1 and <= " + maxParallel
+ + " (based on block size r of " + r + ")");
+ }
+ if (dkLen < 1)
+ {
+ throw new IllegalArgumentException("Generated key length dkLen must be >= 1.");
+ }
return MFcrypt(P, S, N, r, p, dkLen);
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SCryptTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SCryptTest.java
index 1471dafa24..b017a1da51 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/SCryptTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/SCryptTest.java
@@ -20,6 +20,54 @@ public String getName()
}
public void performTest() throws Exception
+ {
+ testParameters();
+ testVectors();
+ }
+
+ 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 65536 OK for r == 1", new byte[0], new byte[0], 65536, 1, 1, 1);
+ checkIllegal("Cost parameter must <= 65536 for r == 1", new byte[0], new byte[0], 65537, 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 (IllegalArgumentException e)
+ {
+ e.printStackTrace();
+ 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 (IllegalArgumentException e)
+ {
+ // e.printStackTrace();
+ }
+ }
+
+ public void testVectors()
+ throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(
getClass().getResourceAsStream("SCryptTestVectors.txt")));