|
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 javax.crypto.Mac; |
|
29 import javax.crypto.spec.SecretKeySpec; |
|
30 import java.io.IOException; |
|
31 import java.security.InvalidKeyException; |
|
32 import java.security.NoSuchAlgorithmException; |
|
33 import java.security.NoSuchProviderException; |
|
34 import java.security.SecureRandomParameters; |
|
35 import java.util.Arrays; |
|
36 |
|
37 public class HmacDrbg extends AbstractHashDrbg { |
|
38 |
|
39 private static final long serialVersionUID = 9L; |
|
40 |
|
41 private transient Mac mac; |
|
42 |
|
43 private String macAlg; |
|
44 |
|
45 private transient byte[] v; |
|
46 private transient byte[] k; |
|
47 |
|
48 public HmacDrbg(SecureRandomParameters params) { |
|
49 mechName = "HMAC_DRBG"; |
|
50 configure(params); |
|
51 } |
|
52 |
|
53 private void status() { |
|
54 if (debug != null) { |
|
55 debug.println(this, "V = " + hex(v)); |
|
56 debug.println(this, "Key = " + hex(k)); |
|
57 debug.println(this, "reseed counter = " + reseedCounter); |
|
58 } |
|
59 } |
|
60 |
|
61 // 800-90Ar1 10.1.2.2: HMAC_DRBG Update Process |
|
62 private void update(byte[]... inputs) { |
|
63 try { |
|
64 // Step 1. K = HMAC (K, V || 0x00 || provided_data). |
|
65 mac.init(new SecretKeySpec(k, macAlg)); |
|
66 mac.update(v); |
|
67 mac.update((byte) 0); |
|
68 for (byte[] input: inputs) { |
|
69 mac.update(input); |
|
70 } |
|
71 k = mac.doFinal(); |
|
72 |
|
73 // Step 2. V = HMAC (K, V). |
|
74 mac.init(new SecretKeySpec(k, macAlg)); |
|
75 v = mac.doFinal(v); |
|
76 |
|
77 if (inputs.length != 0) { |
|
78 // Step 4. K = HMAC (K, V || 0x01 || provided_data). |
|
79 mac.update(v); |
|
80 mac.update((byte) 1); |
|
81 for (byte[] input: inputs) { |
|
82 mac.update(input); |
|
83 } |
|
84 k = mac.doFinal(); |
|
85 |
|
86 // Step 5. V=HMAC(K,V). |
|
87 mac.init(new SecretKeySpec(k, macAlg)); |
|
88 v = mac.doFinal(v); |
|
89 } // else Step 3 |
|
90 |
|
91 // Step 6. Return |
|
92 } catch (InvalidKeyException e) { |
|
93 throw new InternalError(e); |
|
94 } |
|
95 } |
|
96 |
|
97 /** |
|
98 * This call, used by the constructors, instantiates the digest. |
|
99 */ |
|
100 @Override |
|
101 protected void initEngine() { |
|
102 macAlg = "HmacSHA" + algorithm.substring(4); |
|
103 try { |
|
104 mac = Mac.getInstance(macAlg, "SunJCE"); |
|
105 } catch (NoSuchProviderException | NoSuchAlgorithmException e) { |
|
106 // Fallback to any available. |
|
107 try { |
|
108 mac = Mac.getInstance(macAlg); |
|
109 } catch (NoSuchAlgorithmException exc) { |
|
110 throw new InternalError( |
|
111 "internal error: " + macAlg + " not available.", exc); |
|
112 } |
|
113 } |
|
114 } |
|
115 |
|
116 // This method is used by both instantiation and reseeding. |
|
117 @Override |
|
118 protected final void hashReseedInternal(byte[] input) { |
|
119 |
|
120 // 800-90Ar1 10.1.2.3: Instantiate Process. |
|
121 // 800-90Ar1 10.1.2.4: Reseed Process. |
|
122 if (v == null) { |
|
123 k = new byte[outLen]; |
|
124 v = new byte[outLen]; |
|
125 Arrays.fill(v, (byte) 1); |
|
126 } |
|
127 |
|
128 // Step 2: HMAC_DRBG_Update |
|
129 update(input); |
|
130 |
|
131 // Step 3: reseed_counter = 1. |
|
132 reseedCounter = 1; |
|
133 //status(); |
|
134 |
|
135 // Step 4: Return |
|
136 } |
|
137 |
|
138 /** |
|
139 * Generates a user-specified number of random bytes. |
|
140 * |
|
141 * @param result the array to be filled in with random bytes. |
|
142 */ |
|
143 @Override |
|
144 public synchronized void generateAlgorithm( |
|
145 byte[] result, byte[] additionalInput) { |
|
146 |
|
147 if (debug != null) { |
|
148 debug.println(this, "generateAlgorithm"); |
|
149 } |
|
150 |
|
151 // 800-90Ar1 10.1.2.5: HMAC_DRBG_Generate Process |
|
152 |
|
153 // Step 1: Check reseed_counter. Will not fail. Already checked in |
|
154 // AbstractDrbg#engineNextBytes. |
|
155 |
|
156 // Step 2. HMAC_DRBG_Update |
|
157 if (additionalInput != null) { |
|
158 update(additionalInput); |
|
159 } |
|
160 |
|
161 // Step 3. temp = Null. |
|
162 int pos = 0; |
|
163 |
|
164 // Step 4. Loop |
|
165 while (pos < result.length) { |
|
166 int tailLen = result.length - pos; |
|
167 |
|
168 // Step 4.1 V = HMAC (Key, V). |
|
169 try { |
|
170 mac.init(new SecretKeySpec(k, macAlg)); |
|
171 } catch (InvalidKeyException e) { |
|
172 throw new InternalError(e); |
|
173 } |
|
174 v = mac.doFinal(v); |
|
175 // Step 4.2 temp = temp || V. |
|
176 System.arraycopy(v, 0, result, pos, |
|
177 tailLen > outLen ? outLen : tailLen); |
|
178 pos += outLen; |
|
179 } |
|
180 |
|
181 // Step 5: No need to truncate |
|
182 |
|
183 // Step 6. HMAC_DRBG_Update (additional_input, Key, V). |
|
184 if (additionalInput != null) { |
|
185 update(additionalInput); |
|
186 } else { |
|
187 update(); |
|
188 } |
|
189 |
|
190 // Step 7. reseed_counter = reseed_counter + 1. |
|
191 reseedCounter++; |
|
192 |
|
193 //status(); |
|
194 |
|
195 // Step 8. Return |
|
196 } |
|
197 |
|
198 private void readObject(java.io.ObjectInputStream s) |
|
199 throws IOException, ClassNotFoundException { |
|
200 s.defaultReadObject (); |
|
201 initEngine(); |
|
202 } |
|
203 } |