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