001: /*
002: * @(#)PRand.java 1.9 02/07/24 @(#)
003: *
004: * Copyright (c) 2000-2001 Sun Microsystems, Inc. All rights reserved.
005: * PROPRIETARY/CONFIDENTIAL
006: * Use is subject to license terms.
007: */
008:
009: package com.sun.portal.ksecurity;
010:
011: /**
012: * Implements a pseudo random number generator.
013: */
014: final class PRand extends RandomData {
015: /** Local handle to message digest. */
016: private static MessageDigest md = null;
017:
018: /**
019: * For an arbitrary choice of the default seed, we use bits from the
020: * binary expansion of pi (see IETF RFC 2412,
021: * http://www.ietf.org/rfc/rfc2412.txt)
022: */
023: private static byte[] seed = { (byte) 0xC9, (byte) 0x0F,
024: (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68,
025: (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6,
026: (byte) 0x62, (byte) 0x8B, (byte) 0x80, (byte) 0xDC,
027: (byte) 0x1C, (byte) 0xD1 };
028:
029: /** buffer of random bytes */
030: private static byte[] randomBytes;
031:
032: /** number of random bytes currently available */
033: private static int bytesAvailable = 0;
034:
035: /** Constructor for random data. */
036: public PRand() throws CryptoException {
037: if (md != null)
038: return;
039:
040: try {
041: md = MessageDigest
042: .getInstance(MessageDigest.ALG_MD5, false);
043: } catch (Exception e) {
044: throw new CryptoException(CryptoException.NO_SUCH_ALGORITHM);
045: }
046: randomBytes = new byte[seed.length];
047: updateSeed();
048: }
049:
050: /**
051: * This does a reasonable job of producing unpredictable
052: * random data by using a one way hash as a mixing function and
053: * the current time in milliseconds as a source of entropy.
054: * @param b buffer of input data
055: * @param off offset into the provided buffer
056: * @param len length of the data to be processed
057: */
058: public void generateData(byte[] b, short off, short len) {
059: synchronized (md) {
060: int i = 0;
061:
062: while (true) {
063: // see if we need to buffer more random bytes
064: if (bytesAvailable == 0) {
065: md.doFinal(seed, 0, seed.length, randomBytes, 0);
066: updateSeed();
067: bytesAvailable = randomBytes.length;
068: }
069:
070: // hand out some of the random bytes from the buffer
071: while (bytesAvailable > 0) {
072: if (i == len)
073: return;
074: b[off + i] = randomBytes[--bytesAvailable];
075: i++;
076: }
077: }
078: }
079: }
080:
081: /**
082: * Set the random number seed.
083: * @param b initial data to use as the seed
084: * @param off offset into the provided buffer
085: * @param len length of the data to be used
086: */
087: public void setSeed(byte[] b, short off, short len) {
088: int j = 0;
089:
090: if ((len <= 0) || (b.length < (off + len)))
091: return;
092: for (int i = 0; i < seed.length; i++, j++) {
093: if (j == len)
094: j = 0;
095: seed[i] = b[off + j];
096: }
097: }
098:
099: /**
100: * This does a reasonable job of producing unpredictable
101: * random data by using a one way hash as a mixing function and
102: * the current time in milliseconds as a source of entropy.
103: */
104: public void updateSeed() {
105: long t = System.currentTimeMillis();
106: byte[] tmp = new byte[8];
107:
108: // Convert the long value into a byte array
109: for (int i = 0; i < 8; i++) {
110: tmp[i] = (byte) (t & 0xff);
111: t = (t >>> 8);
112: }
113:
114: md.update(seed, 0, seed.length);
115: md.doFinal(tmp, 0, tmp.length, seed, 0);
116: }
117: }
|