--- /dev/null 2016-04-05 10:17:03.000000000 +0800 +++ new/src/java.base/share/classes/sun/security/provider/HashDrbg.java 2016-04-05 10:17:03.000000000 +0800 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.provider; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.DigestException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandomParameters; +import java.util.Arrays; + +public class HashDrbg extends AbstractHashDrbg { + + private static final long serialVersionUID = 9L; + + private static final byte[] ZERO= new byte[1]; + private static final byte[] ONE = new byte[]{1}; + + private transient MessageDigest digest; + + private byte[] v; + private byte[] c; + + public HashDrbg(SecureRandomParameters params) { + mechName = "Hash_DRBG"; + configureInternal(params); + } + + /** + * This call, used by the constructors, instantiates the digest. + */ + @Override + protected void initEngine() { + if (algorithm == null) { + return; + } + try { + /* + * Use the local SUN implementation to avoid native + * performance overhead. + */ + digest = MessageDigest.getInstance(algorithm, "SUN"); + } catch (NoSuchProviderException | NoSuchAlgorithmException e) { + // Fallback to any available. + try { + digest = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException exc) { + throw new InternalError( + "internal error: " + algorithm + " not available.", exc); + } + } + } + + private byte[] hashDf(int requested, byte[]... inputs) { + return hashDf(digest, outLen, requested, inputs); + } + + /** + * A hash-based derivation function defined in NIST SP 800-90Ar1 10.3.1. + * The function is used inside Hash_DRBG, and can also be used as an + * approved conditioning function as described in 800-90B 6.4.2.2. + * + * @param digest a {@code MessageDigest} object in reset state + * @param outLen {@link MessageDigest#getDigestLength} of {@code digest} + * @param requested requested output length, in bytes + * @param inputs input data + * @return the condensed/expanded output + */ + public static byte[] hashDf(MessageDigest digest, int outLen, + int requested, byte[]... inputs) { + int len = (requested + outLen - 1) / outLen; + byte[] temp = new byte[len * outLen]; + int counter = 1; + + for (int i=0; i> 21)); // requested*8 as int32 + digest.update((byte)(requested >> 13)); + digest.update((byte)(requested >> 5)); + digest.update((byte)(requested << 3)); + for (byte[] input: inputs) { + digest.update(input); + } + try { + digest.digest(temp, i * outLen, outLen); + } catch (DigestException e) { + throw new AssertionError("will not happen"); + } + counter++; + } + return temp.length == requested? temp: Arrays.copyOf(temp, requested); + } + + // For seeding, input is entropy_input || nonce || personalization_string; + // for reseeding, input is entropy_input || additional_input + @Override + protected final void hashReseedInternal(byte[] input) { + byte[] seed; + if (v != null) { + seed = hashDf(seedLen, ONE, v, input); + } else { + seed = hashDf(seedLen, input); + } + v = seed; + c = hashDf(seedLen, ZERO, v); + reseedCounter = 1; + status(); + } + + private void status() { + if (debug != null) { + debug.println("V = " + hex(v)); + debug.println("C = " + hex(c)); + debug.println("reseed counter = " + reseedCounter); + } + } + + /** + * Adds byte arrays into an existing one. + * + * @param out existing array + * @param data more arrays, can be of different length + */ + private static void addBytes(byte[] out, int len, byte[]... data) { + for (byte[] d: data) { + int dlen = d.length; + int carry = 0; + for (int i=0; i> 8; + if (i >= dlen - 1 && carry == 0) break; + } + } + } + + /** + * Generates a user-specified number of random bytes. + * + * @param result the array to be filled in with random bytes. + */ + @Override + public final synchronized void generateAlgorithm( + byte[] result, byte[] additionalInput) { + + if (debug != null) { + debug.println("generateAlgorithm"); + } + if (additionalInput != null) { + digest.update((byte)2); + digest.update(v); + digest.update(additionalInput); + addBytes(v, seedLen, digest.digest()); + } + + // Step 3. + hashGen(result, result.length, v); + + // Step 4. + digest.update((byte)3); + digest.update(v); + byte[] h = digest.digest(); + + // Step 5. + byte[] rcBytes; + if (reseedCounter < 256) { + rcBytes = new byte[]{(byte)reseedCounter}; + } else { + rcBytes = BigInteger.valueOf(reseedCounter).toByteArray(); + } + addBytes(v, seedLen, h, c, rcBytes); + + // Step 6. + reseedCounter++; + + status(); + } + + private void hashGen(byte[] output, int len, byte[] v) { + int m = (len + outLen - 1) / outLen; + byte[] data = v; + for (int i=0; i