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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.provider; 27 28 import sun.security.util.Debug; 29 30 import java.security.*; 31 import java.util.Arrays; 32 import java.util.Map; 33 import java.util.concurrent.atomic.AtomicLong; 34 import static java.security.DrbgParameters.Capability.*; 35 36 /** 37 * The abstract base class for all DRBGs. 38 * <p> 39 * This class creates 5 new abstract methods. 3 are defined by the SP800-90A: 40 * <ol> 41 * <li>{@link #generateAlgorithm(byte[], byte[])} 42 * <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported) 43 * <li>{@link #instantiateAlgorithm(byte[])} 44 * </ol> 45 * and 2 for implementation purpose: 46 * <ol> 47 * <li>{@link #initEngine()} 48 * <li>{@link #chooseAlgorithmAndStrength} 49 * </ol> 50 * All existing {@link SecureRandomSpi} methods are implemented based on the 51 * methods above as final. The instantiate process is divided into 2 phases: 52 * configuration is eagerly called to set up parameters, and instantiation 53 * is lazily called only when nextBytes or reseed is called. 54 */ 55 public abstract class AbstractDrbg extends SecureRandomSpi { 56 57 // synchronized keyword should be added to all externally callable engine 58 // methods including engineGenerateSeed, engineReseed, engineSetSeed 59 // and engineNextBytes. Internally engine methods like engineConfigure 60 // and instantiateAlgorithm are not synchronized. They will either be 61 // called in a constructor or in another synchronized method. 62 63 // Precisely engineGenerateSeed does not need to be synchronized since 64 // it does not modify any internal states after configuration is 65 // complete, but the configuration itself can be called by other engine 66 // methods and should be synchronized. My understanding is that the 67 // engineGenerateSeed method is not used much and it's not worth 68 // creating a lock for the configuration itself. 69 70 private static final long serialVersionUID = 9L; 71 72 /** 73 * This field is not null if {@code -Djava.security.debug=securerandom} is 74 * specified on the command line. An implementation can print useful 75 * debug info. 76 */ 77 protected static final Debug debug = Debug.getInstance( 78 "securerandom", "drbg"); 79 80 // Common working status 81 82 private boolean instantiated = false; 83 84 /** 85 * Reseed counter of a DRBG instance. A mechanism should increment it 86 * after each random bits generation and reset it in reseed. A mechanism 87 * does <em>not</em> need to compare it to {@link #reseedInterval}. 88 */ 89 protected int reseedCounter = 0; 90 91 // Mech features. If not same as below, must be redefined in constructor. 92 93 /** 94 * Default strength of a DRBG instance if it is not configured. 95 * 128 is considered secure enough now. A mechanism 96 * can change it in a constructor. 97 * 98 * The default here is described in comments of the "drbg" security property. 99 */ 100 protected static final int defaultStrength = 128; 101 102 /** 103 * Mechanism name, say, {@code HashDRBG}. Must be set in constructor. 104 * This value will be used in {@code toString}. 105 */ 106 protected String mechName = "DRBG"; 107 108 /** 109 * highest_supported_security_strength of this mechanism for all algorithms 110 * it supports. A mechanism should update the value in its constructor 111 * if the value is not 256. 112 */ 113 protected int highestSecurity = 256; 114 115 /** 116 * Whether prediction resistance is supported. A mechanism should update 117 * the value in its constructor if it is <em>not</em> supported. 118 */ 119 protected boolean supportPr = true; 120 121 /** 122 * Whether reseed is supported. A mechanism should update 123 * the value in its constructor if it is <em>not</em> supported. 124 */ 125 protected boolean supportReseed = true; 126 127 // Strength features. If not same as below, must be redefined in 128 // chooseAlgorithmAndStrength. Among these, minLength and seedLen have no 129 // default value and must be redefined. If personalization string or 130 // additional input is not supported, set maxPsLength or 131 // maxAiLength to -1. 132 133 /** 134 * Minimum entropy input length in bytes for this DRBG instance. 135 * Must be assigned in {@link #chooseAlgorithmAndStrength}. 136 */ 137 protected int minLength; 138 139 /** 140 * Maximum entropy input length in bytes for this DRBG instance. 141 * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not 142 * {@link Integer#MAX_VALUE}. 143 */ 144 protected int maxLength = Integer.MAX_VALUE; 145 146 /** 147 * Maximum personalization string length in bytes for this DRBG instance. 148 * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not 149 * {@link Integer#MAX_VALUE}. 150 */ 151 protected int maxPsLength = Integer.MAX_VALUE; 152 153 /** 154 * Maximum additional input length in bytes for this DRBG instance. 155 * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not 156 * {@link Integer#MAX_VALUE}. 157 */ 158 protected int maxAiLength = Integer.MAX_VALUE; 159 160 /** 161 * max_number_of_bits_per_request in bytes for this DRBG instance. 162 * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not 163 * {@link Integer#MAX_VALUE}. 164 */ 165 protected int maxNbLength = Integer.MAX_VALUE; 166 167 /** 168 * Maximum number of requests between reseeds for this DRBG instance. 169 * Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not 170 * {@link Integer#MAX_VALUE}. 171 */ 172 protected int reseedInterval = Integer.MAX_VALUE; 173 174 175 /** 176 * Algorithm used by this instance (SHA-512 or AES-256). Must be assigned 177 * in {@link #chooseAlgorithmAndStrength}. This field is used in 178 * {@link #toString()}. 179 */ 180 protected String algorithm; 181 182 // Configurable parameters 183 184 /** 185 * Security strength for this instance. Must be assigned in 186 * {@link #chooseAlgorithmAndStrength}. Should be at least the requested 187 * strength. Might be smaller than the highest strength 188 * {@link #algorithm} supports. Must not be -1. 189 */ 190 protected int strength; // in bits 191 192 /** 193 * Strength requested in {@link DrbgParameters.Instantiate}. 194 * The real strength is based on it. Do not modify it in a mechanism. 195 */ 196 protected int requestedStrength = -1; 197 198 /** 199 * The personalization string used by this instance. Set inside 200 * {@link #engineConfigure(SecureRandomInstantiateParameters)} and 201 * can be used in a mechanism. Do not modify it in a mechanism. 202 */ 203 protected byte[] ps; 204 205 /** 206 * The prediction resistance flag used by this instance. Set inside 207 * {@link #engineConfigure(SecureRandomInstantiateParameters)}. 208 */ 209 private boolean isPr; 210 211 // Non-standard configurable parameters 212 213 /** 214 * Whether a derivation function is used. Requested in 215 * {@link MoreDrbgParameters}. Only CtrDRBG uses it. 216 * Do not modify it in a mechanism. 217 */ 218 protected boolean usedf; 219 220 /** 221 * The nonce for this instance. Set in {@link #instantiateIfNecessary}. 222 * After instantiation, this field is not null. Do not modify it 223 * in a mechanism. 224 */ 225 protected byte[] nonce; 226 227 /** 228 * Requested nonce in {@link MoreDrbgParameters}. If set to null, 229 * nonce will be chosen by system, and a reinstantiated DRBG will get a 230 * new system-provided nonce. 231 */ 232 private byte[] requestedNonce; 233 234 /** 235 * Requested algorithm in {@link MoreDrbgParameters}. 236 * Do not modify it in a mechanism. 237 */ 238 protected String requestedAlgorithm; 239 240 /** 241 * The prediction resistance flag used by this instance. Set inside 242 * {@link #engineConfigure(SecureRandomInstantiateParameters)}. This field 243 * can be null. {@link #getEntropyInput} will take care of null check. 244 */ 245 private transient EntropySource es; 246 247 // Five abstract methods for SP 800-90A DRBG 248 249 /** 250 * Decides what algorithm and strength to use (SHA-256 or AES-256, 251 * 128 or 256). Strength related fields must also be defined or redefined 252 * here. Called in {@link #engineConfigure}. A mechanism uses 253 * {@link #requestedAlgorithm}, {@link #requestedStrength}, and 254 * {@link #defaultStrength} to decide which algorithm and strength to use. 255 * <p> 256 * If {@code requestedAlgorithm} is provided, it will always be used. 257 * If {@code requestedStrength} is also provided, the algorithm will use 258 * the strength (an exception will be thrown if the strength is not 259 * supported), otherwise, the smaller one of the highest supported strength 260 * of the algorithm and the default strength will be used. 261 * <p> 262 * If {@code requestedAlgorithm} is not provided, an algorithm will be 263 * chosen that supports {@code requestedStrength} 264 * (or {@code defaultStrength} if there is no request). 265 * <p> 266 * Since every call to {@link #engineConfigure} will call this method, 267 * make sure to the calls do not contradict with each other. 268 * <p> 269 * Here are some examples of the algorithm and strength chosen (suppose 270 * {@code defaultStrength} is 128) for HashDRBG: 271 * <pre> 272 * (requestedAlg,requestedStrength) Algorithm Strength 273 * (SHA-1, -1) SHA-1 128 274 * (SHA-1, 112) SHA-1 112 275 * (SHA-1, 192) error error 276 * (SHA-256, -1) SHA-256 128 277 * (SHA-256, 128) SHA-256 128 278 * (SHA-3, -1) error error 279 * (null, -1) SHA-256 128 280 * (null, 112) SHA-256 112 281 * (null, 192) SHA-256 192 282 * (null, 256) SHA-256 256 283 * (null, 384) error error 284 * </pre> 285 * 286 * @throws IllegalArgumentException if the requested parameters 287 * can not be supported or contradict with each other. 288 */ 289 protected abstract void chooseAlgorithmAndStrength(); 290 291 /** 292 * Initiates security engines ({@code MessageDigest}, {@code Mac}, 293 * or {@code Cipher}). Must be called in deserialization. Please note 294 * that before instantiation the algorithm might not be available yet. 295 * In this case, just return and this method will be called 296 * automatically at instantiation. 297 */ 298 protected abstract void initEngine(); 299 300 /** 301 * Instantiates a DRBG. Called automatically before the first 302 * {@code nextBytes} call. 303 * <p> 304 * Note that the other parameters (nonce, strength, ps) are already 305 * stored inside at configuration. 306 * 307 * @param ei the entropy input, its length is already conditioned to be 308 * between {@link #minLength} and {@link #maxLength}. 309 */ 310 protected abstract void instantiateAlgorithm(byte[] ei); 311 312 /** 313 * The generate function. 314 * 315 * @param result fill result here, not null 316 * @param additionalInput additional input, can be null. If not null, 317 * its length is smaller than {@link #maxAiLength} 318 */ 319 protected abstract void generateAlgorithm( 320 byte[] result, byte[] additionalInput); 321 322 /** 323 * The reseed function. 324 * 325 * @param ei the entropy input, its length is already conditioned to be 326 * between {@link #minLength} and {@link #maxLength}. 327 * @param additionalInput additional input, can be null. If not null, 328 * its length is smaller than {@link #maxAiLength} 329 * @throws UnsupportedOperationException if reseed is not supported 330 */ 331 protected void reseedAlgorithm( 332 byte[] ei, byte[] additionalInput) { 333 throw new UnsupportedOperationException("No reseed function"); 334 } 335 336 // SecureRandomSpi methods taken care of here. All final. 337 338 @Override 339 protected final void engineNextBytes(byte[] result) { 340 engineNextBytes(result, DrbgParameters.nextBytes(-1, isPr, null)); 341 } 342 343 @Override 344 protected final void engineNextBytes( 345 byte[] result, SecureRandomNextBytesParameters params) { 346 if (debug != null) { 347 debug.println("nextBytes"); 348 } 349 if (params instanceof DrbgParameters.NextBytes) { 350 DrbgParameters.NextBytes dp = (DrbgParameters.NextBytes) params; 351 if (!isPr && dp.getPredictionResistance()) { 352 throw new IllegalArgumentException("pr not available"); 353 } 354 if (dp.getStrength() > strength) { 355 throw new IllegalArgumentException("strength too high"); 356 } 357 if (result.length > maxNbLength) { 358 throw new IllegalArgumentException("result too long"); 359 } 360 byte[] ai = dp.getAdditionalInput(); 361 if (dp.getAdditionalInput() != null && dp.getAdditionalInput().length > maxAiLength) { 362 throw new IllegalArgumentException("ai too long"); 363 } 364 instantiateIfNecessary(null); 365 if (reseedCounter > reseedInterval || dp.getPredictionResistance()) { 366 reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()), ai); 367 ai = null; 368 } 369 generateAlgorithm(result, ai); 370 } else { 371 throw new IllegalArgumentException("unknown params type"); 372 } 373 } 374 375 @Override 376 public final void engineReseed(SecureRandomReseedParameters params) { 377 if (debug != null) { 378 debug.println("reseed with params"); 379 } 380 if (!supportReseed) { 381 throw new UnsupportedOperationException("Reseed not supported"); 382 } 383 if (params == null) { 384 params = DrbgParameters.reseed(isPr, null); 385 } 386 if (params instanceof DrbgParameters.Reseed) { 387 DrbgParameters.Reseed dp = (DrbgParameters.Reseed) params; 388 if (!isPr && dp.getPredictionResistance()) { 389 throw new IllegalArgumentException("pr not available"); 390 } 391 if (dp.getAdditionalInput() != null && dp.getAdditionalInput().length > maxAiLength) { 392 throw new IllegalArgumentException("ai too long"); 393 } 394 instantiateIfNecessary(null); 395 reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()), 396 dp.getAdditionalInput()); 397 } else { 398 throw new IllegalArgumentException("unknown params type"); 399 } 400 } 401 402 /** 403 * Returns the given number of seed bytes. A DRBG always uses its 404 * {@code EntropySource} to get an array with full-entropy. 405 * 406 * @param numBytes the number of seed bytes to generate. 407 * @return the seed bytes. 408 */ 409 @Override 410 public final synchronized byte[] engineGenerateSeed(int numBytes) { 411 return getEntropyInput(numBytes, numBytes, numBytes, isPr); 412 } 413 414 /** 415 * Reseeds this random object with the given seed. A DRBG always expands 416 * or truncates the input to be between {@link #minLength} and 417 * {@link #maxLength} and uses it to instantiate or reseed itself 418 * (depending on whether the DRBG is instantiated). 419 * 420 * @param input the seed 421 */ 422 @Override 423 public final synchronized void engineSetSeed(byte[] input) { 424 // TODO: Will truncate be insecure? hashDF? 425 if (debug != null) { 426 debug.println("setSeed"); 427 } 428 if (input.length < minLength) { 429 input = Arrays.copyOf(input, minLength); 430 } else if (input.length > maxLength) { 431 input = Arrays.copyOf(input, maxLength); 432 } 433 if (!instantiated) { 434 instantiateIfNecessary(input); 435 } else { 436 reseedAlgorithm(input, null); 437 } 438 } 439 440 // get_entropy_input 441 442 private byte[] getEntropyInput(boolean isPr) { 443 // Should the 1st arg be strength or minLength? 444 // 445 // Precisely I think it should be strength, but CtrDRBG 446 // (not using derivation function) is so confusing 447 // (does it need only strength or seedlen of entropy?) 448 // that maybe it's safer to assume minLength. 449 return getEntropyInput(minLength, minLength, maxLength, isPr); 450 } 451 452 private byte[] getEntropyInput(int security, int min, int max, boolean pr) { 453 if (debug != null) { 454 debug.println("getEntropy(" + security + "," + min + "," + max 455 + "," + pr + ")"); 456 } 457 EntropySource esNow = es; 458 if (esNow == null) { 459 esNow = pr? SeederHolder.prseeder: SeederHolder.seeder; 460 } 461 return esNow.getEntropy(security, min, max, pr); 462 } 463 464 // Defaults 465 466 /** 467 * The default {@code EntropySource} determined by system property 468 * "java.security.egd" or security property "securerandom.source". 469 * <p> 470 * This object uses {@link SeedGenerator#generateSeed(byte[])} to 471 * return a byte array containing {@code minLength} bytes. It is 472 * assumed to support prediction resistance and always contains 473 * full-entropy. A trusted application can update this field. 474 */ 475 public static EntropySource defaultES = (entropy, minLen, maxLen, pr) -> { 476 byte[] result = new byte[minLen]; 477 SeedGenerator.generateSeed(result); 478 return result; 479 }; 480 481 private static class SeederHolder { 482 483 /** 484 * Default EntropySource for SecureRandom with prediction resistance, 485 */ 486 static final EntropySource prseeder; 487 488 /** 489 * Default EntropySource for SecureRandom without prediction resistance, 490 * which is backed by a DRBG whose EntropySource is {@link #prseeder}. 491 */ 492 static final EntropySource seeder; 493 494 static { 495 prseeder = defaultES; 496 HashDrbg drbg = new HashDrbg(null); 497 // According to SP800-90C section 7, a DRBG without live 498 // entropy (drbg here, with pr being false) can instantiate 499 // another DRBG with weaker strength. So we choose highest 500 // strength we support. 501 drbg.engineConfigure(new MoreDrbgParameters( 502 prseeder, null, null, null, false, 503 DrbgParameters.instantiate( 504 256, NONE, 505 SeedGenerator.getSystemEntropy()))); 506 seeder = (entropy, minLen, maxLen, pr) -> { 507 if (pr) { 508 // This SEI does not support pr 509 throw new IllegalArgumentException(); 510 } 511 byte[] result = new byte[minLen]; 512 drbg.engineNextBytes(result); 513 return result; 514 }; 515 } 516 } 517 518 // Constructor called by overridden methods, initializer... 519 520 /** 521 * A constructor without argument so that an implementation does not 522 * need to always write {@code super(params)}. 523 */ 524 protected AbstractDrbg() { 525 // Nothing 526 } 527 528 /** 529 * A mechanism shall override this constructor to setup {@link #mechName}, 530 * {@link #highestSecurity}, {@link #supportPr}, {@link #supportReseed} 531 * or other features like {@link #defaultStrength}. Finally it shall 532 * call {@link #configureInternal} on {@code params}. 533 * 534 * @param params the {@link SecureRandomInstantiateParameters} object. 535 * This argument can be {@code null}. 536 * @throws IllegalArgumentException if {@code params} is 537 * inappropriate for this SecureRandom. 538 */ 539 protected AbstractDrbg(SecureRandomInstantiateParameters params) { 540 // Nothing 541 } 542 543 protected void register(Map<Object, Object> map) { 544 String name = "SecureRandom." + mechName; 545 map.put(name, this.getClass().getName()); 546 map.put(name + " ImplementedIn", "Software"); 547 map.put(name + " DRBG.supportPr", Boolean.toString(supportPr)); 548 map.put(name + " DRBG.highestSecurity", Integer.toString(highestSecurity)); 549 map.put(name + " DRBG.supportReseed", Boolean.toString(supportReseed)); 550 map.put(name + " DRBG.defaultStrength", Integer.toString(defaultStrength)); 551 } 552 553 /** 554 * Returns the current configuration as a {@link DrbgParameters.Instantiate} 555 * object. 556 * 557 * @return the curent configuration 558 */ 559 @Override 560 protected SecureRandomInstantiateParameters engineGetParameters() { 561 // Or read from variable. 562 return DrbgParameters.instantiate( 563 strength, 564 isPr? PR_AND_RESEED: (supportReseed? RESEED_ONLY: NONE), 565 ps); 566 } 567 568 /** 569 * A helper function that calls {@link #engineConfigure}. 570 * 571 * @param params if null, default configuration (default strength, 572 * pr_false, no personalization string) will be used. 573 * @throws IllegalArgumentException if {@code params} is 574 * inappropriate for this SecureRandom. 575 */ 576 protected void configureInternal(SecureRandomInstantiateParameters params) { 577 if (params == null) { 578 params = DrbgParameters.instantiate(-1, RESEED_ONLY, null); 579 } 580 engineConfigure(params); 581 } 582 583 /** 584 * Configure this DRBG. This method calls {@link #chooseAlgorithmAndStrength()} 585 * and {@link #initEngine()} but does not do the actual instantiation. 586 * 587 * @param params configuration, cannot be null 588 * @throws IllegalArgumentException if {@code params} is 589 * inappropriate for this SecureRandom. 590 */ 591 //@Override 592 protected final synchronized void engineConfigure( 593 SecureRandomInstantiateParameters params) { 594 if (debug != null) { 595 debug.println("configure " + this + " with " + params); 596 } 597 if (params instanceof MoreDrbgParameters) { 598 MoreDrbgParameters m = (MoreDrbgParameters)params; 599 this.requestedNonce = m.nonce; 600 this.es = m.es; 601 this.requestedAlgorithm = m.algorithm; 602 this.usedf = m.usedf; 603 params = m.config; 604 } 605 if (params != null) { 606 if (params instanceof DrbgParameters.Instantiate) { 607 DrbgParameters.Instantiate config = (DrbgParameters.Instantiate) params; 608 if (config.getStrength() > highestSecurity) { 609 throw new IllegalArgumentException("strength too big"); 610 } 611 if (config.getPersonalizationString() != null && config.getPersonalizationString().length > maxPsLength) { 612 throw new IllegalArgumentException("ps too long"); 613 } 614 if ((config.getCapability() == PR_AND_RESEED) 615 && !supportPr) { 616 throw new IllegalArgumentException("pr not supported"); 617 } 618 if ((config.getCapability() == PR_AND_RESEED || config.getCapability() == RESEED_ONLY) 619 && !supportReseed) { 620 throw new IllegalArgumentException("reseed not supported"); 621 } 622 this.ps = config.getPersonalizationString(); 623 this.isPr = config.getCapability() == PR_AND_RESEED; 624 this.requestedStrength = config.getStrength(); 625 } else { 626 throw new IllegalArgumentException("unknown params"); 627 } 628 } 629 chooseAlgorithmAndStrength(); 630 instantiated = false; 631 if (debug != null) { 632 debug.println("configured " + this); 633 } 634 } 635 636 /** 637 * Instantiate if necessary, 638 * 639 * @param entropy a user-provided entropy, the length is already good. 640 * If null, will fetch entropy input automatically. 641 */ 642 private synchronized void instantiateIfNecessary(byte[] entropy) { 643 if (!instantiated) { 644 if (debug != null) { 645 debug.println("instantiate"); 646 } 647 if (strength <= 0) { // not configured at all 648 chooseAlgorithmAndStrength(); 649 } 650 // 1-4. strength/ps/pr check 651 // 5. Null 652 // 6/7. Get entropy. TODO: 1st arg security strength? 653 if (entropy == null) { 654 entropy = getEntropyInput(isPr); 655 } 656 // 8. nonce 657 if (requestedNonce != null) { 658 nonce = requestedNonce; 659 } else { 660 nonce = longToByteArray(cc.incrementAndGet()); 661 } 662 // 9. instantiate 663 initEngine(); 664 instantiateAlgorithm(entropy); 665 instantiated = true; 666 } 667 } 668 669 // Nonce provider 670 671 /** 672 * Helper function to convert a long into a byte array (least significant 673 * byte first). 674 */ 675 private static byte[] longToByteArray(long l) { 676 byte[] retVal = new byte[16]; 677 retVal[0] = 's'; 678 retVal[1] = 'u'; 679 retVal[2] = 'n'; 680 retVal[3] = '.'; 681 retVal[4] = 'd'; 682 retVal[5] = 'r'; 683 retVal[6] = 'b'; 684 retVal[7] = 'g'; 685 for (int i = 0; i < 8; i++) { 686 retVal[i+8] = (byte) l; 687 l >>= 8; 688 } 689 return retVal; 690 } 691 692 private static AtomicLong cc = new AtomicLong(0); 693 694 // Misc 695 696 /** A handy method returning hexdump string with no colon or new line. 697 * 698 * @param in input byte array 699 * @return the hexdump string 700 */ 701 protected static String hex(byte[] in) { 702 StringBuilder sb = new StringBuilder(); 703 for (byte b: in) { 704 sb.append(String.format("%02x", b&0xff)); 705 } 706 return sb.toString(); 707 } 708 709 /** 710 * Returns the smallest standard strength (112, 128, 192, 256) that is 711 * greater or equal to the input. 712 * 713 * @param input the input strength 714 * @return the standard strength 715 */ 716 protected static int getStandardStrength(int input) { 717 if (input <= 112) return 112; 718 if (input <= 128) return 128; 719 if (input <= 192) return 192; 720 if (input <= 256) return 256; 721 throw new IllegalArgumentException("input too big: " + input); 722 } 723 724 @Override 725 public String toString() { 726 return mechName + "," + algorithm 727 + "," + strength + "," 728 + (isPr?"pr_and_reseed":(supportReseed?"reseed_only":"none")); 729 } 730 }