KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > crypto > generators > DigestRandom


1 /*
2  * DigestRandom.java
3  *
4  * Created on 12. Oktober 2005, 08:51
5  */

6 /*
7  * Copyright 2005 Schlichtherle IT Services
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package de.schlichtherle.crypto.generators;
23
24 import java.security.SecureRandom JavaDoc;
25 import java.util.Random JavaDoc;
26
27 import org.bouncycastle.crypto.Digest;
28 import org.bouncycastle.crypto.digests.SHA256Digest;
29
30 /**
31  * A Pseudo Random Number Generator (PRNG) using an arbitrary digest function.
32  * Similar to {@link SecureRandom}, this class is self-seeding.
33  * However, unlike <code>SecureRandom</code>, it's not seedable:
34  * Calling one of the {@link Random#setSeed} methods does not have any effect!
35  *
36  * @author Christian Schlichtherle
37  */

38 public class DigestRandom extends Random JavaDoc {
39
40     private static final SecureRandom JavaDoc seeder = new SecureRandom JavaDoc();
41
42     private final byte[] in;
43     private long counter;
44
45     private final Digest digest;
46
47     private final byte[] out;
48     private int outOff;
49
50     public DigestRandom(Digest digest) {
51         this.digest = digest;
52         final int size = digest.getDigestSize();
53         in = new byte[size];
54         out = new byte[size];
55         outOff = size;
56
57         // Seed the PRNG from the seeder PRNG and the current time.
58
// Note: DON'T use seeder.generateSeed(size)! While this makes a very
59
// good seed indeed (on Linux), it seriously KILLS PERFORMANCE!
60
// The resulting performance is so bad that the unit test in
61
// de.schlichtherle.io.RandomDataZip32RaesTest computes for hours
62
// instead of two or three minutes (on my computer).
63
// Note that the seeder is self-seeded whith a true random number on
64
// the first call anyway, so calling generateSeed() is not required.
65
seeder.nextBytes(in);
66
67         // This is probably a bit paranoid...
68
long time = System.currentTimeMillis();
69         for (int i = Math.min(size, 8); --i >= 0; ) {
70             in[i] ^= time; // XOR with PRNG
71
time >>= 8;
72         }
73     }
74
75     /**
76      * Generates a user-specified number of pseudo random bytes.
77      * This method is used as the basis of all random entities returned by
78      * this class (except seed bytes).
79      *
80      * @param bytes The array to be filled in with random bytes.
81      */

82     synchronized public void nextBytes(byte[] bytes) {
83         for (int i = bytes.length; --i >= 0; ) {
84             update();
85             bytes[i] = out[outOff++];
86         }
87     }
88
89     /**
90      * Generates an integer containing the user-specified number of
91      * pseudo-random bits (right justified, with leading zeros).
92      * This method overrides a <tt>java.util.Random</tt> method, and serves
93      * to provide a source of random bits to all of the methods inherited
94      * from that class (for example, <tt>nextInt</tt>, <tt>nextLong</tt>,
95      * and <tt>nextFloat</tt>).
96      *
97      * @param numBits Number of pseudo-random bits to be generated, where
98      * 0 <= <tt>numBits</tt> <= 32.
99      *
100      * @return An <tt>int</tt> containing the user-specified number
101      * of pseudo-random bits (right justified, with leading zeros).
102      */

103     final protected int next(final int numBits) {
104     final int numBytes = (numBits + 7) >>> 3; // round up
105

106         int next = 0;
107     for (int i = numBytes; --i >= 0; ) {
108             update();
109         next = (next << 8) | (out[outOff++] & 0xFF);
110         }
111  
112     return next >>> ((numBytes << 3) - numBits); // shift away rounded bits
113
}
114
115     private void update() {
116         if (outOff >= out.length) {
117             long counter = ++this.counter;
118             for (int i = in.length; --i >= 0; ) {
119                 counter += in[i] & 0xff;
120                 in[i] = (byte) counter;
121                 counter >>>= 8;
122             }
123             digest.update(in, 0, in.length);
124             digest.doFinal(out, 0);
125             outOff = 0;
126         }
127     }
128 }
129
Popular Tags