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/SecureRandom.java
41159 views
1
/*
2
* Copyright (c) 1998, 2020, 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.io.IOException;
29
import java.security.MessageDigest;
30
import java.security.SecureRandomSpi;
31
import java.security.NoSuchAlgorithmException;
32
import java.security.NoSuchProviderException;
33
34
/**
35
* <p>This class provides a crytpographically strong pseudo-random number
36
* generator based on the SHA-1 hash algorithm.
37
*
38
* <p>Note that if a seed is not provided, we attempt to provide sufficient
39
* seed bytes to completely randomize the internal state of the generator
40
* (20 bytes). However, our seed generation algorithm has not been thoroughly
41
* studied or widely deployed.
42
*
43
* <p>Also note that when a random object is deserialized,
44
* <a href="#engineNextBytes(byte[])">engineNextBytes</a> invoked on the
45
* restored random object will yield the exact same (random) bytes as the
46
* original object. If this behaviour is not desired, the restored random
47
* object should be seeded, using
48
* <a href="#engineSetSeed(byte[])">engineSetSeed</a>.
49
*
50
* @author Benjamin Renaud
51
* @author Josh Bloch
52
* @author Gadi Guy
53
*/
54
55
public final class SecureRandom extends SecureRandomSpi
56
implements java.io.Serializable {
57
58
@java.io.Serial
59
private static final long serialVersionUID = 3581829991155417889L;
60
61
private static final int DIGEST_SIZE = 20;
62
private transient MessageDigest digest;
63
private byte[] state;
64
private byte[] remainder;
65
private int remCount;
66
67
/**
68
* An empty constructor that creates an unseeded SecureRandom object.
69
* <p>
70
* Unless the user calls setSeed(), the first call to engineGetBytes()
71
* will have the SeedGenerator provide sufficient seed bytes to
72
* completely randomize the internal state of the generator (20 bytes).
73
* Note that the old threaded seed generation algorithm is provided
74
* only as a fallback, and has not been thoroughly studied or widely
75
* deployed.
76
* <p>
77
* The SeedGenerator relies on a VM-wide entropy pool to generate
78
* seed bytes for these objects. The first time the SeedGenerator is
79
* called, it may take several seconds of CPU time to initialize,
80
* depending on the underlying hardware. Successive calls run
81
* quickly because they rely on the same (internal) pseudo-random
82
* number generator for their seed bits.
83
*/
84
public SecureRandom() {
85
init(null);
86
}
87
88
/**
89
* This constructor is used to instantiate the private seeder object
90
* with a given seed from the SeedGenerator.
91
*
92
* @param seed the seed.
93
*/
94
private SecureRandom(byte[] seed) {
95
init(seed);
96
}
97
98
/**
99
* This call, used by the constructors, instantiates the SHA digest
100
* and sets the seed, if given.
101
*/
102
private void init(byte[] seed) {
103
try {
104
/*
105
* Use the local SUN implementation to avoid native
106
* performance overhead.
107
*/
108
digest = MessageDigest.getInstance("SHA", "SUN");
109
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
110
// Fallback to any available.
111
try {
112
digest = MessageDigest.getInstance("SHA");
113
} catch (NoSuchAlgorithmException exc) {
114
throw new InternalError(
115
"internal error: SHA-1 not available.", exc);
116
}
117
}
118
119
if (seed != null) {
120
engineSetSeed(seed);
121
}
122
}
123
124
/**
125
* Returns the given number of seed bytes, computed using the seed
126
* generation algorithm that this class uses to seed itself. This
127
* call may be used to seed other random number generators. While
128
* we attempt to return a "truly random" sequence of bytes, we do not
129
* know exactly how random the bytes returned by this call are. (See
130
* the empty constructor <a href = "#SecureRandom">SecureRandom</a>
131
* for a brief description of the underlying algorithm.)
132
* The prudent user will err on the side of caution and get extra
133
* seed bytes, although it should be noted that seed generation is
134
* somewhat costly.
135
*
136
* @param numBytes the number of seed bytes to generate.
137
*
138
* @return the seed bytes.
139
*/
140
@Override
141
public byte[] engineGenerateSeed(int numBytes) {
142
// Neither of the SeedGenerator implementations require
143
// locking, so no sync needed here.
144
byte[] b = new byte[numBytes];
145
SeedGenerator.generateSeed(b);
146
return b;
147
}
148
149
/**
150
* Reseeds this random object. The given seed supplements, rather than
151
* replaces, the existing seed. Thus, repeated calls are guaranteed
152
* never to reduce randomness.
153
*
154
* @param seed the seed.
155
*/
156
@Override
157
public synchronized void engineSetSeed(byte[] seed) {
158
if (state != null) {
159
digest.update(state);
160
for (int i = 0; i < state.length; i++) {
161
state[i] = 0;
162
}
163
}
164
state = digest.digest(seed);
165
remCount = 0;
166
}
167
168
private static void updateState(byte[] state, byte[] output) {
169
int last = 1;
170
int v;
171
byte t;
172
boolean zf = false;
173
174
// state(n + 1) = (state(n) + output(n) + 1) % 2^160;
175
for (int i = 0; i < state.length; i++) {
176
// Add two bytes
177
v = (int)state[i] + (int)output[i] + last;
178
// Result is lower 8 bits
179
t = (byte)v;
180
// Store result. Check for state collision.
181
zf = zf | (state[i] != t);
182
state[i] = t;
183
// High 8 bits are carry. Store for next iteration.
184
last = v >> 8;
185
}
186
187
// Make sure at least one bit changes!
188
if (!zf) {
189
state[0]++;
190
}
191
}
192
193
/**
194
* This static object will be seeded by SeedGenerator, and used
195
* to seed future instances of SHA1PRNG SecureRandoms.
196
*
197
* Bloch, Effective Java Second Edition: Item 71
198
*/
199
private static class SeederHolder {
200
201
private static final SecureRandom seeder;
202
203
static {
204
/*
205
* Call to SeedGenerator.generateSeed() to add additional
206
* seed material (likely from the Native implementation).
207
*/
208
seeder = new SecureRandom(SeedGenerator.getSystemEntropy());
209
byte [] b = new byte[DIGEST_SIZE];
210
SeedGenerator.generateSeed(b);
211
seeder.engineSetSeed(b);
212
}
213
}
214
215
/**
216
* Generates a user-specified number of random bytes.
217
*
218
* @param result the array to be filled in with random bytes.
219
*/
220
@Override
221
public synchronized void engineNextBytes(byte[] result) {
222
int index = 0;
223
int todo;
224
byte[] output = remainder;
225
226
if (state == null) {
227
byte[] seed = new byte[DIGEST_SIZE];
228
SeederHolder.seeder.engineNextBytes(seed);
229
state = digest.digest(seed);
230
}
231
232
// Use remainder from last time
233
int r = remCount;
234
if (r > 0) {
235
// How many bytes?
236
todo = (result.length - index) < (DIGEST_SIZE - r) ?
237
(result.length - index) : (DIGEST_SIZE - r);
238
// Copy the bytes, zero the buffer
239
for (int i = 0; i < todo; i++) {
240
result[i] = output[r];
241
output[r++] = 0;
242
}
243
remCount += todo;
244
index += todo;
245
}
246
247
// If we need more bytes, make them.
248
while (index < result.length) {
249
// Step the state
250
digest.update(state);
251
output = digest.digest();
252
updateState(state, output);
253
254
// How many bytes?
255
todo = (result.length - index) > DIGEST_SIZE ?
256
DIGEST_SIZE : result.length - index;
257
// Copy the bytes, zero the buffer
258
for (int i = 0; i < todo; i++) {
259
result[index++] = output[i];
260
output[i] = 0;
261
}
262
remCount += todo;
263
}
264
265
// Store remainder for next time
266
remainder = output;
267
remCount %= DIGEST_SIZE;
268
}
269
270
/*
271
* readObject is called to restore the state of the random object from
272
* a stream. We have to create a new instance of MessageDigest, because
273
* it is not included in the stream (it is marked "transient").
274
*
275
* Note that the engineNextBytes() method invoked on the restored random
276
* object will yield the exact same (random) bytes as the original.
277
* If you do not want this behaviour, you should re-seed the restored
278
* random object, using engineSetSeed().
279
*/
280
@java.io.Serial
281
private void readObject(java.io.ObjectInputStream s)
282
throws IOException, ClassNotFoundException {
283
284
s.defaultReadObject ();
285
286
try {
287
/*
288
* Use the local SUN implementation to avoid native
289
* performance overhead.
290
*/
291
digest = MessageDigest.getInstance("SHA", "SUN");
292
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
293
// Fallback to any available.
294
try {
295
digest = MessageDigest.getInstance("SHA");
296
} catch (NoSuchAlgorithmException exc) {
297
throw new InternalError(
298
"internal error: SHA-1 not available.", exc);
299
}
300
}
301
}
302
}
303
304