1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8141039 27 * @library /lib/testlibrary 28 * @summary When random number is generated through the a SecureRandom instance 29 * as well from it's serialized instance in the same time then the 30 * generated random numbers should be different when one or both are 31 * reseeded. 32 * @run main/othervm -Djava.security.egd=file:/dev/urandom SerializedSeedTest 33 */ 34 import java.io.ByteArrayOutputStream; 35 import java.io.IOException; 36 import java.io.ObjectInputStream; 37 import java.io.ObjectOutputStream; 38 import java.io.ByteArrayInputStream; 39 import java.security.NoSuchAlgorithmException; 40 import java.security.SecureRandom; 41 import java.security.Security; 42 import jdk.testlibrary.Asserts; 43 44 public class SerializedSeedTest { 45 46 private static final byte[] SEED = "seed".getBytes(); 47 private static final String DRBG_CONFIG = "securerandom.drbg.config"; 48 private static final String DRBG_CONFIG_VALUE 49 = Security.getProperty(DRBG_CONFIG); 50 51 public static void main(String[] args) { 52 boolean success = true; 53 54 for (String mech : new String[]{ 55 "SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) { 56 System.out.printf( 57 "%nRunning test for SecureRandom mechanism: '%s'", mech); 58 try { 59 // Serialize without seed and compare generated random numbers 60 // produced through original and serialized instances. 61 SecureRandom orig = getSRInstance(mech); 62 SecureRandom copy = deserializedCopy(orig); 63 System.out.printf("%nSerialize without seed. Generated random" 64 + " numbers should be different."); 65 check(orig, copy, false, mech); 66 67 // Serialize after default seed and compare generated random 68 // numbers produced through original and serialized instances. 69 orig = getSRInstance(mech); 70 orig.nextInt(); // Default seeded 71 copy = deserializedCopy(orig); 72 System.out.printf("%nSerialize after default seed. Generated" 73 + " random numbers should be same till 20-bytes."); 74 check(orig, copy, !isDRBG(mech), mech); 75 76 // Serialize after explicit seed and compare generated random 77 // numbers produced through original and serialized instances. 78 orig = getSRInstance(mech); 79 orig.setSeed(SEED); // Explicitly seeded 80 copy = deserializedCopy(orig); 81 System.out.printf("%nSerialize after explicit seed. Generated " 82 + "random numbers should be same till 20-bytes."); 83 check(orig, copy, !isDRBG(mech), mech); 84 85 // Serialize without seed but original is explicitly seeded 86 // before generating any random number. Then compare generated 87 // random numbers produced through original and serialized 88 // instances. 89 orig = getSRInstance(mech); 90 copy = deserializedCopy(orig); 91 orig.setSeed(SEED); // Explicitly seeded 92 System.out.printf("%nSerialize without seed. When original is " 93 + "explicitly seeded before generating random numbers," 94 + " Generated random numbers should be different."); 95 check(orig, copy, false, mech); 96 97 // Serialize after default seed but original is explicitly 98 // seeded before generating any random number. Then compare 99 // generated random numbers produced through original and 100 // serialized instances. 101 orig = getSRInstance(mech); 102 orig.nextInt(); // Default seeded 103 copy = deserializedCopy(orig); 104 orig.setSeed(SEED); // Explicitly seeded 105 System.out.printf("%nSerialize after default seed but original " 106 + "is explicitly seeded before generating random number" 107 + ". Generated random numbers should be different."); 108 check(orig, copy, false, mech); 109 110 // Serialize after explicit seed but original is explicitly 111 // seeded again before generating random number. Then compare 112 // generated random numbers produced through original and 113 // serialized instances. 114 orig = getSRInstance(mech); 115 orig.setSeed(SEED); // Explicitly seeded 116 copy = deserializedCopy(orig); 117 orig.setSeed(SEED); // Explicitly seeded 118 System.out.printf("%nSerialize after explicit seed but " 119 + "original is explicitly seeded again before " 120 + "generating random number. Generated random " 121 + "numbers should be different."); 122 check(orig, copy, false, mech); 123 124 } catch (Exception e) { 125 e.printStackTrace(System.out); 126 success = false; 127 } finally { 128 Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE); 129 } 130 System.out.printf("%n------Completed Test for %s------", mech); 131 } 132 133 if (!success) { 134 throw new RuntimeException("At least one test failed."); 135 } 136 } 137 138 /** 139 * Find if the mechanism is a DRBG mechanism. 140 * @param mech Mechanism name 141 * @return True for DRBG mechanism else False 142 */ 143 private static boolean isDRBG(String mech) { 144 return mech.contains("_DRBG"); 145 } 146 147 /** 148 * Verify the similarity of random numbers generated though both original 149 * as well as deserialized instance. 150 */ 151 private static void check(SecureRandom orig, SecureRandom copy, 152 boolean equal, String mech) { 153 int o = orig.nextInt(); 154 int c = copy.nextInt(); 155 System.out.printf("%nRandom number generated for mechanism: '%s' " 156 + "from original instance as: '%s' and from serialized " 157 + "instance as: '%s'", mech, o, c); 158 if (equal) { 159 Asserts.assertEquals(o, c, mech); 160 } else { 161 Asserts.assertNotEquals(o, c, mech); 162 } 163 } 164 165 /** 166 * Get a copy of SecureRandom instance through deserialization. 167 * @param orig Original SecureRandom instance 168 * @return Deserialized SecureRandom instance 169 * @throws IOException 170 * @throws ClassNotFoundException 171 */ 172 private static SecureRandom deserializedCopy(SecureRandom orig) 173 throws IOException, ClassNotFoundException { 174 return deserialize(serialize(orig)); 175 } 176 177 /** 178 * Deserialize the SecureRandom object. 179 */ 180 private static SecureRandom deserialize(byte[] serialized) 181 throws IOException, ClassNotFoundException { 182 SecureRandom sr = null; 183 try (ByteArrayInputStream bis = new ByteArrayInputStream(serialized); 184 ObjectInputStream ois = new ObjectInputStream(bis)) { 185 sr = (SecureRandom) ois.readObject(); 186 } 187 return sr; 188 } 189 190 /** 191 * Serialize the given SecureRandom object. 192 */ 193 private static byte[] serialize(SecureRandom sr) throws IOException { 194 try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); 195 ObjectOutputStream oos = new ObjectOutputStream(bos)) { 196 oos.writeObject(sr); 197 return bos.toByteArray(); 198 } 199 } 200 201 /** 202 * Create a SecureRandom instance for a given mechanism. 203 */ 204 private static SecureRandom getSRInstance(String mech) 205 throws NoSuchAlgorithmException { 206 if (!isDRBG(mech)) { 207 return SecureRandom.getInstance(mech); 208 } else { 209 Security.setProperty(DRBG_CONFIG, mech); 210 return SecureRandom.getInstance("DRBG"); 211 } 212 } 213 214 }