blob: b017a1da511656b4032d96c3831ccb016885fc13 [file] [log] [blame]
package org.bouncycastle.crypto.test;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.bouncycastle.crypto.generators.SCrypt;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
/*
* scrypt test vectors from "Stronger Key Derivation Via Sequential Memory-hard Functions" Appendix B.
* (http://www.tarsnap.com/scrypt/scrypt.pdf)
*/
public class SCryptTest extends SimpleTest
{
public String getName()
{
return "SCrypt";
}
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")));
int count = 0;
String line = br.readLine();
while (line != null)
{
++count;
String header = line;
StringBuffer data = new StringBuffer();
while (!isEndData(line = br.readLine()))
{
for (int i = 0; i != line.length(); i++)
{
if (line.charAt(i) != ' ')
{
data.append(line.charAt(i));
}
}
}
int start = header.indexOf('(') + 1;
int limit = header.lastIndexOf(')');
String argStr = header.substring(start, limit);
String[] args = Strings.split(argStr, ',');
byte[] P = extractQuotedString(args[0]);
byte[] S = extractQuotedString(args[1]);
int N = extractInteger(args[2]);
int r = extractInteger(args[3]);
int p = extractInteger(args[4]);
int dkLen = extractInteger(args[5]);
byte[] expected = Hex.decode(data.toString());
// This skips very expensive test case(s), remove check to re-enable
if (N <= 16384)
{
byte[] result = SCrypt.generate(P, S, N, r, p, dkLen);
if (!areEqual(expected, result))
{
fail("Result does not match expected value in test case " + count);
}
}
}
br.close();
}
private static boolean isEndData(String line)
{
return line == null || line.startsWith("scrypt");
}
private static byte[] extractQuotedString(String arg)
{
arg = arg.trim();
arg = arg.substring(1, arg.length() - 1);
return Strings.toByteArray(arg);
}
private static int extractInteger(String arg)
{
return Integer.parseInt(arg.trim());
}
public static void main(String[] args)
{
runTest(new SCryptTest());
}
}