1 /*
   2  * Copyright (c) 2013, 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 6425477 8141039
  27  * @summary Better support for generation of high entropy random numbers
  28  * @run main StrongSecureRandom
  29  */
  30 import java.security.*;
  31 import java.util.*;
  32 
  33 /**
  34  * This test assumes that the standard Sun providers are installed.
  35  */
  36 public class StrongSecureRandom {
  37 
  38     private static final String os = System.getProperty("os.name", "unknown");
  39     private static final String DRBG_CONFIG = "securerandom.drbg.config";
  40     private static final String DRBG_CONFIG_VALUE
  41             = Security.getProperty(DRBG_CONFIG);
  42 
  43     private static void testDefaultEgd() throws Exception {
  44         // No SecurityManager installed.
  45         String s = Security.getProperty("securerandom.source");
  46 
  47         System.out.println("Testing:  default EGD: " + s);
  48         if (!s.equals("file:/dev/random")) {
  49             throw new Exception("Default is not 'file:/dev/random'");
  50         }
  51     }
  52 
  53     /**
  54      * Verify if the mechanism is DRBG type.
  55      * @param mech Mechanism name
  56      * @return True if the mechanism name is DRBG type else False.
  57      */
  58     private static boolean isDRBG(String mech) {
  59         return mech.contains("_DRBG");
  60     }
  61 
  62     private static void testSecureRandomImpl(String algo, boolean drbg)
  63             throws Exception {
  64 
  65         byte[] ba;
  66         final String secureRandomSource
  67                 = Security.getProperty("securerandom.source");
  68         try {
  69             String urandom = "file:/dev/urandom";
  70 
  71             System.out.println("Testing new SeedGenerator and EGD");
  72 
  73             Security.setProperty("securerandom.source", urandom);
  74             if (!Security.getProperty("securerandom.source").equals(urandom)) {
  75                 throw new Exception("Couldn't set securerandom.source");
  76             }
  77 
  78             /*
  79              * Take out a large number of bytes in hopes of blocking.
  80              * Don't expect this to happen, unless something is broken on Linux
  81              */
  82             SecureRandom sr = null;
  83             if (drbg) {
  84                 Security.setProperty(DRBG_CONFIG, algo);
  85                 sr = SecureRandom.getInstance("DRBG");
  86             } else {
  87                 sr = SecureRandom.getInstance(algo);
  88             }
  89             if (!sr.getAlgorithm().equals(isDRBG(algo) ? "DRBG" : algo)) {
  90                 throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
  91             }
  92 
  93             ba = sr.generateSeed(4096);
  94             sr.nextBytes(ba);
  95             sr.setSeed(ba);
  96         } finally {
  97             Security.setProperty("securerandom.source", secureRandomSource);
  98             Security.setProperty(DRBG_CONFIG, DRBG_CONFIG_VALUE);
  99         }
 100     }
 101 
 102     private static void testNativePRNGImpls() throws Exception {
 103         SecureRandom sr;
 104         byte[] ba;
 105 
 106         System.out.println("Testing new NativePRNGImpls");
 107 
 108         if (os.startsWith("Windows")) {
 109             System.out.println("Skip windows testing.");
 110             return;
 111         }
 112 
 113         System.out.println("Testing regular");
 114         sr = SecureRandom.getInstance("NativePRNG");
 115         if (!sr.getAlgorithm().equals("NativePRNG")) {
 116             throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
 117         }
 118         ba = sr.generateSeed(1);
 119         sr.nextBytes(ba);
 120         sr.setSeed(ba);
 121 
 122         System.out.println("Testing NonBlocking");
 123         sr = SecureRandom.getInstance("NativePRNGNonBlocking");
 124         if (!sr.getAlgorithm().equals("NativePRNGNonBlocking")) {
 125             throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
 126         }
 127         ba = sr.generateSeed(1);
 128         sr.nextBytes(ba);
 129         sr.setSeed(ba);
 130 
 131         if (os.equals("Linux")) {
 132             System.out.println("Skip Linux blocking test.");
 133             return;
 134         }
 135 
 136         System.out.println("Testing Blocking");
 137         sr = SecureRandom.getInstance("NativePRNGBlocking");
 138         if (!sr.getAlgorithm().equals("NativePRNGBlocking")) {
 139             throw new Exception("sr.getAlgorithm(): " + sr.getAlgorithm());
 140         }
 141         ba = sr.generateSeed(1);
 142         sr.nextBytes(ba);
 143         sr.setSeed(ba);
 144     }
 145 
 146     private static void testStrongInstance(boolean expected) throws Exception {
 147 
 148         boolean result;
 149 
 150         try {
 151             SecureRandom.getInstanceStrong();
 152             result = true;
 153         } catch (NoSuchAlgorithmException e) {
 154             result = false;
 155         }
 156 
 157         if (expected != result) {
 158             throw new Exception("Received: " + result);
 159         }
 160     }
 161 
 162     /*
 163      * This test assumes that the standard providers are installed.
 164      */
 165     private static void testProperty(String property, boolean expected)
 166             throws Exception {
 167 
 168         System.out.println("Testing: '" + property + "' " + expected);
 169         final String origStrongAlgoProp
 170                 = Security.getProperty("securerandom.strongAlgorithms");
 171         try {
 172             Security.setProperty("securerandom.strongAlgorithms", property);
 173             testStrongInstance(expected);
 174         } finally {
 175             Security.setProperty(
 176                     "securerandom.strongAlgorithms", origStrongAlgoProp);
 177         }
 178     }
 179 
 180     private static void testProperties() throws Exception {
 181         // Sets securerandom.strongAlgorithms, and then tests various combos.
 182         testProperty("", false);
 183 
 184         testProperty("SHA1PRNG", true);
 185         testProperty(" SHA1PRNG", true);
 186         testProperty("SHA1PRNG ", true);
 187         testProperty(" SHA1PRNG ", true);
 188 
 189         // Impls are case-insenstive, providers are sensitive.
 190         testProperty("SHA1PRNG:SUN", true);
 191         testProperty("Sha1PRNG:SUN", true);
 192         testProperty("SHA1PRNG:Sun", false);
 193 
 194         testProperty(" SHA1PRNG:SUN", true);
 195         testProperty("SHA1PRNG:SUN ", true);
 196         testProperty(" SHA1PRNG:SUN ", true);
 197 
 198         testProperty(" SHA1PRNG:SUn", false);
 199         testProperty("SHA1PRNG:SUn ", false);
 200         testProperty(" SHA1PRNG:SUn ", false);
 201 
 202         testProperty(",,,SHA1PRNG", true);
 203         testProperty(",,, SHA1PRNG", true);
 204         testProperty(" , , ,SHA1PRNG ", true);
 205 
 206         testProperty(",,,, SHA1PRNG ,,,", true);
 207         testProperty(",,,, SHA1PRNG:SUN ,,,", true);
 208         testProperty(",,,, SHA1PRNG:SUn ,,,", false);
 209 
 210         testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUN", true);
 211         testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUN", true);
 212         testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUN", true);
 213 
 214         testProperty(",,,SHA1PRNG:Sun,, SHA1PRNG:SUn", false);
 215         testProperty(",,,Sha1PRNG:Sun, SHA1PRNG:SUn", false);
 216         testProperty(" SHA1PRNG:Sun, Sha1PRNG:Sun,,,,Sha1PRNG:SUn", false);
 217 
 218         testProperty(
 219                 " @#%,%$#:!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUN",
 220                 true);
 221         testProperty(" @#%,%$#!%^, NativePRNG:Sun, Sha1PRNG:Sun,,Sha1PRNG:SUn",
 222                 false);
 223     }
 224 
 225     /*
 226      * Linux tends to block, so ignore anything that reads /dev/random.
 227      */
 228     private static void handleLinuxRead(SecureRandom sr) throws Exception {
 229         if (os.equals("Linux")) {
 230             if (!sr.getAlgorithm().equalsIgnoreCase("NativePRNGBlocking")) {
 231                 sr.nextBytes(new byte[34]);
 232             }
 233         } else {
 234             sr.nextBytes(new byte[34]);
 235             sr.generateSeed(34);
 236             sr.setSeed(new byte[34]);
 237         }
 238     }
 239 
 240     /*
 241      * This is duplicating stuff above, but just iterate over all impls
 242      * just in case we missed something.
 243      */
 244     private static void testAllImpls() throws Exception {
 245         System.out.print("Testing:  AllImpls:  ");
 246 
 247         Iterator<String> i = Security.getAlgorithms("SecureRandom").iterator();
 248 
 249         while (i.hasNext()) {
 250             String s = i.next();
 251             System.out.print("/" + s);
 252             SecureRandom sr = SecureRandom.getInstance(s);
 253 
 254             handleLinuxRead(sr);
 255             handleLinuxRead(sr);
 256         }
 257         System.out.println("/");
 258     }
 259 
 260     public static void main(String args[]) throws Exception {
 261         testDefaultEgd();
 262         for (String algo : new String[]{
 263             "SHA1PRNG", "Hash_DRBG", "HMAC_DRBG", "CTR_DRBG"}) {
 264             testSecureRandomImpl(algo, isDRBG(algo));
 265         }
 266         testNativePRNGImpls();
 267         testAllImpls();
 268 
 269         // test default.
 270         testStrongInstance(true);
 271         testProperties();
 272     }
 273 }