1 module hunt.security.SecureRandom; 2 3 import hunt.Exceptions; 4 5 6 /** 7 * This class provides a cryptographically strong random number 8 * generator (RNG). 9 * 10 * <p>A cryptographically strong random number 11 * minimally complies with the statistical random number generator tests 12 * specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm"> 13 * <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>, 14 * section 4.9.1. 15 * Additionally, SecureRandom must produce non-deterministic output. 16 * Therefore any seed material passed to a SecureRandom object must be 17 * unpredictable, and all SecureRandom output sequences must be 18 * cryptographically strong, as described in 19 * <a href="http://www.ietf.org/rfc/rfc1750.txt"> 20 * <i>RFC 1750: Randomness Recommendations for Security</i></a>. 21 * 22 * <p>A caller obtains a SecureRandom instance via the 23 * no-argument constructor or one of the {@code getInstance} methods: 24 * 25 * <pre> 26 * SecureRandom random = new SecureRandom(); 27 * </pre> 28 * 29 * <p> Many SecureRandom implementations are in the form of a pseudo-random 30 * number generator (PRNG), which means they use a deterministic algorithm 31 * to produce a pseudo-random sequence from a true random seed. 32 * Other implementations may produce true random numbers, 33 * and yet others may use a combination of both techniques. 34 * 35 * <p> Typical callers of SecureRandom invoke the following methods 36 * to retrieve random bytes: 37 * 38 * <pre> 39 * SecureRandom random = new SecureRandom(); 40 * byte bytes[] = new byte[20]; 41 * random.nextBytes(bytes); 42 * </pre> 43 * 44 * <p> Callers may also invoke the {@code generateSeed} method 45 * to generate a given number of seed bytes (to seed other random number 46 * generators, for example): 47 * <pre> 48 * byte seed[] = random.generateSeed(20); 49 * </pre> 50 * 51 * Note: Depending on the implementation, the {@code generateSeed} and 52 * {@code nextBytes} methods may block as entropy is being gathered, 53 * for example, if they need to read from /dev/random on various Unix-like 54 * operating systems. 55 * 56 * @see java.security.SecureRandomSpi 57 * @see java.util.Random 58 * 59 * @author Benjamin Renaud 60 * @author Josh Bloch 61 */ 62 63 class SecureRandom { // : java.util.Random 64 65 // private static final Debug pdebug = 66 // Debug.getInstance("provider", "Provider"); 67 // private static final bool skipDebug = 68 // Debug.isOn("engine=") && !Debug.isOn("securerandom"); 69 70 // /** 71 // * The provider. 72 // * 73 // * @serial 74 // * @since 1.2 75 // */ 76 // private Provider provider = null; 77 78 // /** 79 // * The provider implementation. 80 // * 81 // * @serial 82 // * @since 1.2 83 // */ 84 // private SecureRandomSpi secureRandomSpi = null; 85 86 // /* 87 // * The algorithm name of null if unknown. 88 // * 89 // * @serial 90 // * @since 1.5 91 // */ 92 // private string algorithm; 93 94 // // Seed Generator 95 // private static volatile SecureRandom seedGenerator = null; 96 97 /** 98 * Constructs a secure random number generator (RNG) implementing the 99 * default random number algorithm. 100 * 101 * <p> This constructor traverses the list of registered security Providers, 102 * starting with the most preferred Provider. 103 * A new SecureRandom object encapsulating the 104 * SecureRandomSpi implementation from the first 105 * Provider that supports a SecureRandom (RNG) algorithm is returned. 106 * If none of the Providers support a RNG algorithm, 107 * then an implementation-specific default is returned. 108 * 109 * <p> Note that the list of registered providers may be retrieved via 110 * the {@link Security#getProviders() Security.getProviders()} method. 111 * 112 * <p> See the SecureRandom section in the <a href= 113 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom"> 114 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 115 * for information about standard RNG algorithm names. 116 * 117 * <p> The returned SecureRandom object has not been seeded. To seed the 118 * returned object, call the {@code setSeed} method. 119 * If {@code setSeed} is not called, the first call to 120 * {@code nextBytes} will force the SecureRandom object to seed itself. 121 * This self-seeding will not occur if {@code setSeed} was 122 * previously called. 123 */ 124 this() { 125 /* 126 * This call to our superclass constructor will result in a call 127 * to our own {@code setSeed} method, which will return 128 * immediately when it is passed zero. 129 */ 130 // super(0); 131 // getDefaultPRNG(false, null); 132 } 133 134 /** 135 * Constructs a secure random number generator (RNG) implementing the 136 * default random number algorithm. 137 * The SecureRandom instance is seeded with the specified seed bytes. 138 * 139 * <p> This constructor traverses the list of registered security Providers, 140 * starting with the most preferred Provider. 141 * A new SecureRandom object encapsulating the 142 * SecureRandomSpi implementation from the first 143 * Provider that supports a SecureRandom (RNG) algorithm is returned. 144 * If none of the Providers support a RNG algorithm, 145 * then an implementation-specific default is returned. 146 * 147 * <p> Note that the list of registered providers may be retrieved via 148 * the {@link Security#getProviders() Security.getProviders()} method. 149 * 150 * <p> See the SecureRandom section in the <a href= 151 * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom"> 152 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 153 * for information about standard RNG algorithm names. 154 * 155 * @param seed the seed. 156 */ 157 this(byte[] seed) { 158 // super(0); 159 // getDefaultPRNG(true, seed); 160 } 161 162 // private void getDefaultPRNG(bool setSeed, byte[] seed) { 163 // string prng = getPrngAlgorithm(); 164 // if (prng is null) { 165 // // bummer, get the SUN implementation 166 // prng = "SHA1PRNG"; 167 // this.secureRandomSpi = new sun.security.provider.SecureRandom(); 168 // this.provider = Providers.getSunProvider(); 169 // if (setSeed) { 170 // this.secureRandomSpi.engineSetSeed(seed); 171 // } 172 // } else { 173 // try { 174 // SecureRandom random = SecureRandom.getInstance(prng); 175 // this.secureRandomSpi = random.getSecureRandomSpi(); 176 // this.provider = random.getProvider(); 177 // if (setSeed) { 178 // this.secureRandomSpi.engineSetSeed(seed); 179 // } 180 // } catch (NoSuchAlgorithmException nsae) { 181 // // never happens, because we made sure the algorithm exists 182 // throw new RuntimeException(nsae); 183 // } 184 // } 185 // // JDK 1.1 based implementations subclass SecureRandom instead of 186 // // SecureRandomSpi. They will also go through this code path because 187 // // they must call a SecureRandom constructor as it is their superclass. 188 // // If we are dealing with such an implementation, do not set the 189 // // algorithm value as it would be inaccurate. 190 // if (getClass() == SecureRandom.class) { 191 // this.algorithm = prng; 192 // } 193 // } 194 195 // /** 196 // * Creates a SecureRandom object. 197 // * 198 // * @param secureRandomSpi the SecureRandom implementation. 199 // * @param provider the provider. 200 // */ 201 // protected SecureRandom(SecureRandomSpi secureRandomSpi, 202 // Provider provider) { 203 // this(secureRandomSpi, provider, null); 204 // } 205 206 // private SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider, 207 // string algorithm) { 208 // super(0); 209 // this.secureRandomSpi = secureRandomSpi; 210 // this.provider = provider; 211 // this.algorithm = algorithm; 212 213 // if (!skipDebug && pdebug !is null) { 214 // pdebug.println("SecureRandom." ~ algorithm + 215 // " algorithm from: " ~ this.provider.getName()); 216 // } 217 // } 218 219 // /** 220 // * Returns a SecureRandom object that implements the specified 221 // * Random Number Generator (RNG) algorithm. 222 // * 223 // * <p> This method traverses the list of registered security Providers, 224 // * starting with the most preferred Provider. 225 // * A new SecureRandom object encapsulating the 226 // * SecureRandomSpi implementation from the first 227 // * Provider that supports the specified algorithm is returned. 228 // * 229 // * <p> Note that the list of registered providers may be retrieved via 230 // * the {@link Security#getProviders() Security.getProviders()} method. 231 // * 232 // * <p> The returned SecureRandom object has not been seeded. To seed the 233 // * returned object, call the {@code setSeed} method. 234 // * If {@code setSeed} is not called, the first call to 235 // * {@code nextBytes} will force the SecureRandom object to seed itself. 236 // * This self-seeding will not occur if {@code setSeed} was 237 // * previously called. 238 // * 239 // * @param algorithm the name of the RNG algorithm. 240 // * See the SecureRandom section in the <a href= 241 // * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom"> 242 // * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 243 // * for information about standard RNG algorithm names. 244 // * 245 // * @return the new SecureRandom object. 246 // * 247 // * @exception NoSuchAlgorithmException if no Provider supports a 248 // * SecureRandomSpi implementation for the 249 // * specified algorithm. 250 // * 251 // * @see Provider 252 // * 253 // * @since 1.2 254 // */ 255 // static SecureRandom getInstance(string algorithm) 256 // throws NoSuchAlgorithmException { 257 // Instance instance = GetInstance.getInstance("SecureRandom", 258 // SecureRandomSpi.class, algorithm); 259 // return new SecureRandom((SecureRandomSpi)instance.impl, 260 // instance.provider, algorithm); 261 // } 262 263 // /** 264 // * Returns a SecureRandom object that implements the specified 265 // * Random Number Generator (RNG) algorithm. 266 // * 267 // * <p> A new SecureRandom object encapsulating the 268 // * SecureRandomSpi implementation from the specified provider 269 // * is returned. The specified provider must be registered 270 // * in the security provider list. 271 // * 272 // * <p> Note that the list of registered providers may be retrieved via 273 // * the {@link Security#getProviders() Security.getProviders()} method. 274 // * 275 // * <p> The returned SecureRandom object has not been seeded. To seed the 276 // * returned object, call the {@code setSeed} method. 277 // * If {@code setSeed} is not called, the first call to 278 // * {@code nextBytes} will force the SecureRandom object to seed itself. 279 // * This self-seeding will not occur if {@code setSeed} was 280 // * previously called. 281 // * 282 // * @param algorithm the name of the RNG algorithm. 283 // * See the SecureRandom section in the <a href= 284 // * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom"> 285 // * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 286 // * for information about standard RNG algorithm names. 287 // * 288 // * @param provider the name of the provider. 289 // * 290 // * @return the new SecureRandom object. 291 // * 292 // * @exception NoSuchAlgorithmException if a SecureRandomSpi 293 // * implementation for the specified algorithm is not 294 // * available from the specified provider. 295 // * 296 // * @exception NoSuchProviderException if the specified provider is not 297 // * registered in the security provider list. 298 // * 299 // * @exception IllegalArgumentException if the provider name is null 300 // * or empty. 301 // * 302 // * @see Provider 303 // * 304 // * @since 1.2 305 // */ 306 // static SecureRandom getInstance(string algorithm, string provider) 307 // throws NoSuchAlgorithmException, NoSuchProviderException { 308 // Instance instance = GetInstance.getInstance("SecureRandom", 309 // SecureRandomSpi.class, algorithm, provider); 310 // return new SecureRandom((SecureRandomSpi)instance.impl, 311 // instance.provider, algorithm); 312 // } 313 314 // /** 315 // * Returns a SecureRandom object that implements the specified 316 // * Random Number Generator (RNG) algorithm. 317 // * 318 // * <p> A new SecureRandom object encapsulating the 319 // * SecureRandomSpi implementation from the specified Provider 320 // * object is returned. Note that the specified Provider object 321 // * does not have to be registered in the provider list. 322 // * 323 // * <p> The returned SecureRandom object has not been seeded. To seed the 324 // * returned object, call the {@code setSeed} method. 325 // * If {@code setSeed} is not called, the first call to 326 // * {@code nextBytes} will force the SecureRandom object to seed itself. 327 // * This self-seeding will not occur if {@code setSeed} was 328 // * previously called. 329 // * 330 // * @param algorithm the name of the RNG algorithm. 331 // * See the SecureRandom section in the <a href= 332 // * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom"> 333 // * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 334 // * for information about standard RNG algorithm names. 335 // * 336 // * @param provider the provider. 337 // * 338 // * @return the new SecureRandom object. 339 // * 340 // * @exception NoSuchAlgorithmException if a SecureRandomSpi 341 // * implementation for the specified algorithm is not available 342 // * from the specified Provider object. 343 // * 344 // * @exception IllegalArgumentException if the specified provider is null. 345 // * 346 // * @see Provider 347 // * 348 // * @since 1.4 349 // */ 350 // static SecureRandom getInstance(string algorithm, 351 // Provider provider) throws NoSuchAlgorithmException { 352 // Instance instance = GetInstance.getInstance("SecureRandom", 353 // SecureRandomSpi.class, algorithm, provider); 354 // return new SecureRandom((SecureRandomSpi)instance.impl, 355 // instance.provider, algorithm); 356 // } 357 358 // /** 359 // * Returns the SecureRandomSpi of this SecureRandom object. 360 // */ 361 // SecureRandomSpi getSecureRandomSpi() { 362 // return secureRandomSpi; 363 // } 364 365 // /** 366 // * Returns the provider of this SecureRandom object. 367 // * 368 // * @return the provider of this SecureRandom object. 369 // */ 370 // final Provider getProvider() { 371 // return provider; 372 // } 373 374 // /** 375 // * Returns the name of the algorithm implemented by this SecureRandom 376 // * object. 377 // * 378 // * @return the name of the algorithm or {@code unknown} 379 // * if the algorithm name cannot be determined. 380 // * @since 1.5 381 // */ 382 // string getAlgorithm() { 383 // return (algorithm !is null) ? algorithm : "unknown"; 384 // } 385 386 /** 387 * Reseeds this random object. The given seed supplements, rather than 388 * replaces, the existing seed. Thus, repeated calls are guaranteed 389 * never to reduce randomness. 390 * 391 * @param seed the seed. 392 * 393 * @see #getSeed 394 */ 395 void setSeed(byte[] seed) { 396 // secureRandomSpi.engineSetSeed(seed); 397 implementationMissing(false); 398 } 399 400 // /** 401 // * Reseeds this random object, using the eight bytes contained 402 // * in the given {@code long seed}. The given seed supplements, 403 // * rather than replaces, the existing seed. Thus, repeated calls 404 // * are guaranteed never to reduce randomness. 405 // * 406 // * <p>This method is defined for compatibility with 407 // * {@code java.util.Random}. 408 // * 409 // * @param seed the seed. 410 // * 411 // * @see #getSeed 412 // */ 413 // override 414 // void setSeed(long seed) { 415 // /* 416 // * Ignore call from super constructor (as well as any other calls 417 // * unfortunate enough to be passing 0). It's critical that we 418 // * ignore call from superclass constructor, as digest has not 419 // * yet been initialized at that point. 420 // */ 421 // if (seed != 0) { 422 // secureRandomSpi.engineSetSeed(longToByteArray(seed)); 423 // } 424 // } 425 426 /** 427 * Generates a user-specified number of random bytes. 428 * 429 * <p> If a call to {@code setSeed} had not occurred previously, 430 * the first call to this method forces this SecureRandom object 431 * to seed itself. This self-seeding will not occur if 432 * {@code setSeed} was previously called. 433 * 434 * @param bytes the array to be filled in with random bytes. 435 */ 436 // override 437 void nextBytes(byte[] bytes) { 438 // secureRandomSpi.engineNextBytes(bytes); 439 implementationMissing(false); 440 } 441 442 // /** 443 // * Generates an integer containing the user-specified number of 444 // * pseudo-random bits (right justified, with leading zeros). This 445 // * method overrides a {@code java.util.Random} method, and serves 446 // * to provide a source of random bits to all of the methods inherited 447 // * from that class (for example, {@code nextInt}, 448 // * {@code nextLong}, and {@code nextFloat}). 449 // * 450 // * @param numBits number of pseudo-random bits to be generated, where 451 // * {@code 0 <= numBits <= 32}. 452 // * 453 // * @return an {@code int} containing the user-specified number 454 // * of pseudo-random bits (right justified, with leading zeros). 455 // */ 456 // override 457 // final protected int next(int numBits) { 458 // int numBytes = (numBits+7)/8; 459 // byte b[] = new byte[numBytes]; 460 // int next = 0; 461 462 // nextBytes(b); 463 // for (int i = 0; i < numBytes; i++) { 464 // next = (next << 8) + (b[i] & 0xFF); 465 // } 466 467 // return next >>> (numBytes*8 - numBits); 468 // } 469 470 // /** 471 // * Returns the given number of seed bytes, computed using the seed 472 // * generation algorithm that this class uses to seed itself. This 473 // * call may be used to seed other random number generators. 474 // * 475 // * <p>This method is only included for backwards compatibility. 476 // * The caller is encouraged to use one of the alternative 477 // * {@code getInstance} methods to obtain a SecureRandom object, and 478 // * then call the {@code generateSeed} method to obtain seed bytes 479 // * from that object. 480 // * 481 // * @param numBytes the number of seed bytes to generate. 482 // * 483 // * @return the seed bytes. 484 // * 485 // * @see #setSeed 486 // */ 487 // static byte[] getSeed(int numBytes) { 488 // if (seedGenerator is null) { 489 // seedGenerator = new SecureRandom(); 490 // } 491 // return seedGenerator.generateSeed(numBytes); 492 // } 493 494 // /** 495 // * Returns the given number of seed bytes, computed using the seed 496 // * generation algorithm that this class uses to seed itself. This 497 // * call may be used to seed other random number generators. 498 // * 499 // * @param numBytes the number of seed bytes to generate. 500 // * 501 // * @return the seed bytes. 502 // */ 503 // byte[] generateSeed(int numBytes) { 504 // return secureRandomSpi.engineGenerateSeed(numBytes); 505 // } 506 507 // /** 508 // * Helper function to convert a long into a byte array (least significant 509 // * byte first). 510 // */ 511 // private static byte[] longToByteArray(long l) { 512 // byte[] retVal = new byte[8]; 513 514 // for (int i = 0; i < 8; i++) { 515 // retVal[i] = (byte) l; 516 // l >>= 8; 517 // } 518 519 // return retVal; 520 // } 521 522 // /** 523 // * Gets a default PRNG algorithm by looking through all registered 524 // * providers. Returns the first PRNG algorithm of the first provider that 525 // * has registered a SecureRandom implementation, or null if none of the 526 // * registered providers supplies a SecureRandom implementation. 527 // */ 528 // private static string getPrngAlgorithm() { 529 // for (Provider p : Providers.getProviderList().providers()) { 530 // for (Service s : p.getServices()) { 531 // if (s.getType().equals("SecureRandom")) { 532 // return s.getAlgorithm(); 533 // } 534 // } 535 // } 536 // return null; 537 // } 538 539 // /* 540 // * Lazily initialize since Pattern.compile() is heavy. 541 // * Effective Java (2nd Edition), Item 71. 542 // */ 543 // private static final class StrongPatternHolder { 544 // /* 545 // * Entries are alg:prov separated by , 546 // * Allow for prepended/appended whitespace between entries. 547 // * 548 // * Capture groups: 549 // * 1 - alg 550 // * 2 - :prov (optional) 551 // * 3 - prov (optional) 552 // * 4 - ,nextEntry (optional) 553 // * 5 - nextEntry (optional) 554 // */ 555 // private static Pattern pattern = 556 // Pattern.compile( 557 // "\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?"); 558 // } 559 560 // /** 561 // * Returns a {@code SecureRandom} object that was selected by using 562 // * the algorithms/providers specified in the {@code 563 // * securerandom.strongAlgorithms} {@link Security} property. 564 // * <p> 565 // * Some situations require strong random values, such as when 566 // * creating high-value/long-lived secrets like RSA public/private 567 // * keys. To help guide applications in selecting a suitable strong 568 // * {@code SecureRandom} implementation, Java distributions 569 // * include a list of known strong {@code SecureRandom} 570 // * implementations in the {@code securerandom.strongAlgorithms} 571 // * Security property. 572 // * <p> 573 // * Every implementation of the Java platform is required to 574 // * support at least one strong {@code SecureRandom} implementation. 575 // * 576 // * @return a strong {@code SecureRandom} implementation as indicated 577 // * by the {@code securerandom.strongAlgorithms} Security property 578 // * 579 // * @throws NoSuchAlgorithmException if no algorithm is available 580 // * 581 // * @see Security#getProperty(string) 582 // * 583 // * @since 1.8 584 // */ 585 // static SecureRandom getInstanceStrong() 586 // throws NoSuchAlgorithmException { 587 588 // string property = AccessController.doPrivileged( 589 // new PrivilegedAction!string() { 590 // override 591 // string run() { 592 // return Security.getProperty( 593 // "securerandom.strongAlgorithms"); 594 // } 595 // }); 596 597 // if ((property is null) || (property.length() == 0)) { 598 // throw new NoSuchAlgorithmException( 599 // "Null/empty securerandom.strongAlgorithms Security Property"); 600 // } 601 602 // string remainder = property; 603 // while (remainder !is null) { 604 // Matcher m; 605 // if ((m = StrongPatternHolder.pattern.matcher( 606 // remainder)).matches()) { 607 608 // string alg = m.group(1); 609 // string prov = m.group(3); 610 611 // try { 612 // if (prov is null) { 613 // return SecureRandom.getInstance(alg); 614 // } else { 615 // return SecureRandom.getInstance(alg, prov); 616 // } 617 // } catch (NoSuchAlgorithmException | 618 // NoSuchProviderException e) { 619 // } 620 // remainder = m.group(5); 621 // } else { 622 // remainder = null; 623 // } 624 // } 625 626 // throw new NoSuchAlgorithmException( 627 // "No strong SecureRandom impls available: " ~ property); 628 // } 629 630 // // Declare serialVersionUID to be compatible with JDK1.1 631 // // static final long serialVersionUID = 4940670005562187L; 632 633 // // Retain unused values serialized from JDK1.1 634 // /** 635 // * @serial 636 // */ 637 // private byte[] state; 638 // /** 639 // * @serial 640 // */ 641 // private MessageDigest digest = null; 642 // /** 643 // * @serial 644 // * 645 // * We know that the MessageDigest class does not implement 646 // * java.io.Serializable. However, since this field is no longer 647 // * used, it will always be NULL and won't affect the serialization 648 // * of the SecureRandom class itself. 649 // */ 650 // private byte[] randomBytes; 651 // /** 652 // * @serial 653 // */ 654 // private int randomBytesUsed; 655 // /** 656 // * @serial 657 // */ 658 // private long counter; 659 }