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 }