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 24import sun.security.provider.AbstractDrbg; 25import sun.security.provider.EntropySource; 26 27import java.lang.reflect.Field; 28import java.lang.reflect.Modifier; 29import java.security.DrbgParameters; 30import java.security.SecureRandom; 31import java.security.Security; 32 33/** 34 * @test 35 * @bug 8051408 36 * @modules java.base/java.lang.reflect:open 37 * java.base/sun.security.provider:+open 38 * @run main/othervm CommonSeeder 39 * @summary check entropy reading of DRBGs 40 */ 41public class CommonSeeder { 42 43 static class MyES implements EntropySource { 44 int count = 100; 45 int lastCount = 100; 46 47 @Override 48 public byte[] getEntropy(int minEntropy, int minLength, 49 int maxLength, boolean pr) { 50 count--; 51 return new byte[minLength]; 52 } 53 54 /** 55 * Confirms genEntropy() has been called {@code less} times 56 * since last check. 57 */ 58 public void checkUsage(int less) throws Exception { 59 if (lastCount != count + less) { 60 throw new Exception(String.format( 61 "lastCount = %d, count = %d, less = %d", 62 lastCount, count, less)); 63 } 64 lastCount = count; 65 } 66 } 67 68 public static void main(String[] args) throws Exception { 69 70 byte[] result = new byte[10]; 71 MyES es = new MyES(); 72 73 // Set es as the default entropy source, overriding SeedGenerator. 74 setDefaultSeeder(es); 75 76 // Nothing happened yet 77 es.checkUsage(0); 78 79 SecureRandom sr; 80 sr = SecureRandom.getInstance("DRBG"); 81 82 // No entropy reading if only getInstance 83 es.checkUsage(0); 84 85 // Entropy is read at 1st nextBytes of the 1st DRBG 86 sr.nextInt(); 87 es.checkUsage(1); 88 89 for (String mech : new String[]{"Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) { 90 System.out.println("Testing " + mech + "..."); 91 92 // DRBG with pr_false will never read entropy again no matter 93 // if nextBytes or reseed is called. 94 95 Security.setProperty("securerandom.drbg.config", mech); 96 sr = SecureRandom.getInstance("DRBG"); 97 sr.nextInt(); 98 sr.reseed(); 99 es.checkUsage(0); 100 101 // DRBG with pr_true always read from default entropy, and 102 // its nextBytes always reseed itself 103 104 Security.setProperty("securerandom.drbg.config", 105 mech + ",pr_and_reseed"); 106 sr = SecureRandom.getInstance("DRBG"); 107 108 sr.nextInt(); 109 es.checkUsage(2); // one instantiate, one reseed 110 sr.nextInt(); 111 es.checkUsage(1); // one reseed in nextBytes 112 sr.reseed(); 113 es.checkUsage(1); // one reseed 114 sr.nextBytes(result, DrbgParameters.nextBytes(-1, false, null)); 115 es.checkUsage(0); // pr_false for this call 116 sr.nextBytes(result, DrbgParameters.nextBytes(-1, true, null)); 117 es.checkUsage(1); // pr_true for this call 118 sr.reseed(DrbgParameters.reseed(true, null)); 119 es.checkUsage(1); // reseed from es 120 sr.reseed(DrbgParameters.reseed(false, null)); 121 es.checkUsage(0); // reseed from AbstractDrbg.SeederHolder.seeder 122 } 123 } 124 125 static void setDefaultSeeder(EntropySource es) throws Exception { 126 Field f = AbstractDrbg.class.getDeclaredField("defaultES"); 127 f.setAccessible(true); // no more private 128 Field f2 = Field.class.getDeclaredField("modifiers"); 129 f2.setAccessible(true); 130 f2.setInt(f, f2.getInt(f) - Modifier.FINAL); // no more final 131 f.set(null, es); 132 } 133} 134