jdk/test/java/security/SecureRandom/SerializedSeedTest.java
author ssahoo
Thu, 19 May 2016 04:20:08 -0700
changeset 38423 5d6ff7d76bf4
child 38447 435b76ccc9e3
permissions -rw-r--r--
8141039: Test Task: Develop new tests for JEP 273: DRBG-Based SecureRandom Implementations Reviewed-by: weijun

/*
 * 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");
        }
    }

}