001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.crypto;
028:
029: /**
030: * Implements a pseudo random number generator.
031: */
032: final class PRand extends SecureRandom {
033: /** Local handle to message digest. */
034: private static MessageDigest md = null;
035:
036: /**
037: * For an arbitrary choice of the default seed, we use bits from the
038: * binary expansion of pi.
039: * <p>
040: * This seed is just an example implementation and NOT
041: * considered for used in SECURE (unpredicable) protocols, for this class
042: * to be considered a secure source of random data the seed MUST
043: * be derived from unpredicatable data in a production
044: * device at the native level.
045: * (see IETF RFC 1750, Randomness Recommendations for Security,
046: * http://www.ietf.org/rfc/rfc1750.txt)
047: */
048: private static byte[] seed = { (byte) 0xC9, (byte) 0x0F,
049: (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68,
050: (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6,
051: (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC,
052: (byte) 0x1C, (byte) 0xD1 };
053:
054: /** buffer of random bytes */
055: private static byte[] randomBytes;
056:
057: /** number of random bytes currently available */
058: private static int bytesAvailable = 0;
059:
060: /** Constructor for random data. */
061: public PRand() {
062: if (md != null)
063: return;
064:
065: try {
066: md = MessageDigest.getInstance("MD5");
067: } catch (Exception e) {
068: throw new RuntimeException("MD5 missing");
069: }
070:
071: randomBytes = new byte[seed.length];
072: updateSeed();
073: }
074:
075: /**
076: * This does a reasonable job of producing unpredictable
077: * random data by using a one way hash as a mixing function and
078: * the current time in milliseconds as a source of entropy.
079: * @param b buffer of input data
080: * @param off offset into the provided buffer
081: * @param len length of the data to be processed
082: */
083: public void nextBytes(byte[] b, int off, int len) {
084: synchronized (md) {
085: int i = 0;
086:
087: while (true) {
088: // see if we need to buffer more random bytes
089: if (bytesAvailable == 0) {
090: md.update(seed, 0, seed.length);
091: try {
092: md.digest(randomBytes, 0, randomBytes.length);
093: } catch (DigestException de) {
094: // nothing to do
095: }
096:
097: updateSeed();
098: bytesAvailable = randomBytes.length;
099: }
100:
101: // hand out some of the random bytes from the buffer
102: while (bytesAvailable > 0) {
103: if (i == len)
104: return;
105: b[off + i] = randomBytes[--bytesAvailable];
106: i++;
107: }
108: }
109: }
110: }
111:
112: /**
113: * Set the random number seed.
114: * @param b initial data to use as the seed
115: * @param off offset into the provided buffer
116: * @param len length of the data to be used
117: */
118: public void setSeed(byte[] b, int off, int len) {
119: int j = 0;
120:
121: if ((len <= 0) || (b.length < (off + len)))
122: return;
123: for (int i = 0; i < seed.length; i++, j++) {
124: if (j == len)
125: j = 0;
126: seed[i] = b[off + j];
127: }
128: }
129:
130: /**
131: * This does a reasonable job of producing unpredictable
132: * random data by using a one way hash as a mixing function and
133: * the current time in milliseconds as a source of entropy for the seed.
134: * This method assumes the original seed data is unpredicatble.
135: */
136: private void updateSeed() {
137: long t = System.currentTimeMillis();
138: byte[] tmp = new byte[8];
139:
140: // Convert the long value into a byte array
141: for (int i = 0; i < 8; i++) {
142: tmp[i] = (byte) (t & 0xff);
143: t = (t >>> 8);
144: }
145:
146: md.update(seed, 0, seed.length);
147: md.update(tmp, 0, tmp.length);
148: try {
149: md.digest(seed, 0, seed.length);
150: } catch (DigestException de) {
151: // nothing to do
152: }
153: }
154: }
|