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