Path: blob/master/test/jdk/java/security/SecureRandom/ApiTest.java
41149 views
/*1* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 814103926* @library /lib/testlibrary27* @summary This test do API coverage for SecureRandom. It covers most of28* supported operations along with possible positive and negative29* parameters for DRBG mechanism.30* @run main/othervm ApiTest Hash_DRBG31* @run main/othervm ApiTest HMAC_DRBG32* @run main/othervm ApiTest CTR_DRBG33* @run main/othervm ApiTest SHA1PRNG34* @run main/othervm ApiTest NATIVE35*/36import java.security.NoSuchAlgorithmException;37import java.security.SecureRandom;38import java.security.Security;39import java.security.SecureRandomParameters;40import java.security.DrbgParameters;41import java.security.DrbgParameters.Instantiation;42import java.security.DrbgParameters.Capability;43import javax.crypto.Cipher;4445public class ApiTest {4647private static final boolean SHOULD_PASS = true;48private static final long SEED = 1l;49private static final String INVALID_ALGO = "INVALID";50private static final String DRBG_CONFIG = "securerandom.drbg.config";51private static final String DRBG_CONFIG_VALUE52= Security.getProperty(DRBG_CONFIG);5354public static void main(String[] args) throws Exception {55System.setProperty("java.security.egd", "file:/dev/urandom");5657if (args == null || args.length < 1) {58throw new RuntimeException("No mechanism available to run test.");59}60String mech61= "NATIVE".equals(args[0]) ? supportedNativeAlgo() : args[0];62String[] algs = null;63boolean success = true;6465try {66if (!isDRBG(mech)) {67SecureRandom random = SecureRandom.getInstance(mech);68verifyAPI(random, mech);69return;70} else if (mech.equals("CTR_DRBG")) {71algs = new String[]{"AES-128", "AES-192", "AES-256",72INVALID_ALGO};73} else if (mech.equals("Hash_DRBG") || mech.equals("HMAC_DRBG")) {74algs = new String[]{"SHA-224", "SHA-256", "SHA-512/224",75"SHA-512/256", "SHA-384", "SHA-512", INVALID_ALGO};76} else {77throw new RuntimeException(78String.format("Not a valid mechanism '%s'", mech));79}80runForEachMech(mech, algs);81} catch (Exception e) {82e.printStackTrace(System.out);83success = false;84}8586if (!success) {87throw new RuntimeException("At least one test failed.");88}89}9091/**92* Run the test for a DRBG mechanism with a possible set of parameter93* combination.94* @param mech DRBG mechanism name95* @param algs Algorithm supported by each mechanism96* @throws Exception97*/98private static void runForEachMech(String mech, String[] algs)99throws Exception {100for (String alg : algs) {101runForEachAlg(mech, alg);102}103}104105private static void runForEachAlg(String mech, String alg)106throws Exception {107for (int strength : new int[]{-1, 0, 1, 223, 224,108192, 255, 256}) {109for (Capability cp : Capability.values()) {110for (byte[] pr : new byte[][]{null, new byte[]{},111"personal".getBytes()}) {112SecureRandomParameters param113= DrbgParameters.instantiation(strength, cp, pr);114runForEachParam(mech, alg, param);115}116}117}118}119120private static void runForEachParam(String mech, String alg,121SecureRandomParameters param) throws Exception {122123for (boolean df : new Boolean[]{true, false}) {124try {125Security.setProperty(DRBG_CONFIG, mech + "," + alg + ","126+ (df ? "use_df" : "no_df"));127System.out.printf("%nParameter for SecureRandom "128+ "mechanism: %s is (param:%s, algo:%s, df:%s)",129mech, param, alg, df);130SecureRandom sr = SecureRandom.getInstance("DRBG", param);131verifyAPI(sr, mech);132} catch (NoSuchAlgorithmException e) {133// Verify exception status for current test.134checkException(getDefaultAlg(mech, alg), param, e);135} finally {136Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);137}138}139}140141/**142* Returns the algorithm supported for input mechanism.143* @param mech Mechanism name144* @param alg Algorithm name145* @return Algorithm name146*/147private static String getDefaultAlg(String mech, String alg)148throws NoSuchAlgorithmException {149if (alg == null) {150switch (mech) {151case "Hash_DRBG":152case "HMAC_DRBG":153return "SHA-256";154case "CTR_DRBG":155return (Cipher.getMaxAllowedKeyLength("AES") < 256)156? "AES-128" : "AES-256";157default:158throw new RuntimeException("Mechanism not supported");159}160}161return alg;162}163164/**165* Verify the exception type either it is expected to occur or not.166* @param alg Algorithm name167* @param param DRBG parameter168* @param e Exception to verify169* @throws NoSuchAlgorithmException170*/171private static void checkException(String alg, SecureRandomParameters param,172NoSuchAlgorithmException e) throws NoSuchAlgorithmException {173174int strength = ((Instantiation) param).getStrength();175boolean error = true;176switch (alg) {177case INVALID_ALGO:178error = false;179break;180case "SHA-224":181case "SHA-512/224":182if (strength > 192) {183error = false;184}185break;186case "SHA-256":187case "SHA-512/256":188case "SHA-384":189case "SHA-512":190if (strength > 256) {191error = false;192}193break;194case "AES-128":195case "AES-192":196case "AES-256":197int algoStrength = Integer.parseInt(alg.substring("AES-".length()));198int maxAESStrength = Cipher.getMaxAllowedKeyLength("AES");199if (strength > algoStrength200|| algoStrength > maxAESStrength) {201error = false;202}203break;204}205if (error) {206throw new RuntimeException("Unknown :", e);207}208}209210/**211* Find if the mechanism is a DRBG mechanism.212* @param mech Mechanism name213* @return True for DRBG mechanism else False214*/215private static boolean isDRBG(String mech) {216return mech.contains("_DRBG");217}218219/**220* Find the name of supported native mechanism name for current platform.221*/222private static String supportedNativeAlgo() {223String nativeSr = "Windows-PRNG";224try {225SecureRandom.getInstance(nativeSr);226} catch (NoSuchAlgorithmException e) {227nativeSr = "NativePRNG";228}229return nativeSr;230}231232/**233* Test a possible set of SecureRandom API for a SecureRandom instance.234* @param random SecureRandom instance235* @param mech Mechanism used to create SecureRandom instance236*/237private static void verifyAPI(SecureRandom random, String mech)238throws Exception {239240System.out.printf("%nTest SecureRandom mechanism: %s for provider: %s",241mech, random.getProvider().getName());242byte[] output = new byte[2];243244// Generate random number.245random.nextBytes(output);246247// Seed the SecureRandom with a generated seed value of lesser size.248byte[] seed = random.generateSeed(1);249random.setSeed(seed);250random.nextBytes(output);251252// Seed the SecureRandom with a fixed seed value.253random.setSeed(SEED);254random.nextBytes(output);255256// Seed the SecureRandom with a larger seed value.257seed = random.generateSeed(128);258random.setSeed(seed);259random.nextBytes(output);260261// Additional operation only supported for DRBG based SecureRandom.262// Execute the code block and expect to pass for DRBG. If it will fail263// then it should fail with specified exception type. Else the case264// will be considered as a test case failure.265matchExc(() -> {266random.reseed();267random.nextBytes(output);268},269isDRBG(mech),270UnsupportedOperationException.class,271String.format("PASS - Unsupported reseed() method for "272+ "SecureRandom Algorithm %s ", mech));273274matchExc(() -> {275random.reseed(DrbgParameters.reseed(false, new byte[]{}));276random.nextBytes(output);277},278isDRBG(mech),279UnsupportedOperationException.class,280String.format("PASS - Unsupported reseed(param) method for "281+ "SecureRandom Algorithm %s ", mech));282283matchExc(() -> {284random.reseed(DrbgParameters.reseed(true, new byte[]{}));285random.nextBytes(output);286},287isDRBG(mech),288!isSupportPR(mech, random) ? IllegalArgumentException.class289: UnsupportedOperationException.class,290String.format("PASS - Unsupported or illegal reseed(param) "291+ "method for SecureRandom Algorithm %s ", mech));292293matchExc(() -> random.nextBytes(output,294DrbgParameters.nextBytes(-1, false, new byte[]{})),295isDRBG(mech),296UnsupportedOperationException.class,297String.format("PASS - Unsupported nextBytes(out, nextByteParam)"298+ " method for SecureRandom Algorithm %s ", mech));299300matchExc(() -> random.nextBytes(output,301DrbgParameters.nextBytes(-1, true, new byte[]{})),302isDRBG(mech),303!isSupportPR(mech, random) ? IllegalArgumentException.class304: UnsupportedOperationException.class,305String.format("PASS - Unsupported or illegal "306+ "nextBytes(out, nextByteParam) method for "307+ "SecureRandom Algorithm %s ", mech));308309matchExc(() -> {310random.reseed(null);311random.nextBytes(output);312},313!SHOULD_PASS,314IllegalArgumentException.class,315"PASS - Test is expected to fail when parameter for reseed() "316+ "is null");317318matchExc(() -> random.nextBytes(output, null),319!SHOULD_PASS,320IllegalArgumentException.class,321"PASS - Test is expected to fail when parameter for nextBytes()"322+ " is null");323324}325326private static boolean isSupportPR(String mech, SecureRandom random) {327return (isDRBG(mech) && ((Instantiation) random.getParameters())328.getCapability()329.supportsPredictionResistance());330}331332private interface RunnableCode {333334void run() throws Exception;335}336337/**338* Execute a given code block and verify, if the exception type is expected.339* @param r Code block to run340* @param ex Expected exception type341* @param shouldPass If the code execution expected to pass without failure342* @param msg Message to log in case of expected failure343*/344private static void matchExc(RunnableCode r, boolean shouldPass, Class ex,345String msg) {346try {347r.run();348if (!shouldPass) {349throw new RuntimeException("Excecution should fail here.");350}351} catch (Exception e) {352System.out.printf("%nOccured exception: %s - Expected exception: "353+ "%s : ", e.getClass(), ex.getCanonicalName());354if (ex.isAssignableFrom(e.getClass())) {355System.out.printf("%n%s : Expected Exception occured: %s : ",356e.getClass(), msg);357} else if (shouldPass) {358throw new RuntimeException(e);359} else {360System.out.printf("Ignore the following exception: %s%n",361e.getMessage());362}363}364}365}366367368