src/share/classes/sun/security/provider/SeedGenerator.java

Print this page




  58  * Security property to a URL specifying the location of the entropy
  59  * gathering device, or by setting the {@code java.security.egd} System
  60  * property.
  61  * <p>
  62  * In the event the specified URL cannot be accessed the default
  63  * threading mechanism is used.
  64  *
  65  * @author Joshua Bloch
  66  * @author Gadi Guy
  67  */
  68 
  69 import java.security.*;
  70 import java.io.*;
  71 import java.util.Properties;
  72 import java.util.Enumeration;
  73 import java.net.*;
  74 import java.nio.file.DirectoryStream;
  75 import java.nio.file.Files;
  76 import java.nio.file.Path;
  77 import java.util.Random;




  78 import sun.security.util.Debug;
  79 
  80 abstract class SeedGenerator {
  81 
  82     // Static instance is created at link time
  83     private static SeedGenerator instance;
  84 
  85     private static final Debug debug = Debug.getInstance("provider");
  86 
  87     // Static initializer to hook in selected or best performing generator
  88     static {
  89         String egdSource = SunEntries.getSeedSource();
  90 
  91         /*
  92          * Try the URL specifying the source (e.g. file:/dev/random)
  93          *
  94          * The URLs "file:/dev/random" or "file:/dev/urandom" are used to
  95          * indicate the SeedGenerator should use OS support, if available.
  96          *
  97          * On Windows, this causes the MS CryptoAPI seeder to be used.
  98          *
  99          * On Solaris/Linux/MacOS, this is identical to using
 100          * URLSeedGenerator to read from /dev/[u]random
 101          */
 102         if (egdSource.equals(SunEntries.URL_DEV_RANDOM) ||
 103                 egdSource.equals(SunEntries.URL_DEV_URANDOM)) {
 104             try {
 105                 instance = new NativeSeedGenerator(egdSource);


 106                 if (debug != null) {
 107                     debug.println(
 108                         "Using operating system seed generator" + egdSource);
 109                 }
 110             } catch (IOException e) {
 111                 if (debug != null) {
 112                     debug.println("Failed to use operating system seed "
 113                                   + "generator: " + e.toString());
 114                 }
 115             }
 116         } else if (egdSource.length() != 0) {
 117             try {
 118                 instance = new URLSeedGenerator(egdSource);


 119                 if (debug != null) {
 120                     debug.println("Using URL seed generator reading from "
 121                                   + egdSource);
 122                 }
 123             } catch (IOException e) {
 124                 if (debug != null) {
 125                     debug.println("Failed to create seed generator with "
 126                                   + egdSource + ": " + e.toString());
 127                 }
 128             }
 129         }
 130 
 131         // Fall back to ThreadedSeedGenerator
 132         if (instance == null) {
 133             if (debug != null) {
 134                 debug.println("Using default threaded seed generator");
 135             }
 136             instance = new ThreadedSeedGenerator();














 137         }
 138     }
 139 









 140     /**
 141      * Fill result with bytes from the queue. Wait for it if it isn't ready.
 142      */
 143     static public void generateSeed(byte[] result) {
 144         instance.getSeedBytes(result);
 145     }
 146 
 147     abstract void getSeedBytes(byte[] result);





 148 
 149     /**
 150      * Retrieve some system information, hashed.
 151      */
 152     static byte[] getSystemEntropy() {
 153         final MessageDigest md;
 154 
 155         try {
 156             md = MessageDigest.getInstance("SHA");
 157         } catch (NoSuchAlgorithmException nsae) {
 158             throw new InternalError("internal error: SHA-1 not available.",
 159                     nsae);
 160         }
 161 
 162         // The current time in millis
 163         byte b =(byte)System.currentTimeMillis();
 164         md.update(b);
 165 
 166         java.security.AccessController.doPrivileged
 167             (new java.security.PrivilegedAction<Void>() {


 367                     // Push it into the queue and notify anybody who might
 368                     // be waiting for it.
 369                     synchronized(this) {
 370                         pool[end] = v;
 371                         end++;
 372                         count++;
 373                         if (end >= pool.length) {
 374                             end = 0;
 375                         }
 376 
 377                         notifyAll();
 378                     }
 379                 }
 380             } catch (Exception e) {
 381                 throw new InternalError("internal error: " +
 382                     "SeedGenerator thread generated an exception.", e);
 383             }
 384         }
 385 
 386         @Override
 387         void getSeedBytes(byte[] result) {
 388             for (int i = 0; i < result.length; i++) {
 389                 result[i] = getSeedByte();
 390             }
 391         }
 392 
 393         byte getSeedByte() {
 394             byte b;
 395 
 396             try {
 397                 // Wait for it...
 398                 synchronized(this) {
 399                     while (count <= 0) {
 400                         wait();
 401                     }
 402                 }
 403             } catch (Exception e) {
 404                 if (count <= 0) {
 405                     throw new InternalError("internal error: " +
 406                         "SeedGenerator thread generated an exception.", e);
 407                 }


 510                              * can buffer up to 8K bytes. This read is a
 511                              * performance issue for entropy sources which
 512                              * can be slow to replenish.
 513                              */
 514                             if (device.getProtocol().equalsIgnoreCase("file")) {
 515                                 File deviceFile =
 516                                     SunEntries.getDeviceFile(device);
 517                                 return new FileInputStream(deviceFile);
 518                             } else {
 519                                 return device.openStream();
 520                             }
 521                         }
 522                     });
 523             } catch (Exception e) {
 524                 throw new IOException(
 525                     "Failed to open " + deviceName, e.getCause());
 526             }
 527         }
 528 
 529         @Override
 530         void getSeedBytes(byte[] result) {
 531             int len = result.length;
 532             int read = 0;
 533             try {
 534                 while (read < len) {
 535                     int count = seedStream.read(result, read, len - read);
 536                     // /dev/random blocks - should never have EOF
 537                     if (count < 0) {
 538                         throw new InternalError(
 539                             "URLSeedGenerator " + deviceName +
 540                             " reached end of file");
 541                     }
 542                     read += count;
 543                 }
 544             } catch (IOException ioe) {
 545                 throw new InternalError("URLSeedGenerator " + deviceName +
 546                     " generated exception: " + ioe.getMessage(), ioe);
 547             }







 548         }
 549     }
 550 }


  58  * Security property to a URL specifying the location of the entropy
  59  * gathering device, or by setting the {@code java.security.egd} System
  60  * property.
  61  * <p>
  62  * In the event the specified URL cannot be accessed the default
  63  * threading mechanism is used.
  64  *
  65  * @author Joshua Bloch
  66  * @author Gadi Guy
  67  */
  68 
  69 import java.security.*;
  70 import java.io.*;
  71 import java.util.Properties;
  72 import java.util.Enumeration;
  73 import java.net.*;
  74 import java.nio.file.DirectoryStream;
  75 import java.nio.file.Files;
  76 import java.nio.file.Path;
  77 import java.util.Random;
  78 
  79 import sun.misc.VM;
  80 import sun.reflect.CallerSensitive;
  81 import sun.reflect.Reflection;
  82 import sun.security.util.Debug;
  83 
  84 public abstract class SeedGenerator implements AutoCloseable {
  85 
  86     // Static instance is created at link time
  87     private static SeedGenerator instance;
  88 
  89     private static final Debug debug = Debug.getInstance("provider");
  90 
  91     // Static initializer to hook in selected or best performing generator
  92     static {
  93         String egdSource = SunEntries.getSeedSource();
  94 
  95         /*
  96          * Try the URL specifying the source (e.g. file:/dev/random)
  97          *
  98          * The URLs "file:/dev/random" or "file:/dev/urandom" are used to
  99          * indicate the SeedGenerator should use OS support, if available.
 100          *
 101          * On Windows, this causes the MS CryptoAPI seeder to be used.
 102          *
 103          * On Solaris/Linux/MacOS, this is identical to using
 104          * URLSeedGenerator to read from /dev/[u]random
 105          */
 106         if (egdSource.equals(SunEntries.URL_DEV_RANDOM) ||
 107                 egdSource.equals(SunEntries.URL_DEV_URANDOM)) {
 108             try {
 109                 instance = new NativeSeedGenerator(egdSource) {
 110                     @Override public void close() {} // never close shared instance
 111                 };
 112                 if (debug != null) {
 113                     debug.println(
 114                         "Using operating system seed generator" + egdSource);
 115                 }
 116             } catch (IOException e) {
 117                 if (debug != null) {
 118                     debug.println("Failed to use operating system seed "
 119                                   + "generator: " + e.toString());
 120                 }
 121             }
 122         } else if (egdSource.length() != 0) {
 123             try {
 124                 instance = new URLSeedGenerator(egdSource) {
 125                     @Override public void close() {} // never close shared instance
 126                 };
 127                 if (debug != null) {
 128                     debug.println("Using URL seed generator reading from "
 129                                   + egdSource);
 130                 }
 131             } catch (IOException e) {
 132                 if (debug != null) {
 133                     debug.println("Failed to create seed generator with "
 134                                   + egdSource + ": " + e.toString());
 135                 }
 136             }
 137         }
 138 
 139         // Fall back to ThreadedSeedGenerator
 140         if (instance == null) {
 141             if (debug != null) {
 142                 debug.println("Using default threaded seed generator");
 143             }
 144             instance = new ThreadedSeedGenerator(); // close() is a no-op here
 145         }
 146     }
 147 
 148     @CallerSensitive
 149     public static SeedGenerator getNativeInstance() {
 150         Class<?> caller = Reflection.getCallerClass();
 151         if (!VM.isSystemDomainLoader(caller.getClassLoader())) {
 152             throw new SecurityException("Internal API");
 153         }
 154         try {
 155             return new NativeSeedGenerator(SunEntries.URL_DEV_URANDOM);
 156         } catch (IOException e) {
 157             // fall-back to default shared instance
 158             return instance;
 159         }
 160     }
 161 
 162     @CallerSensitive
 163     public static SeedGenerator getDefaultInstance() {
 164         Class<?> caller = Reflection.getCallerClass();
 165         if (!VM.isSystemDomainLoader(caller.getClassLoader())) {
 166             throw new SecurityException("Internal API");
 167         }
 168         return instance;
 169     }
 170 
 171     /**
 172      * Fill result with bytes from the queue. Wait for it if it isn't ready.
 173      */
 174     static void generateSeed(byte[] result) {
 175         instance.getSeedBytes(result);
 176     }
 177 
 178     public abstract void getSeedBytes(byte[] result);
 179 
 180     @Override
 181     public void close() {
 182         // nothing to close by default
 183     }
 184 
 185     /**
 186      * Retrieve some system information, hashed.
 187      */
 188     static byte[] getSystemEntropy() {
 189         final MessageDigest md;
 190 
 191         try {
 192             md = MessageDigest.getInstance("SHA");
 193         } catch (NoSuchAlgorithmException nsae) {
 194             throw new InternalError("internal error: SHA-1 not available.",
 195                     nsae);
 196         }
 197 
 198         // The current time in millis
 199         byte b =(byte)System.currentTimeMillis();
 200         md.update(b);
 201 
 202         java.security.AccessController.doPrivileged
 203             (new java.security.PrivilegedAction<Void>() {


 403                     // Push it into the queue and notify anybody who might
 404                     // be waiting for it.
 405                     synchronized(this) {
 406                         pool[end] = v;
 407                         end++;
 408                         count++;
 409                         if (end >= pool.length) {
 410                             end = 0;
 411                         }
 412 
 413                         notifyAll();
 414                     }
 415                 }
 416             } catch (Exception e) {
 417                 throw new InternalError("internal error: " +
 418                     "SeedGenerator thread generated an exception.", e);
 419             }
 420         }
 421 
 422         @Override
 423         public void getSeedBytes(byte[] result) {
 424             for (int i = 0; i < result.length; i++) {
 425                 result[i] = getSeedByte();
 426             }
 427         }
 428 
 429         byte getSeedByte() {
 430             byte b;
 431 
 432             try {
 433                 // Wait for it...
 434                 synchronized(this) {
 435                     while (count <= 0) {
 436                         wait();
 437                     }
 438                 }
 439             } catch (Exception e) {
 440                 if (count <= 0) {
 441                     throw new InternalError("internal error: " +
 442                         "SeedGenerator thread generated an exception.", e);
 443                 }


 546                              * can buffer up to 8K bytes. This read is a
 547                              * performance issue for entropy sources which
 548                              * can be slow to replenish.
 549                              */
 550                             if (device.getProtocol().equalsIgnoreCase("file")) {
 551                                 File deviceFile =
 552                                     SunEntries.getDeviceFile(device);
 553                                 return new FileInputStream(deviceFile);
 554                             } else {
 555                                 return device.openStream();
 556                             }
 557                         }
 558                     });
 559             } catch (Exception e) {
 560                 throw new IOException(
 561                     "Failed to open " + deviceName, e.getCause());
 562             }
 563         }
 564 
 565         @Override
 566         public void getSeedBytes(byte[] result) {
 567             int len = result.length;
 568             int read = 0;
 569             try {
 570                 while (read < len) {
 571                     int count = seedStream.read(result, read, len - read);
 572                     // /dev/random blocks - should never have EOF
 573                     if (count < 0) {
 574                         throw new InternalError(
 575                             "URLSeedGenerator " + deviceName +
 576                             " reached end of file");
 577                     }
 578                     read += count;
 579                 }
 580             } catch (IOException ioe) {
 581                 throw new InternalError("URLSeedGenerator " + deviceName +
 582                     " generated exception: " + ioe.getMessage(), ioe);
 583             }
 584         }
 585 
 586         @Override
 587         public void close() {
 588             try {
 589                 seedStream.close();
 590             } catch (IOException ignore) {}
 591         }
 592     }
 593 }