8141039: Test Task: Develop new tests for JEP 273: DRBG-Based SecureRandom Implementations

Reviewed-by: weijun
This commit is contained in:
Sibabrata Sahoo 2016-05-19 04:20:08 -07:00
parent 8aff72ba65
commit 19c7dcc012
8 changed files with 1297 additions and 61 deletions

View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8141039
* @library /lib/testlibrary
* @summary This test do API coverage for SecureRandom. It covers most of
* supported operations along with possible positive and negative
* parameters for DRBG mechanism.
* @run main ApiTest Hash_DRBG
* @run main ApiTest HMAC_DRBG
* @run main ApiTest CTR_DRBG
* @run main ApiTest SHA1PRNG
* @run main ApiTest NATIVE
*/
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.SecureRandomParameters;
import java.security.DrbgParameters;
import java.security.DrbgParameters.Instantiation;
import java.security.DrbgParameters.Capability;
import javax.crypto.Cipher;
public class ApiTest {
private static final boolean SHOULD_PASS = true;
private static final long SEED = 1l;
private static final String INVALID_ALGO = "INVALID";
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
public static void main(String[] args) throws Exception {
if (args == null || args.length < 1) {
throw new RuntimeException("No mechanism available to run test.");
}
String mech
= "NATIVE".equals(args[0]) ? supportedNativeAlgo() : args[0];
String[] algs = null;
boolean success = true;
try {
if (!isDRBG(mech)) {
SecureRandom random = SecureRandom.getInstance(mech);
verifyAPI(random, mech);
return;
} else if (mech.equals("CTR_DRBG")) {
algs = new String[]{"AES-128", "AES-192", "AES-256",
INVALID_ALGO};
} else if (mech.equals("Hash_DRBG") || mech.equals("HMAC_DRBG")) {
algs = new String[]{"SHA-224", "SHA-256", "SHA-512/224",
"SHA-512/256", "SHA-384", "SHA-512", INVALID_ALGO};
} else {
throw new RuntimeException(
String.format("Not a valid mechanism '%s'", mech));
}
runForEachMech(mech, algs);
} catch (Exception e) {
e.printStackTrace(System.out);
success = false;
}
if (!success) {
throw new RuntimeException("At least one test failed.");
}
}
/**
* Run the test for a DRBG mechanism with a possible set of parameter
* combination.
* @param mech DRBG mechanism name
* @param algs Algorithm supported by each mechanism
* @throws Exception
*/
private static void runForEachMech(String mech, String[] algs)
throws Exception {
for (String alg : algs) {
runForEachAlg(mech, alg);
}
}
private static void runForEachAlg(String mech, String alg)
throws Exception {
for (int strength : new int[]{Integer.MIN_VALUE, -1, 0, 1, 223, 224,
192, 255, 256}) {
for (Capability cp : Capability.values()) {
for (byte[] pr : new byte[][]{null, new byte[]{},
"personal".getBytes()}) {
SecureRandomParameters param
= DrbgParameters.instantiation(strength, cp, pr);
runForEachParam(mech, alg, param);
}
}
}
}
private static void runForEachParam(String mech, String alg,
SecureRandomParameters param) throws Exception {
for (boolean df : new Boolean[]{true, false}) {
try {
Security.setProperty(DRBG_CONFIG, mech + "," + alg + ","
+ (df ? "use_df" : "no_df"));
System.out.printf("%nParameter for SecureRandom "
+ "mechanism: %s is (param:%s, algo:%s, df:%s)",
mech, param, alg, df);
SecureRandom sr = SecureRandom.getInstance("DRBG", param);
verifyAPI(sr, mech);
} catch (NoSuchAlgorithmException e) {
// Verify exception status for current test.
checkException(getDefaultAlg(mech, alg), param, e);
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
}
}
/**
* Returns the algorithm supported for input mechanism.
* @param mech Mechanism name
* @param alg Algorithm name
* @return Algorithm name
*/
private static String getDefaultAlg(String mech, String alg)
throws NoSuchAlgorithmException {
if (alg == null) {
switch (mech) {
case "Hash_DRBG":
case "HMAC_DRBG":
return "SHA-256";
case "CTR_DRBG":
return (Cipher.getMaxAllowedKeyLength("AES") < 256)
? "AES-128" : "AES-256";
default:
throw new RuntimeException("Mechanism not supported");
}
}
return alg;
}
/**
* Verify the exception type either it is expected to occur or not.
* @param alg Algorithm name
* @param param DRBG parameter
* @param e Exception to verify
* @throws NoSuchAlgorithmException
*/
private static void checkException(String alg, SecureRandomParameters param,
NoSuchAlgorithmException e) throws NoSuchAlgorithmException {
int strength = ((Instantiation) param).getStrength();
boolean error = true;
switch (alg) {
case INVALID_ALGO:
error = false;
break;
case "SHA-224":
case "SHA-512/224":
if (strength > 192) {
error = false;
}
break;
case "SHA-256":
case "SHA-512/256":
case "SHA-384":
case "SHA-512":
if (strength > 256) {
error = false;
}
break;
case "AES-128":
case "AES-192":
case "AES-256":
int algoStrength = Integer.parseInt(alg.replaceAll("AES-", ""));
int maxStrengthSupported = Cipher.getMaxAllowedKeyLength("AES");
if (strength > maxStrengthSupported
|| algoStrength > maxStrengthSupported) {
error = false;
}
break;
}
if (error) {
throw new RuntimeException("Unknown :", e);
}
}
/**
* Find if the mechanism is a DRBG mechanism.
* @param mech Mechanism name
* @return True for DRBG mechanism else False
*/
private static boolean isDRBG(String mech) {
return mech.contains("_DRBG");
}
/**
* Find the name of supported native mechanism name for current platform.
*/
private static String supportedNativeAlgo() {
String nativeSr = "Windows-PRNG";
try {
SecureRandom.getInstance(nativeSr);
} catch (NoSuchAlgorithmException e) {
nativeSr = "NativePRNG";
}
return nativeSr;
}
/**
* Test a possible set of SecureRandom API for a SecureRandom instance.
* @param random SecureRandom instance
* @param mech Mechanism used to create SecureRandom instance
*/
private static void verifyAPI(SecureRandom random, String mech)
throws Exception {
System.out.printf("%nTest SecureRandom mechanism: %s for provider: %s",
mech, random.getProvider().getName());
byte[] output = new byte[2];
// Generate random number.
random.nextBytes(output);
// Seed the SecureRandom with a generated seed value of lesser size.
byte[] seed = random.generateSeed(1);
random.setSeed(seed);
random.nextBytes(output);
// Seed the SecureRandom with a fixed seed value.
random.setSeed(SEED);
random.nextBytes(output);
// Seed the SecureRandom with a larger seed value.
seed = random.generateSeed(128);
random.setSeed(seed);
random.nextBytes(output);
// Additional operation only supported for DRBG based SecureRandom.
// Execute the code block and expect to pass for DRBG. If it will fail
// then it should fail with specified exception type. Else the case
// will be considered as a test case failure.
matchExc(() -> {
random.reseed();
random.nextBytes(output);
},
isDRBG(mech),
UnsupportedOperationException.class,
String.format("PASS - Unsupported reseed() method for "
+ "SecureRandom Algorithm %s ", mech));
matchExc(() -> {
random.reseed(DrbgParameters.reseed(false, new byte[]{}));
random.nextBytes(output);
},
isDRBG(mech),
UnsupportedOperationException.class,
String.format("PASS - Unsupported reseed(param) method for "
+ "SecureRandom Algorithm %s ", mech));
matchExc(() -> {
random.reseed(DrbgParameters.reseed(true, new byte[]{}));
random.nextBytes(output);
},
isDRBG(mech),
!isSupportPR(mech, random) ? IllegalArgumentException.class
: UnsupportedOperationException.class,
String.format("PASS - Unsupported or illegal reseed(param) "
+ "method for SecureRandom Algorithm %s ", mech));
matchExc(() -> random.nextBytes(output,
DrbgParameters.nextBytes(-1, false, new byte[]{})),
isDRBG(mech),
UnsupportedOperationException.class,
String.format("PASS - Unsupported nextBytes(out, nextByteParam)"
+ " method for SecureRandom Algorithm %s ", mech));
matchExc(() -> random.nextBytes(output,
DrbgParameters.nextBytes(-1, true, new byte[]{})),
isDRBG(mech),
!isSupportPR(mech, random) ? IllegalArgumentException.class
: UnsupportedOperationException.class,
String.format("PASS - Unsupported or illegal "
+ "nextBytes(out, nextByteParam) method for "
+ "SecureRandom Algorithm %s ", mech));
matchExc(() -> {
random.reseed(null);
random.nextBytes(output);
},
!SHOULD_PASS,
IllegalArgumentException.class,
"PASS - Test is expected to fail when parameter for reseed() "
+ "is null");
matchExc(() -> random.nextBytes(output, null),
!SHOULD_PASS,
IllegalArgumentException.class,
"PASS - Test is expected to fail when parameter for nextBytes()"
+ " is null");
}
private static boolean isSupportPR(String mech, SecureRandom random) {
return (isDRBG(mech) && ((Instantiation) random.getParameters())
.getCapability()
.supportsPredictionResistance());
}
private interface RunnableCode {
void run() throws Exception;
}
/**
* Execute a given code block and verify, if the exception type is expected.
* @param r Code block to run
* @param ex Expected exception type
* @param shouldPass If the code execution expected to pass without failure
* @param msg Message to log in case of expected failure
*/
private static void matchExc(RunnableCode r, boolean shouldPass, Class ex,
String msg) {
try {
r.run();
if (!shouldPass) {
throw new RuntimeException("Excecution should fail here.");
}
} catch (Exception e) {
System.out.printf("%nOccured exception: %s - Expected exception: "
+ "%s : ", e.getClass(), ex.getCanonicalName());
if (ex.isAssignableFrom(e.getClass())) {
System.out.printf("%n%s : Expected Exception occured: %s : ",
e.getClass(), msg);
} else if (shouldPass) {
throw new RuntimeException(e);
} else {
System.out.printf("Ignore the following exception: %s%n",
e.getMessage());
}
}
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8141039
* @library /lib/testlibrary
* @summary Check SecureRandom generate expected seed counts what the caller
* asked for.
* @run main EnoughSeedTest
*/
import java.security.SecureRandom;
import java.security.Security;
import static java.lang.Math.*;
public class EnoughSeedTest {
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
public static void main(String[] args) {
boolean success = true;
for (String mech : new String[]{
"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
System.out.printf("%nTest for SecureRandom algorithm: '%s'", mech);
try {
SecureRandom sr = null;
if (!mech.contains("_DRBG")) {
sr = SecureRandom.getInstance(mech);
} else {
Security.setProperty(DRBG_CONFIG, mech);
sr = SecureRandom.getInstance("DRBG");
}
success &= forEachSeedBytes(sr);
System.out.printf("%nCompleted test for SecureRandom "
+ "mechanism: '%s'", mech);
} catch (Exception e) {
success &= false;
e.printStackTrace(System.out);
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
}
if (!success) {
throw new RuntimeException("At least one test failed.");
}
}
/**
* Generates fixed number of seed bytes through a SecureRandom instance
* to verify it's seed generation status.
* @param sr SecureRandom instance
* @return The test success indicator
*/
private static boolean forEachSeedBytes(SecureRandom sr) {
boolean success = true;
sr.setSeed(1l);
for (int seedByte : new int[]{Integer.MIN_VALUE, -1, 0, 1, 256, 1024,
Short.MAX_VALUE, (int) pow(2, 20)}) {
try {
byte[] seed = sr.generateSeed(seedByte);
if (seed.length != seedByte) {
throw new RuntimeException("Not able to produce expected "
+ "seed size.");
}
} catch (IllegalArgumentException e) {
if (seedByte >= 0) {
throw new RuntimeException("Unknown Exception occured.", e);
}
System.out.printf("%nPASS - Exception expected when required "
+ "seed size requested is negative: %s", seedByte);
}
}
return success;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,49 +23,54 @@
/**
* @test
* @bug 4915392
* @bug 4915392 8141039
* @summary test that the getAlgorithm() method works correctly
* @author Andreas Sterbenz
* @run main GetAlgorithm
*/
import java.io.*;
import java.security.*;
import java.util.Arrays;
import java.util.List;
public class GetAlgorithm {
private final static String BASE = System.getProperty("test.src", ".");
private static final String BASE = System.getProperty("test.src", ".");
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
public static void main(String[] args) throws Exception {
SecureRandom sr;
sr = new SecureRandom();
SecureRandom sr = new SecureRandom();
if (sr.getAlgorithm().equals("unknown")) {
throw new Exception("Unknown: " + sr.getAlgorithm());
}
sr = SecureRandom.getInstance("SHA1PRNG");
check("SHA1PRNG", sr);
for (String mech : new String[]{supportedNativeAlgo(), "SHA1PRNG",
"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
if (!mech.contains("_DRBG")) {
check(mech, SecureRandom.getInstance(mech));
} else {
try {
Security.setProperty(DRBG_CONFIG, mech);
check("DRBG", SecureRandom.getInstance("DRBG"));
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
}
}
check("unknown", new MySecureRandom());
// OutputStream out = new FileOutputStream("sha1prng.bin");
// ObjectOutputStream oout = new ObjectOutputStream(out);
// sr.nextInt();
// oout.writeObject(sr);
// oout.flush();
// oout.close();
sr = new MySecureRandom();
check("unknown", sr);
InputStream in = new FileInputStream(new File(BASE, "sha1prng-old.bin"));
InputStream in = new FileInputStream(
new File(BASE, "sha1prng-old.bin"));
ObjectInputStream oin = new ObjectInputStream(in);
sr = (SecureRandom)oin.readObject();
sr = (SecureRandom) oin.readObject();
oin.close();
check("unknown", sr);
in = new FileInputStream(new File(BASE, "sha1prng-new.bin"));
oin = new ObjectInputStream(in);
sr = (SecureRandom)oin.readObject();
sr = (SecureRandom) oin.readObject();
oin.close();
check("SHA1PRNG", sr);
@ -83,4 +88,17 @@ public class GetAlgorithm {
}
/**
* Find the name of supported native mechanism name for current platform.
*/
private static String supportedNativeAlgo() {
String nativeSr = "Windows-PRNG";
try {
SecureRandom.getInstance(nativeSr);
} catch (NoSuchAlgorithmException e) {
nativeSr = "NativePRNG";
}
return nativeSr;
}
}

View File

@ -0,0 +1,312 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8141039
* @library /lib/testlibrary
* @summary SecureRandom supports multiple getInstance method including
* getInstanceStrong() method. This test verifies a set of possible
* cases for getInstance with different SecureRandom mechanism
* supported in Java.
* @run main GetInstanceTest
*/
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.SecureRandomParameters;
import java.security.DrbgParameters;
import static java.security.DrbgParameters.Capability.*;
import java.security.Security;
import java.util.Arrays;
import jdk.testlibrary.Asserts;
public class GetInstanceTest {
private static final boolean PASS = true;
private static final String INVALID_ALGO = "INVALID";
private static final String SUN_PROVIDER = "SUN";
private static final String INVALID_PROVIDER = "INVALID";
private static final String STRONG_ALG_SEC_PROP
= "securerandom.strongAlgorithms";
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
public static void main(String[] args) throws Exception {
boolean success = true;
// Only accepted failure is NoSuchAlgorithmException.
// For any other failure the test case will fail here.
SecureRandom sr = matchExc(() -> SecureRandom.getInstanceStrong(),
PASS, NoSuchAlgorithmException.class,
"PASS - Undefined security Property "
+ "'securerandom.strongAlgorithms'");
System.out.format("Current platform supports mechanism: '%s' through "
+ "provider: '%s' for the method getInstanceStrong().",
sr.getAlgorithm(), sr.getProvider().getName());
// DRBG name should appear with "securerandom.strongAlgorithms"
// security property.
String origDRBGConfig = Security.getProperty(STRONG_ALG_SEC_PROP);
if (!origDRBGConfig.contains("DRBG")) {
throw new RuntimeException("DRBG is not associated with default "
+ "strong algorithm through security Property: "
+ "'securerandom.strongAlgorithms'.");
}
Security.setProperty(STRONG_ALG_SEC_PROP, "DRBG:SUN");
sr = matchExc(() -> SecureRandom.getInstanceStrong(),
PASS, NoSuchAlgorithmException.class,
"PASS - Undefined security Property "
+ "'securerandom.strongAlgorithms'");
checkAttributes(sr, "DRBG");
Security.setProperty(STRONG_ALG_SEC_PROP, origDRBGConfig);
for (String mech : new String[]{
"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG", INVALID_ALGO,}) {
System.out.printf("%nTest SecureRandom mechanism: '%s'", mech);
try {
if (isDRBG(mech)) {
Security.setProperty(DRBG_CONFIG, mech);
}
verifyInstance(mech);
} catch (Exception e) {
e.printStackTrace(System.out);
success = false;
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
}
if (!success) {
throw new RuntimeException("At least one test failed.");
}
}
private static void verifyInstance(String mech) throws Exception {
String srAlgo = isDRBG(mech) ? "DRBG" : mech;
// Test for getInstance(algorithm) method.
// It should pass for all case other than invalid algorithm name.
// If it fails then the expected exception type should be
// NoSuchAlgorithmException. Any other Exception type occured will be
// treated as failure.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo), !(nsa(mech)),
NoSuchAlgorithmException.class,
String.format("PASS - It is expected to fail for"
+ " getInstance(algorithm) when algorithm: '%s'"
+ " is null or invalid.", mech)), mech);
// Test for getInstance(algorithm, provider) method.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo,
Security.getProvider(SUN_PROVIDER)),
!(nsa(mech)),
NoSuchAlgorithmException.class,
String.format("PASS - It is expected to fail for"
+ " getInstance(algorithm, provider) when"
+ " algorithm:'%s' is null or invalid.", mech)),
mech);
// Test for getInstance(algorithm, providerName) method.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, SUN_PROVIDER),
!(nsa(mech)), NoSuchAlgorithmException.class,
String.format("PASS - It is expected to fail for "
+ "getInstance(algorithm, providerName) when "
+ "algorithm: '%s' is null or invalid.", mech)),
mech);
// Test for getInstance(algorithm, providerName) method.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(
srAlgo, INVALID_PROVIDER),
!PASS, NoSuchProviderException.class,
String.format("PASS - It is expected to fail for "
+ "getInstance(algorithm, providerName) when "
+ "provider name: '%s' is invalid and "
+ "algorithm: '%s'", INVALID_PROVIDER, mech)),
mech);
// Run the test for a set of SecureRandomParameters
for (SecureRandomParameters param : Arrays.asList(null,
DrbgParameters.instantiation(-1, NONE, null))) {
System.out.printf("%nRunning DRBG param getInstance() methods "
+ "for algorithm: %s and DRBG param type: %s", mech,
(param != null) ? param.getClass().getName() : param);
// Following Test are applicable for new DRBG methods only.
// Test for getInstance(algorithm, params) method.
// Tests are expected to pass for DRBG type with valid parameter
// If it fails the expected exception type is derived from
// getExcType(mech, param) method. If exception type is not
// expected then the test will be considered as failure.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, param),
(isDRBG(mech)) && (isValidDRBGParam(param)),
getExcType(mech, param),
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params) "
+ "for algorithm: %s and parameter: %s",
mech, param)),
mech);
// Test for getInstance(algorithm, params, provider) method.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, param,
Security.getProvider(SUN_PROVIDER)),
(isDRBG(mech)) && (isValidDRBGParam(param)),
getExcType(mech, param),
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params, "
+ "provider) for algorithm: %s and "
+ "parameter: %s", mech, param)),
mech);
// Test for getInstance(algorithm, params, providerName) method.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, param,
SUN_PROVIDER),
(isDRBG(mech)) && (isValidDRBGParam(param)),
getExcType(mech, param),
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params, "
+ "providerName) for algorithm: %s and "
+ "parameter: %s", mech, param)), mech);
// getInstance(algorithm, params, providerName) when
// providerName is invalid
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, param,
INVALID_PROVIDER),
!PASS, ((param == null)
? IllegalArgumentException.class
: NoSuchProviderException.class),
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params, "
+ "providerName) when param is null or"
+ " provider: %s is invalid for "
+ "algorithm: '%s'", INVALID_PROVIDER,
mech)), mech);
// getInstance(algorithm, params, provider) when provider=null
checkAttributes(
matchExc(() -> SecureRandom.getInstance(srAlgo, param,
(String) null),
!PASS, IllegalArgumentException.class,
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params, "
+ "providerName) when provider name "
+ "is null")), mech);
// getInstance(algorithm, params, providerName) when
// providerName is empty.
checkAttributes(
matchExc(() -> SecureRandom.getInstance(
srAlgo, param, ""),
!PASS, IllegalArgumentException.class,
String.format("PASS - It is expected to fail "
+ "for getInstance(algorithm, params, "
+ "providerName) when provider name "
+ "is empty")), mech);
}
}
private static boolean isValidDRBGParam(SecureRandomParameters param) {
return (param instanceof DrbgParameters.Instantiation);
}
/**
* If the mechanism should occur NoSuchAlgorithmException.
*/
private static boolean nsa(String mech) {
return mech.equals(INVALID_ALGO);
}
/**
* Verify if the mechanism is DRBG type.
* @param mech Mechanism name
* @return True if the mechanism name is DRBG type else False.
*/
private static boolean isDRBG(String mech) {
return mech.contains("_DRBG");
}
/**
* Type of exception expected for a SecureRandom instance when exception
* occurred while calling getInstance method with a fixed set of parameter.
* @param mech Mechanism used to create a SecureRandom instance
* @param param Parameter to getInstance() method
* @return Exception type expected
*/
private static Class getExcType(String mech, SecureRandomParameters param) {
return ((isDRBG(mech) && !isValidDRBGParam(param)) || param == null)
? IllegalArgumentException.class
: NoSuchAlgorithmException.class;
}
private interface RunnableCode {
SecureRandom run() throws Exception;
}
/**
* Execute a given code block and verify, if the exception type is expected.
* @param r Code block to run
* @param ex Expected exception type
* @param shouldPass If the code execution expected to pass without failure
* @param msg Message to log in case of expected failure
*/
private static SecureRandom matchExc(RunnableCode r, boolean shouldPass,
Class ex, String msg) {
SecureRandom sr = null;
try {
sr = r.run();
if (!shouldPass) {
throw new RuntimeException("Excecution should fail here.");
}
} catch (Exception e) {
System.out.printf("%nOccured exception: %s - Expected exception: %s"
+ " : ", e.getClass(), ex.getCanonicalName());
if (ex.isAssignableFrom(e.getClass())) {
System.out.printf("%n%s : Expected Exception: %s : ",
e.getClass(), msg);
} else if (shouldPass) {
throw new RuntimeException(e);
} else {
System.out.printf("%nIgnore the following exception: %s%n",
e.getMessage());
}
}
return sr;
}
/**
* Check specific attributes of a SecureRandom instance.
*/
private static void checkAttributes(SecureRandom sr, String mech) {
if (sr == null) {
return;
}
Asserts.assertEquals(sr.getAlgorithm(), (isDRBG(mech) ? "DRBG" : mech));
Asserts.assertEquals(sr.getProvider().getName(), SUN_PROVIDER);
}
}

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import static java.lang.Math.*;
/*
* @test
* @bug 8141039
* @library /lib/testlibrary
* @summary Test behavior of a shared SecureRandom object when it is operated
* by multiple threads concurrently.
* @run main MultiThreadTest
*/
public class MultiThreadTest {
private static final byte[] GEN_RND_BYTES = {1};
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
private enum SEED {
NONE, RESEED, SETSEED
}
public static void main(String[] args) {
boolean success = true;
for (int byteLen : GEN_RND_BYTES) {
for (SEED reSeed : SEED.values()) {
for (String mech : new String[]{
"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
try {
forEachMech(mech, byteLen, reSeed);
} catch (Exception e) {
success = false;
e.printStackTrace(System.out);
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
}
}
}
if (!success) {
throw new RuntimeException("At least one test failed.");
}
}
/**
* Generate a number of threads to fetch random numbers of certain bits
* generated through a shared SecureRandom instance.
* @param mech Mechanism name
* @param byteLen Number of bytes of random number to produce
* @param reSeed Call reseed() before generating random numbers
* @throws NoSuchAlgorithmException
* @throws InterruptedException
* @throws ExecutionException
*/
private static void forEachMech(String mech, int byteLen, SEED reSeed)
throws NoSuchAlgorithmException, InterruptedException,
ExecutionException {
if ("SHA1PRNG".equals(mech) && SEED.RESEED.equals(reSeed)) {
System.out.printf(
"%nreseed() api is not supported for '%s'", mech);
return;
}
System.out.printf("%nTest SecureRandom mechanism: '%s' with support of"
+ " reseed: '%s'", mech, reSeed);
int threadCount = (int) pow(2, 8 * byteLen);
System.out.printf("%nCreating %s number of threads to generate secure "
+ "random numbers concurrently.", threadCount);
ExecutorService executor
= Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory()
.newThread(r);
t.setDaemon(true);
return t;
}
});
CompletionService<Integer> completionService
= new ExecutorCompletionService<Integer>(executor);
CountDownLatch latch = new CountDownLatch(1);
SecureRandom rnd = null;
if (!mech.contains("_DRBG")) {
rnd = SecureRandom.getInstance(mech);
} else {
Security.setProperty(DRBG_CONFIG, mech);
rnd = SecureRandom.getInstance("DRBG");
}
try {
for (int i = 0; i < threadCount; i++) {
completionService.submit(new Task(rnd, latch, byteLen, reSeed));
}
latch.countDown();
for (int i = 0; i < threadCount; i++) {
completionService.take();
}
} finally {
executor.shutdown();
}
System.out.printf("%nCompleted Test for algorithm '%s' with thread "
+ "counts to '%s' using reseeding '%s'",
mech, threadCount, reSeed);
}
/**
* Define a Task to be executed by multiple thread to produce random numbers
* from a shared SecureRandom instance.
*/
private static class Task implements Callable<Integer> {
private final SecureRandom random;
private final CountDownLatch latch;
private final SEED reSeed;
private final int byteSize;
public Task(SecureRandom random, CountDownLatch latch, int byteSize,
SEED reSeed) {
this.random = random;
this.latch = latch;
this.byteSize = byteSize;
this.reSeed = reSeed;
}
@Override
public Integer call() throws Exception {
latch.await();
switch (this.reSeed) {
case RESEED:
this.random.reseed();
break;
case SETSEED:
this.random.setSeed(1l);
break;
}
byte[] bytes = new byte[byteSize];
random.nextBytes(bytes);
return new BigInteger(bytes).intValue();
}
}
}

