History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/provider/SecureRandom.java (1 of 18352 files). Show all

Unified · Split

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