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 }