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