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(SecureRandomParameters)} 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(SecureRandomParameters)}. 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(SecureRandomParameters)}. 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, SecureRandomParameters 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 + dp.getStrength()); 357 } 358 if (result.length > maxNbLength) { 359 throw new IllegalArgumentException("result too long: " 360 + result.length); 361 } 362 byte[] ai = dp.getAdditionalInput(); 363 if (ai != null && ai.length > maxAiLength) { 364 throw new IllegalArgumentException("ai too long: " 365 + ai.length); 366 } 367 instantiateIfNecessary(null); 368 if (reseedCounter > reseedInterval || dp.getPredictionResistance()) { 369 reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()), ai); 370 ai = null; 371 } 372 generateAlgorithm(result, ai); 373 } else { 374 throw new IllegalArgumentException("unknown params type:" 375 + params.getClass()); 376 } 377 } 378 379 @Override 380 public final void engineReseed(SecureRandomParameters params) { 381 if (debug != null) { 382 debug.println("reseed with params"); 383 } 384 if (!supportReseed) { 385 throw new UnsupportedOperationException("Reseed not supported"); 386 } 387 if (params == null) { 388 params = DrbgParameters.reseed(isPr, null); 389 } 390 if (params instanceof DrbgParameters.Reseed) { 391 DrbgParameters.Reseed dp = (DrbgParameters.Reseed) params; 392 if (!isPr && dp.getPredictionResistance()) { 393 throw new IllegalArgumentException("pr not available"); 394 } 395 byte[] ai = dp.getAdditionalInput(); 396 if (ai != null && ai.length > maxAiLength) { 397 throw new IllegalArgumentException("ai too long: " 398 + ai.length); 399 } 400 instantiateIfNecessary(null); 401 reseedAlgorithm(getEntropyInput(dp.getPredictionResistance()), ai); 402 } else { 403 throw new IllegalArgumentException("unknown params type: " 404 + params.getClass()); 405 } 406 } 407 408 /** 409 * Returns the given number of seed bytes. A DRBG always uses its 410 * {@code EntropySource} to get an array with full-entropy. 411 * 412 * @param numBytes the number of seed bytes to generate. 413 * @return the seed bytes. 414 */ 415 @Override 416 public final synchronized byte[] engineGenerateSeed(int numBytes) { 417 return getEntropyInput(numBytes, numBytes, numBytes, isPr); 418 } 419 420 /** 421 * Reseeds this random object with the given seed. A DRBG always expands 422 * or truncates the input to be between {@link #minLength} and 423 * {@link #maxLength} and uses it to instantiate or reseed itself 424 * (depending on whether the DRBG is instantiated). 425 * 426 * @param input the seed 427 */ 428 @Override 429 public final synchronized void engineSetSeed(byte[] input) { 430 // TODO: Will truncate be insecure? hashDF? 431 if (debug != null) { 432 debug.println("setSeed"); 433 } 434 if (input.length < minLength) { 435 input = Arrays.copyOf(input, minLength); 436 } else if (input.length > maxLength) { 437 input = Arrays.copyOf(input, maxLength); 438 } 439 if (!instantiated) { 440 instantiateIfNecessary(input); 441 } else { 442 reseedAlgorithm(input, null); 443 } 444 } 445 446 // get_entropy_input 447 448 private byte[] getEntropyInput(boolean isPr) { 449 // Should the 1st arg be strength or minLength? 450 // 451 // Precisely I think it should be strength, but CtrDRBG 452 // (not using derivation function) is so confusing 453 // (does it need only strength or seedlen of entropy?) 454 // that maybe it's safer to assume minLength. 455 return getEntropyInput(minLength, minLength, maxLength, isPr); 456 } 457 458 private byte[] getEntropyInput(int security, int min, int max, boolean pr) { 459 if (debug != null) { 460 debug.println("getEntropy(" + security + "," + min + "," + max 461 + "," + pr + ")"); 462 } 463 EntropySource esNow = es; 464 if (esNow == null) { 465 esNow = pr? SeederHolder.prseeder: SeederHolder.seeder; 466 } 467 return esNow.getEntropy(security, min, max, pr); 468 } 469 470 // Defaults 471 472 /** 473 * The default {@code EntropySource} determined by system property 474 * "java.security.egd" or security property "securerandom.source". 475 * <p> 476 * This object uses {@link SeedGenerator#generateSeed(byte[])} to 477 * return a byte array containing {@code minLength} bytes. It is 478 * assumed to support prediction resistance and always contains 479 * full-entropy. A trusted application can update this field. 480 */ 481 public static EntropySource defaultES = (entropy, minLen, maxLen, pr) -> { 482 byte[] result = new byte[minLen]; 483 SeedGenerator.generateSeed(result); 484 return result; 485 }; 486 487 private static class SeederHolder { 488 489 /** 490 * Default EntropySource for SecureRandom with prediction resistance, 491 */ 492 static final EntropySource prseeder; 493 494 /** 495 * Default EntropySource for SecureRandom without prediction resistance, 496 * which is backed by a DRBG whose EntropySource is {@link #prseeder}. 497 */ 498 static final EntropySource seeder; 499 500 static { 501 prseeder = defaultES; 502 HashDrbg drbg = new HashDrbg(null); 503 // According to SP800-90C section 7, a DRBG without live 504 // entropy (drbg here, with pr being false) can instantiate 505 // another DRBG with weaker strength. So we choose highest 506 // strength we support. 507 drbg.engineConfigure(new MoreDrbgParameters( 508 prseeder, null, null, null, false, 509 DrbgParameters.instantiate( 510 256, NONE, 511 SeedGenerator.getSystemEntropy()))); 512 seeder = (entropy, minLen, maxLen, pr) -> { 513 if (pr) { 514 // This SEI does not support pr 515 throw new IllegalArgumentException("pr not supported"); 516 } 517 byte[] result = new byte[minLen]; 518 drbg.engineNextBytes(result); 519 return result; 520 }; 521 } 522 } 523 524 // Constructor called by overridden methods, initializer... 525 526 /** 527 * A constructor without argument so that an implementation does not 528 * need to always write {@code super(params)}. 529 */ 530 protected AbstractDrbg() { 531 // Nothing 532 } 533 534 /** 535 * A mechanism shall override this constructor to setup {@link #mechName}, 536 * {@link #highestSecurity}, {@link #supportPr}, {@link #supportReseed} 537 * or other features like {@link #defaultStrength}. Finally it shall 538 * call {@link #configureInternal} on {@code params}. 539 * 540 * @param params the {@link SecureRandomParameters} object. 541 * This argument can be {@code null}. 542 * @throws IllegalArgumentException if {@code params} is 543 * inappropriate for this SecureRandom. 544 */ 545 protected AbstractDrbg(SecureRandomParameters params) { 546 // Nothing 547 } 548 549 protected void register(Map<Object, Object> map) { 550 String name = "SecureRandom." + mechName; 551 map.put(name, this.getClass().getName()); 552 map.put(name + " ImplementedIn", "Software"); 553 map.put(name + " DRBG.supportPr", Boolean.toString(supportPr)); 554 map.put(name + " DRBG.highestSecurity", Integer.toString(highestSecurity)); 555 map.put(name + " DRBG.supportReseed", Boolean.toString(supportReseed)); 556 map.put(name + " DRBG.defaultStrength", Integer.toString(defaultStrength)); 557 } 558 559 /** 560 * Returns the current configuration as a {@link DrbgParameters.Instantiate} 561 * object. 562 * 563 * @return the curent configuration 564 */ 565 @Override 566 protected SecureRandomParameters engineGetParameters() { 567 // Or read from variable. 568 return DrbgParameters.instantiate( 569 strength, 570 isPr? PR_AND_RESEED: (supportReseed? RESEED_ONLY: NONE), 571 ps); 572 } 573 574 /** 575 * A helper function that calls {@link #engineConfigure}. 576 * 577 * @param params if null, default configuration (default strength, 578 * pr_false, no personalization string) will be used. 579 * @throws IllegalArgumentException if {@code params} is 580 * inappropriate for this SecureRandom. 581 */ 582 protected void configureInternal(SecureRandomParameters params) { 583 if (params == null) { 584 params = DrbgParameters.instantiate(-1, RESEED_ONLY, null); 585 } 586 engineConfigure(params); 587 } 588 589 /** 590 * Configure this DRBG. This method calls {@link #chooseAlgorithmAndStrength()} 591 * and {@link #initEngine()} but does not do the actual instantiation. 592 * 593 * @param params configuration, cannot be null 594 * @throws IllegalArgumentException if {@code params} is 595 * inappropriate for this SecureRandom. 596 */ 597 //@Override 598 protected final synchronized void engineConfigure( 599 SecureRandomParameters params) { 600 if (debug != null) { 601 debug.println("configure " + this + " with " + params); 602 } 603 if (params instanceof MoreDrbgParameters) { 604 MoreDrbgParameters m = (MoreDrbgParameters)params; 605 this.requestedNonce = m.nonce; 606 this.es = m.es; 607 this.requestedAlgorithm = m.algorithm; 608 this.usedf = m.usedf; 609 params = m.config; 610 } 611 if (params != null) { 612 if (params instanceof DrbgParameters.Instantiate) { 613 DrbgParameters.Instantiate config = (DrbgParameters.Instantiate) params; 614 if (config.getStrength() > highestSecurity) { 615 throw new IllegalArgumentException("strength too big: " 616 + config.getStrength()); 617 } 618 byte[] ps = config.getPersonalizationString(); 619 if (ps != null && ps.length > maxPsLength) { 620 throw new IllegalArgumentException("ps too long: " 621 + ps.length); 622 } 623 if (config.getCapability().supportsPredictionResistance() 624 && !supportPr) { 625 throw new IllegalArgumentException("pr not supported"); 626 } 627 if (config.getCapability().supportsReseeding() 628 && !supportReseed) { 629 throw new IllegalArgumentException("reseed not supported"); 630 } 631 this.ps = ps; 632 this.isPr = config.getCapability().supportsPredictionResistance(); 633 this.requestedStrength = config.getStrength(); 634 } else { 635 throw new IllegalArgumentException("unknown params: " 636 + params.getClass()); 637 } 638 } 639 chooseAlgorithmAndStrength(); 640 instantiated = false; 641 if (debug != null) { 642 debug.println("configured " + this); 643 } 644 } 645 646 /** 647 * Instantiate if necessary, 648 * 649 * @param entropy a user-provided entropy, the length is already good. 650 * If null, will fetch entropy input automatically. 651 */ 652 private synchronized void instantiateIfNecessary(byte[] entropy) { 653 if (!instantiated) { 654 if (debug != null) { 655 debug.println("instantiate"); 656 } 657 if (strength <= 0) { // not configured at all 658 chooseAlgorithmAndStrength(); 659 } 660 // 1-4. strength/ps/pr check 661 // 5. Null 662 // 6/7. Get entropy. TODO: 1st arg security strength? 663 if (entropy == null) { 664 entropy = getEntropyInput(isPr); 665 } 666 // 8. nonce 667 if (requestedNonce != null) { 668 nonce = requestedNonce; 669 } else { 670 nonce = longToByteArray(cc.incrementAndGet()); 671 } 672 // 9. instantiate 673 initEngine(); 674 instantiateAlgorithm(entropy); 675 instantiated = true; 676 } 677 } 678 679 // Nonce provider 680 681 /** 682 * Helper function to convert a long into a byte array (least significant 683 * byte first). 684 */ 685 private static byte[] longToByteArray(long l) { 686 byte[] retVal = new byte[16]; 687 retVal[0] = 's'; 688 retVal[1] = 'u'; 689 retVal[2] = 'n'; 690 retVal[3] = '.'; 691 retVal[4] = 'd'; 692 retVal[5] = 'r'; 693 retVal[6] = 'b'; 694 retVal[7] = 'g'; 695 for (int i = 0; i < 8; i++) { 696 retVal[i+8] = (byte) l; 697 l >>= 8; 698 } 699 return retVal; 700 } 701 702 private static AtomicLong cc = new AtomicLong(0); 703 704 // Misc 705 706 /** A handy method returning hexdump string with no colon or new line. 707 * 708 * @param in input byte array 709 * @return the hexdump string 710 */ 711 protected static String hex(byte[] in) { 712 StringBuilder sb = new StringBuilder(); 713 for (byte b: in) { 714 sb.append(String.format("%02x", b&0xff)); 715 } 716 return sb.toString(); 717 } 718 719 /** 720 * Returns the smallest standard strength (112, 128, 192, 256) that is 721 * greater or equal to the input. 722 * 723 * @param input the input strength 724 * @return the standard strength 725 */ 726 protected static int getStandardStrength(int input) { 727 if (input <= 112) return 112; 728 if (input <= 128) return 128; 729 if (input <= 192) return 192; 730 if (input <= 256) return 256; 731 throw new IllegalArgumentException("input too big: " + input); 732 } 733 734 @Override 735 public String toString() { 736 return mechName + "," + algorithm 737 + "," + strength + "," 738 + (isPr?"pr_and_reseed":(supportReseed?"reseed_only":"none")); 739 } 740 }