46 * activites, which in turn add entropy to the random seed. 47 * <p> The class also gathers miscellaneous system information, some 48 * machine dependent, some not. This information is then hashed together 49 * with the 20 seed bytes. 50 * <P> The alternative to the above approach is to acquire seed material 51 * from an entropy gathering device, such as /dev/random. This can be 52 * accomplished by setting the value of the "securerandom.source" 53 * security property (in the Java security properties file) to a URL 54 * specifying the location of the entropy gathering device. 55 * In the event the specified URL cannot be accessed the default 56 * mechanism is used. 57 * The Java security properties file is located in the file named 58 * <JAVA_HOME>/lib/security/java.security. 59 * <JAVA_HOME> refers to the value of the java.home system property, 60 * and specifies the directory where the JRE is installed. 61 * 62 * @author Joshua Bloch 63 * @author Gadi Guy 64 */ 65 66 import java.lang.reflect.Method; 67 import java.lang.reflect.InvocationTargetException; 68 import java.security.*; 69 import java.io.*; 70 import java.util.Properties; 71 import java.util.Enumeration; 72 import java.net.*; 73 import java.util.Random; 74 import sun.security.util.Debug; 75 76 abstract class SeedGenerator { 77 78 // Static instance is created at link time 79 private static SeedGenerator instance; 80 81 private static final Debug debug = Debug.getInstance("provider"); 82 83 final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM; 84 final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM; 85 86 // Static initializer to hook in selected or best performing generator 87 static { 88 String egdSource = SunEntries.getSeedSource(); 89 90 // Try the URL specifying the source 91 // e.g. file:/dev/random 92 // 160 java.security.AccessController.doPrivileged 161 (new java.security.PrivilegedAction<Void>() { 162 public Void run() { 163 164 try { 165 // System properties can change from machine to machine 166 String s; 167 Properties p = System.getProperties(); 168 Enumeration<?> e = p.propertyNames(); 169 while (e.hasMoreElements()) { 170 s =(String)e.nextElement(); 171 md.update(s.getBytes()); 172 md.update(p.getProperty(s).getBytes()); 173 } 174 175 md.update 176 (InetAddress.getLocalHost().toString().getBytes()); 177 178 // The temporary dir 179 File f = new File(p.getProperty("java.io.tmpdir")); 180 181 // Go thru files in the tmp dir using NIO's 182 // DirectoryStream. Fallback to File.list() 183 // if NIO is not available. 184 if (NIODirectoryStream.isAvailable()) { 185 int count = 0; 186 Iterable<?> stream = 187 NIODirectoryStream.newDirectoryStream(f); 188 // We use a Random object to choose what file names 189 // should be used. Otherwise on a machine with too 190 // many files, the same first 1024 files always get 191 // used. Any, We make sure the first 512 files are 192 // always used. 193 Random r = new Random(); 194 try { 195 for (Object entry: stream) { 196 if (count < 512 || r.nextBoolean()) { 197 md.update(NIODirectoryStream.getName( 198 entry).getBytes()); 199 } 200 if (count++ > 1024) { 201 break; 202 } 203 } 204 } finally { 205 ((Closeable)stream).close(); 206 } 207 } else { 208 String[] sa = f.list(); 209 for(int i = 0; i < sa.length; i++) { 210 md.update(sa[i].getBytes()); 211 } 212 } 213 } catch (Exception ex) { 214 md.update((byte)ex.hashCode()); 215 } 216 217 // get Runtime memory stats 218 Runtime rt = Runtime.getRuntime(); 219 byte[] memBytes = longToByteArray(rt.totalMemory()); 220 md.update(memBytes, 0, memBytes.length); 221 memBytes = longToByteArray(rt.freeMemory()); 222 md.update(memBytes, 0, memBytes.length); 223 224 return null; 225 } 226 }); 227 return md.digest(); 228 } 229 230 /** 231 * Helper function to convert a long into a byte array (least significant 232 * byte first). 536 void getSeedBytes(byte[] result) { 537 int len = result.length; 538 int read = 0; 539 try { 540 while (read < len) { 541 int count = devRandom.read(result, read, len - read); 542 // /dev/random blocks - should never have EOF 543 if (count < 0) 544 throw new InternalError("URLSeedGenerator " + deviceName + 545 " reached end of file"); 546 read += count; 547 } 548 } catch (IOException ioe) { 549 throw new InternalError("URLSeedGenerator " + deviceName + 550 " generated exception: " + 551 ioe.getMessage()); 552 } 553 } 554 555 } 556 557 /** 558 * A wrapper of NIO DirectoryStream using reflection. 559 */ 560 private static class NIODirectoryStream { 561 private static final Class<?> pathClass = 562 getClass("java.nio.file.Path"); 563 564 private static final Method toPathMethod = 565 (pathClass == null) ? null : getMethod(File.class, "toPath"); 566 private static final Method getNameMethod = 567 getMethod(pathClass, "getName"); 568 private static final Method newDirectoryStreamMethod = 569 getMethod(pathClass, "newDirectoryStream"); 570 571 private static Class<?> getClass(String name) { 572 try { 573 return Class.forName(name, true, null); 574 } catch (ClassNotFoundException e) { 575 return null; 576 } 577 } 578 579 private static Method getMethod(Class<?> clazz, 580 String name, 581 Class<?>... paramTypes) { 582 if (clazz != null) { 583 try { 584 return clazz.getMethod(name, paramTypes); 585 } catch (NoSuchMethodException e) { 586 throw new AssertionError(e); 587 } 588 } else { 589 return null; 590 } 591 } 592 593 static boolean isAvailable() { 594 return pathClass != null; 595 } 596 597 static Iterable<?> newDirectoryStream(File dir) throws IOException { 598 assert pathClass != null; 599 try { 600 Object path = toPathMethod.invoke(dir); 601 return (Iterable<?>)newDirectoryStreamMethod.invoke(path); 602 } catch (InvocationTargetException e) { 603 Throwable cause = e.getCause(); 604 if (cause instanceof IOException) 605 throw (IOException)cause; 606 if (cause instanceof RuntimeException) 607 throw (RuntimeException)cause; 608 if (cause instanceof Error) 609 throw (Error)cause; 610 throw new AssertionError(e); 611 } catch (IllegalAccessException iae) { 612 throw new AssertionError(iae); 613 } 614 } 615 616 static String getName(Object path) { 617 assert pathClass != null; 618 try { 619 Object name = getNameMethod.invoke(path); 620 return name.toString(); 621 } catch (InvocationTargetException e) { 622 throw new AssertionError(e); 623 } catch (IllegalAccessException iae) { 624 throw new AssertionError(iae); 625 } 626 } 627 } 628 } 629 | 46 * activites, which in turn add entropy to the random seed. 47 * <p> The class also gathers miscellaneous system information, some 48 * machine dependent, some not. This information is then hashed together 49 * with the 20 seed bytes. 50 * <P> The alternative to the above approach is to acquire seed material 51 * from an entropy gathering device, such as /dev/random. This can be 52 * accomplished by setting the value of the "securerandom.source" 53 * security property (in the Java security properties file) to a URL 54 * specifying the location of the entropy gathering device. 55 * In the event the specified URL cannot be accessed the default 56 * mechanism is used. 57 * The Java security properties file is located in the file named 58 * <JAVA_HOME>/lib/security/java.security. 59 * <JAVA_HOME> refers to the value of the java.home system property, 60 * and specifies the directory where the JRE is installed. 61 * 62 * @author Joshua Bloch 63 * @author Gadi Guy 64 */ 65 66 import java.security.*; 67 import java.io.*; 68 import java.util.Properties; 69 import java.util.Enumeration; 70 import java.net.*; 71 import java.nio.file.DirectoryStream; 72 import java.nio.file.Files; 73 import java.nio.file.Path; 74 import java.util.Random; 75 import sun.security.util.Debug; 76 77 abstract class SeedGenerator { 78 79 // Static instance is created at link time 80 private static SeedGenerator instance; 81 82 private static final Debug debug = Debug.getInstance("provider"); 83 84 final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM; 85 final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM; 86 87 // Static initializer to hook in selected or best performing generator 88 static { 89 String egdSource = SunEntries.getSeedSource(); 90 91 // Try the URL specifying the source 92 // e.g. file:/dev/random 93 // 161 java.security.AccessController.doPrivileged 162 (new java.security.PrivilegedAction<Void>() { 163 public Void run() { 164 165 try { 166 // System properties can change from machine to machine 167 String s; 168 Properties p = System.getProperties(); 169 Enumeration<?> e = p.propertyNames(); 170 while (e.hasMoreElements()) { 171 s =(String)e.nextElement(); 172 md.update(s.getBytes()); 173 md.update(p.getProperty(s).getBytes()); 174 } 175 176 md.update 177 (InetAddress.getLocalHost().toString().getBytes()); 178 179 // The temporary dir 180 File f = new File(p.getProperty("java.io.tmpdir")); 181 int count = 0; 182 try (DirectoryStream<Path> stream = Files.newDirectoryStream(f.toPath())) { 183 // We use a Random object to choose what file names 184 // should be used. Otherwise on a machine with too 185 // many files, the same first 1024 files always get 186 // used. Any, We make sure the first 512 files are 187 // always used. 188 Random r = new Random(); 189 for (Path entry: stream) { 190 if (count < 512 || r.nextBoolean()) { 191 md.update(entry.getFileName().toString().getBytes()); 192 } 193 if (count++ > 1024) { 194 break; 195 } 196 } 197 } 198 } catch (Exception ex) { 199 md.update((byte)ex.hashCode()); 200 } 201 202 // get Runtime memory stats 203 Runtime rt = Runtime.getRuntime(); 204 byte[] memBytes = longToByteArray(rt.totalMemory()); 205 md.update(memBytes, 0, memBytes.length); 206 memBytes = longToByteArray(rt.freeMemory()); 207 md.update(memBytes, 0, memBytes.length); 208 209 return null; 210 } 211 }); 212 return md.digest(); 213 } 214 215 /** 216 * Helper function to convert a long into a byte array (least significant 217 * byte first). 521 void getSeedBytes(byte[] result) { 522 int len = result.length; 523 int read = 0; 524 try { 525 while (read < len) { 526 int count = devRandom.read(result, read, len - read); 527 // /dev/random blocks - should never have EOF 528 if (count < 0) 529 throw new InternalError("URLSeedGenerator " + deviceName + 530 " reached end of file"); 531 read += count; 532 } 533 } catch (IOException ioe) { 534 throw new InternalError("URLSeedGenerator " + deviceName + 535 " generated exception: " + 536 ioe.getMessage()); 537 } 538 } 539 540 } 541 } |