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 26package sun.security.provider; 27 28import java.math.BigInteger; 29import java.security.DigestException; 30import java.security.MessageDigest; 31import java.security.NoSuchAlgorithmException; 32import java.security.NoSuchProviderException; 33import java.security.SecureRandomParameters; 34import java.util.ArrayList; 35import java.util.Arrays; 36import java.util.List; 37 38public class HashDrbg extends AbstractHashDrbg { 39 40 private static final byte[] ZERO = new byte[1]; 41 private static final byte[] ONE = new byte[]{1}; 42 43 private MessageDigest digest; 44 45 private byte[] v; 46 private byte[] c; 47 48 public HashDrbg(SecureRandomParameters params) { 49 mechName = "Hash_DRBG"; 50 configure(params); 51 } 52 53 /** 54 * This call, used by the constructors, instantiates the digest. 55 */ 56 @Override 57 protected void initEngine() { 58 try { 59 /* 60 * Use the local SUN implementation to avoid native 61 * performance overhead. 62 */ 63 digest = MessageDigest.getInstance(algorithm, "SUN"); 64 } catch (NoSuchProviderException | NoSuchAlgorithmException e) { 65 // Fallback to any available. 66 try { 67 digest = MessageDigest.getInstance(algorithm); 68 } catch (NoSuchAlgorithmException exc) { 69 throw new InternalError( 70 "internal error: " + algorithm + " not available.", exc); 71 } 72 } 73 } 74 75 private byte[] hashDf(int requested, List<byte[]> inputs) { 76 return hashDf(digest, outLen, requested, inputs); 77 } 78 79 /** 80 * A hash-based derivation function defined in NIST SP 800-90Ar1 10.3.1. 81 * The function is used inside Hash_DRBG, and can also be used as an 82 * approved conditioning function as described in 800-90B 6.4.2.2. 83 * 84 * Note: In each current call, requested is seedLen, therefore small, 85 * no need to worry about overflow. 86 * 87 * @param digest a {@code MessageDigest} object in reset state 88 * @param outLen {@link MessageDigest#getDigestLength} of {@code digest} 89 * @param requested requested output length, in bytes 90 * @param inputs input data 91 * @return the condensed/expanded output 92 */ 93 public static byte[] hashDf(MessageDigest digest, int outLen, 94 int requested, List<byte[]> inputs) { 95 // 1. temp = the Null string. 96 // 2. len = upper_int(no_of_bits_to_return / outLen) 97 int len = (requested + outLen - 1) / outLen; 98 byte[] temp = new byte[len * outLen]; 99 // 3. counter = 0x01 100 int counter = 1; 101 102 // 4. For i = 1 to len do 103 for (int i=0; i<len; i++) { 104 // 4.1 temp = temp 105 // || Hash (counter || no_of_bits_to_return || input_string). 106 digest.update((byte) counter); 107 digest.update((byte)(requested >> 21)); // requested*8 as int32 108 digest.update((byte)(requested >> 13)); 109 digest.update((byte)(requested >> 5)); 110 digest.update((byte)(requested << 3)); 111 for (byte[] input : inputs) { 112 digest.update(input); 113 } 114 try { 115 digest.digest(temp, i * outLen, outLen); 116 } catch (DigestException e) { 117 throw new AssertionError("will not happen", e); 118 } 119 // 4.2 counter = counter + 1 120 counter++; 121 } 122 // 5. requested_bits = leftmost (temp, no_of_bits_to_return). 123 return temp.length == requested? temp: Arrays.copyOf(temp, requested); 124 // 6. Return 125 } 126 127 // This method is used by both instantiation and reseeding. 128 @Override 129 protected final synchronized void hashReseedInternal(List<byte[]> inputs) { 130 131 // 800-90Ar1 10.1.1.2: Instantiate Process. 132 // 800-90Ar1 10.1.1.3: Reseed Process. 133 byte[] seed; 134 135 // Step 2: seed = Hash_df (seed_material, seedlen). 136 if (v != null) { 137 // Step 1 of 10.1.1.3: Prepend 0x01 || V 138 inputs.add(0, ONE); 139 inputs.add(1, v); 140 seed = hashDf(seedLen, inputs); 141 } else { 142 seed = hashDf(seedLen, inputs); 143 } 144 145 // Step 3. V = seed. 146 v = seed; 147 148 // Step 4. C = Hash_df ((0x00 || V), seedlen). 149 inputs = new ArrayList<>(2); 150 inputs.add(ZERO); 151 inputs.add(v); 152 c = hashDf(seedLen, inputs); 153 154 // Step 5. reseed_counter = 1. 155 reseedCounter = 1; 156 157 //status(); 158 159 // Step 6: Return 160 } 161 162 private void status() { 163 if (debug != null) { 164 debug.println(this, "V = " + hex(v)); 165 debug.println(this, "C = " + hex(c)); 166 debug.println(this, "reseed counter = " + reseedCounter); 167 } 168 } 169 170 /** 171 * Adds byte arrays into an existing one. 172 * 173 * @param out existing array 174 * @param data more arrays, can be of different length 175 */ 176 private static void addBytes(byte[] out, int len, byte[]... data) { 177 for (byte[] d: data) { 178 int dlen = d.length; 179 int carry = 0; 180 for (int i = 0; i < len; i++) { 181 int sum = (out[len - i - 1] & 0xff) + carry; 182 if (i < dlen) { 183 sum += (d[dlen - i - 1] & 0xff); 184 } 185 out[len - i - 1] = (byte) sum; 186 carry = sum >> 8; 187 if (i >= dlen - 1 && carry == 0) break; 188 } 189 } 190 } 191 192 /** 193 * Generates a user-specified number of random bytes. 194 * 195 * @param result the array to be filled in with random bytes. 196 */ 197 @Override 198 public final synchronized void generateAlgorithm( 199 byte[] result, byte[] additionalInput) { 200 201 if (debug != null) { 202 debug.println(this, "generateAlgorithm"); 203 } 204 205 // 800-90Ar1 10.1.1.4: Hash_DRBG_Generate Process 206 207 // Step 1: Check reseed_counter. Will not fail. Already checked in 208 // AbstractDrbg#engineNextBytes. 209 210 // Step 2: additional_input 211 if (additionalInput != null) { 212 digest.update((byte)2); 213 digest.update(v); 214 digest.update(additionalInput); 215 addBytes(v, seedLen, digest.digest()); 216 } 217 218 // Step 3. Hashgen (requested_number_of_bits, V). 219 hashGen(result, v); 220 221 // Step 4. H = Hash (0x03 || V). 222 digest.update((byte)3); 223 digest.update(v); 224 byte[] h = digest.digest(); 225 226 // Step 5. V = (V + H + C + reseed_counter) mod 2seedlen. 227 byte[] rcBytes; 228 if (reseedCounter < 256) { 229 rcBytes = new byte[]{(byte)reseedCounter}; 230 } else { 231 rcBytes = BigInteger.valueOf(reseedCounter).toByteArray(); 232 } 233 addBytes(v, seedLen, h, c, rcBytes); 234 235 // Step 6. reseed_counter = reseed_counter + 1. 236 reseedCounter++; 237 238 //status(); 239 240 // Step 7: Return. 241 } 242 243 // 800-90Ar1 10.1.1.4: Hashgen 244 private void hashGen(byte[] output, byte[] v) { 245 246 // Step 2. data = V 247 byte[] data = v; 248 249 // Step 3: W is output not filled 250 251 // Step 4: For i = 1 to m 252 int pos = 0; 253 int len = output.length; 254 255 while (len > 0) { 256 if (len < outLen) { 257 // Step 4.1 w = Hash (data). 258 // Step 4.2 W = W || w. 259 System.arraycopy(digest.digest(data), 0, output, pos, 260 len); 261 } else { 262 try { 263 // Step 4.1 w = Hash (data). 264 digest.update(data); 265 // Step 4.2 digest into right position, no need to cat 266 digest.digest(output, pos, outLen); 267 } catch (DigestException e) { 268 throw new AssertionError("will not happen", e); 269 } 270 } 271 len -= outLen; 272 if (len <= 0) { 273 // shortcut, so that data and pos needn't be updated 274 break; 275 } 276 // Step 4.3 data = (data + 1) mod 2^seedlen. 277 if (data == v) { 278 data = Arrays.copyOf(v, v.length); 279 } 280 addBytes(data, seedLen, ONE); 281 pos += outLen; 282 } 283 284 // Step 5: No need to truncate 285 // Step 6: Return 286 } 287} 288