View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8141039
* @library /lib/testlibrary
* @summary When random number is generated through the a SecureRandom instance
* as well from it's serialized instance in the same time then the
* generated random numbers should be different when one or both are
* reseeded.
* @run main SerializedSeedTest
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import jdk.testlibrary.Asserts;
public class SerializedSeedTest {
private static final byte[] SEED = "seed".getBytes();
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
public static void main(String[] args) {
boolean success = true;
for (String mech : new String[]{
"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
System.out.printf(
"%nRunning test for SecureRandom mechanism: '%s'", mech);
try {
// Serialize without seed and compare generated random numbers
// produced through original and serialized instances.
SecureRandom orig = getSRInstance(mech);
SecureRandom copy = deserializedCopy(orig);
System.out.printf("%nSerialize without seed. Generated random"
+ " numbers should be different.");
check(orig, copy, false, mech);
// Serialize after default seed and compare generated random
// numbers produced through original and serialized instances.
orig = getSRInstance(mech);
orig.nextInt(); // Default seeded
copy = deserializedCopy(orig);
System.out.printf("%nSerialize after default seed. Generated"
+ " random numbers should be same till 20-bytes.");
check(orig, copy, !isDRBG(mech), mech);
// Serialize after explicit seed and compare generated random
// numbers produced through original and serialized instances.
orig = getSRInstance(mech);
orig.setSeed(SEED); // Explicitly seeded
copy = deserializedCopy(orig);
System.out.printf("%nSerialize after explicit seed. Generated "
+ "random numbers should be same till 20-bytes.");
check(orig, copy, !isDRBG(mech), mech);
// Serialize without seed but original is explicitly seeded
// before generating any random number. Then compare generated
// random numbers produced through original and serialized
// instances.
orig = getSRInstance(mech);
copy = deserializedCopy(orig);
orig.setSeed(SEED); // Explicitly seeded
System.out.printf("%nSerialize without seed. When original is "
+ "explicitly seeded before generating random numbers,"
+ " Generated random numbers should be different.");
check(orig, copy, false, mech);
// Serialize after default seed but original is explicitly
// seeded before generating any random number. Then compare
// generated random numbers produced through original and
// serialized instances.
orig = getSRInstance(mech);
orig.nextInt(); // Default seeded
copy = deserializedCopy(orig);
orig.setSeed(SEED); // Explicitly seeded
System.out.printf("%nSerialize after default seed but original "
+ "is explicitly seeded before generating random number"
+ ". Generated random numbers should be different.");
check(orig, copy, false, mech);
// Serialize after explicit seed but original is explicitly
// seeded again before generating random number. Then compare
// generated random numbers produced through original and
// serialized instances.
orig = getSRInstance(mech);
orig.setSeed(SEED); // Explicitly seeded
copy = deserializedCopy(orig);
orig.setSeed(SEED); // Explicitly seeded
System.out.printf("%nSerialize after explicit seed but "
+ "original is explicitly seeded again before "
+ "generating random number. Generated random "
+ "numbers should be different.");
check(orig, copy, false, mech);
} catch (Exception e) {
e.printStackTrace(System.out);
success = false;
} finally {
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
System.out.printf("%n------Completed Test for %s------", mech);
}
if (!success) {
throw new RuntimeException("At least one test failed.");
}
}
/**
* Find if the mechanism is a DRBG mechanism.
* @param mech Mechanism name
* @return True for DRBG mechanism else False
*/
private static boolean isDRBG(String mech) {
return mech.contains("_DRBG");
}
/**
* Verify the similarity of random numbers generated though both original
* as well as deserialized instance.
*/
private static void check(SecureRandom orig, SecureRandom copy,
boolean equal, String mech) {
int o = orig.nextInt();
int c = copy.nextInt();
System.out.printf("%nRandom number generated for mechanism: '%s' "
+ "from original instance as: '%s' and from serialized "
+ "instance as: '%s'", mech, o, c);
if (equal) {
Asserts.assertEquals(o, c, mech);
} else {
Asserts.assertNotEquals(o, c, mech);
}
}
/**
* Get a copy of SecureRandom instance through deserialization.
* @param orig Original SecureRandom instance
* @return Deserialized SecureRandom instance
* @throws IOException
* @throws ClassNotFoundException
*/
private static SecureRandom deserializedCopy(SecureRandom orig)
throws IOException, ClassNotFoundException {
return deserialize(serialize(orig));
}
/**
* Deserialize the SecureRandom object.
*/
private static SecureRandom deserialize(byte[] serialized)
throws IOException, ClassNotFoundException {
SecureRandom sr = null;
try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized);
ObjectInputStream ois = new ObjectInputStream(bis)) {
sr = (SecureRandom) ois.readObject();
}
return sr;
}
/**
* Serialize the given SecureRandom object.
*/
private static byte[] serialize(SecureRandom sr) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(sr);
return bos.toByteArray();
}
}
/**
* Create a SecureRandom instance for a given mechanism.
*/
private static SecureRandom getSRInstance(String mech)
throws NoSuchAlgorithmException {
if (!isDRBG(mech)) {
return SecureRandom.getInstance(mech);
} else {
Security.setProperty(DRBG_CONFIG, mech);
return SecureRandom.getInstance("DRBG");
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -21,11 +21,11 @@
* questions.
*/
/**
/*
* @test
* @bug 6425477
* @bug 6425477 8141039
* @summary Better support for generation of high entropy random numbers
* @run main/othervm StrongSecureRandom
* @run main StrongSecureRandom
*/
import java.security.*;
import java.util.*;
@ -35,7 +35,10 @@ import java.util.*;
*/
public class StrongSecureRandom {
private static String os = System.getProperty("os.name", "unknown");
private static final String os = System.getProperty("os.name", "unknown");
private static final String DRBG_CONFIG = "securerandom.drbg.config";
private static final String DRBG_CONFIG_VALUE
= Security.getProperty(DRBG_CONFIG);
private static void testDefaultEgd() throws Exception {
// No SecurityManager installed.
@ -47,31 +50,53 @@ public class StrongSecureRandom {
}
}
private static void testSHA1PRNGImpl() throws Exception {
SecureRandom sr;
/**
* Verify if the mechanism is DRBG type.
* @param mech Mechanism name
* @return True if the mechanism name is DRBG type else False.
*/
private static boolean isDRBG(String mech) {
return mech.contains("_DRBG");
}
private static void testSecureRandomImpl(String algo, boolean drbg)
throws Exception {
byte[] ba;
final String secureRandomSource
= Security.getProperty("securerandom.source");
try {
String urandom = "file:/dev/urandom";
String urandom = "file:/dev/urandom";
System.out.println("Testing new SeedGenerator and EGD");
System.out.println("Testing new SeedGenerator and EGD");
Security.setProperty("securerandom.source", urandom);
if (!Security.getProperty("securerandom.source").equals(urandom)) {
throw new Exception("Couldn't set securerandom.source");
}
Security.setProperty("securerandom.source", urandom);
if (!Security.getProperty("securerandom.source").equals(urandom)) {
throw new Exception("Couldn't set securerandom.source");
/*
* Take out a large number of bytes in hopes of blocking.
* Don't expect this to happen, unless something is broken on Linux
*/
SecureRandom sr = null;
if (drbg) {
Security.setProperty(DRBG_CONFIG, algo);
sr = SecureRandom.getInstance("DRBG");
} else {
sr = SecureRandom.getInstance(algo);
}
if (!sr.getAlgorithm().equals(isDRBG(algo) ? "DRBG" : algo)) {
throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
}
ba = sr.generateSeed(4096);
sr.nextBytes(ba);
sr.setSeed(ba);
} finally {
Security.setProperty("securerandom.source", secureRandomSource);
Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
}
/*
* Take out a large number of bytes in hopes of blocking.
* Don't expect this to happen, unless something is broken on Linux
*/
sr = SecureRandom.getInstance("SHA1PRNG");
if (!sr.getAlgorithm().equals("SHA1PRNG")) {
throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
}
ba = sr.generateSeed(4096);
sr.nextBytes(ba);
sr.setSeed(ba);
}
private static void testNativePRNGImpls() throws Exception {
@ -85,7 +110,7 @@ public class StrongSecureRandom {
return;
}
System.out.println(" Testing regular");
System.out.println("Testing regular");
sr = SecureRandom.getInstance("NativePRNG");
if (!sr.getAlgorithm().equals("NativePRNG")) {
throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
@ -94,7 +119,7 @@ public class StrongSecureRandom {
sr.nextBytes(ba);
sr.setSeed(ba);
System.out.println(" Testing NonBlocking");
System.out.println("Testing NonBlocking");
sr = SecureRandom.getInstance("NativePRNGNonBlocking");
if (!sr.getAlgorithm().equals("NativePRNGNonBlocking")) {
throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
@ -108,7 +133,7 @@ public class StrongSecureRandom {
return;
}
System.out.println(" Testing Blocking");
System.out.println("Testing Blocking");
sr = SecureRandom.getInstance("NativePRNGBlocking");
if (!sr.getAlgorithm().equals("NativePRNGBlocking")) {
throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
@ -141,9 +166,15 @@ public class StrongSecureRandom {
throws Exception {
System.out.println("Testing: '" + property + "' " + expected);
Security.setProperty("securerandom.strongAlgorithms", property);
testStrongInstance(expected);
final String origStrongAlgoProp
= Security.getProperty("securerandom.strongAlgorithms");
try {
Security.setProperty("securerandom.strongAlgorithms", property);
testStrongInstance(expected);
} finally {
Security.setProperty(
"securerandom.strongAlgorithms", origStrongAlgoProp);
}
}
private static void testProperties() throws Exception {
@ -228,7 +259,10 @@ public class StrongSecureRandom {
public static void main(String args[]) throws Exception {
testDefaultEgd();
testSHA1PRNGImpl();
for (String algo : new String[]{
"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
testSecureRandomImpl(algo, isDRBG(algo));
}
testNativePRNGImpls();
testAllImpls();

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2011, 2016, Oracle and/or its affiliates. All rights
* reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +24,7 @@
/*
* @test
* @bug 6998583
* @bug 6998583 8141039
* @summary NativeSeedGenerator is making 8192 byte read requests from
* entropy pool on each init.
* @run main SeedGeneratorChoice
@ -39,14 +40,24 @@
* We should always fall back to the ThreadedSeedGenerator if exceptions
* are encountered with user defined source of entropy.
*/
import java.security.SecureRandom;
import java.security.Security;
public class SeedGeneratorChoice {
public static void main(String... arguments) throws Exception {
byte[] bytes;
SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
bytes = prng.generateSeed(1);
for (String mech : new String[]{"SHA1PRNG", "Hash_DRBG", "HMAC_DRBG",
"CTR_DRBG"}) {
SecureRandom prng = null;
if (!mech.contains("_DRBG")) {
prng = SecureRandom.getInstance(mech);
} else {
Security.setProperty("securerandom.drbg.config", mech);
prng = SecureRandom.getInstance("DRBG");
}
prng.generateSeed(1);
}
}
}