001: package org.gomba.utils.token;
002:
003: import java.security.MessageDigest;
004: import java.security.NoSuchAlgorithmException;
005: import java.util.Random;
006:
007: /**
008: * Random id generator. This code has been *stolen* and adapted from Tomcat 5
009: * <code>org.apache.catalina.session.ManagerBase</code>. Thank you guys! :)
010: *
011: * @author Craig R. McClanahan
012: * @author Flavio Tordini
013: * @version $Id: IdGenerator.java,v 1.1 2004/11/26 17:52:58 flaviotordini Exp $
014: */
015: public class IdGenerator {
016:
017: /**
018: * The session id length created by this class.
019: */
020: protected int idLength = 16;
021:
022: /**
023: * A random number generator to use when generating session identifiers.
024: */
025: protected Random random = null;
026:
027: /**
028: * A String initialization parameter used to increase the entropy of the
029: * initialization of our random number generator.
030: */
031: protected String entropy = null;
032:
033: /**
034: * The Java class name of the random number generator class to be used when
035: * generating session identifiers.
036: */
037: protected String randomClass = "java.security.SecureRandom";
038:
039: /**
040: * The default message digest algorithm to use if we cannot use the
041: * requested one.
042: */
043: protected static final String DEFAULT_ALGORITHM = "MD5";
044:
045: /**
046: * The message digest algorithm to be used when generating session
047: * identifiers. This must be an algorithm supported by the
048: * <code>java.security.MessageDigest</code> class on your platform.
049: */
050: protected String algorithm = DEFAULT_ALGORITHM;
051:
052: /**
053: * Return the MessageDigest implementation to be used when creating session
054: * identifiers.
055: */
056: protected MessageDigest digest = null;
057:
058: /**
059: * Return the MessageDigest object to be used for calculating session
060: * identifiers. If none has been created yet, initialize one the first time
061: * this method is called.
062: */
063: public MessageDigest getDigest() {
064:
065: if (this .digest == null) {
066: synchronized (this ) {
067: if (this .digest == null) {
068: try {
069: this .digest = MessageDigest
070: .getInstance(this .algorithm);
071: } catch (NoSuchAlgorithmException e) {
072: try {
073: this .digest = MessageDigest
074: .getInstance(DEFAULT_ALGORITHM);
075: } catch (NoSuchAlgorithmException f) {
076: this .digest = null;
077: }
078: }
079: }
080: }
081: }
082:
083: return (this .digest);
084:
085: }
086:
087: /**
088: * Return the entropy increaser value, or compute a semi-useful value if
089: * this String has not yet been set.
090: */
091: public String getEntropy() {
092:
093: // Calculate a semi-useful value if this has not been set
094: if (this .entropy == null)
095: setEntropy(this .toString());
096:
097: return (this .entropy);
098:
099: }
100:
101: /**
102: * Set the entropy increaser value.
103: *
104: * @param entropy
105: * The new entropy increaser value
106: */
107: public void setEntropy(String entropy) {
108:
109: this .entropy = entropy;
110:
111: }
112:
113: /**
114: * Return the random number generator instance we should use for generating
115: * session identifiers. If there is no such generator currently defined,
116: * construct and seed a new one.
117: */
118: public Random getRandom() {
119: if (this .random == null) {
120: synchronized (this ) {
121: if (this .random == null) {
122: // Calculate the new random number generator seed
123: long seed = System.currentTimeMillis();
124: char entropy[] = getEntropy().toCharArray();
125: for (int i = 0; i < entropy.length; i++) {
126: long update = ((byte) entropy[i]) << ((i % 8) * 8);
127: seed ^= update;
128: }
129: try {
130: // Construct and seed a new random number generator
131: Class clazz = Class.forName(this .randomClass);
132: this .random = (Random) clazz.newInstance();
133: this .random.setSeed(seed);
134: } catch (Exception e) {
135: // Fall back to the simple case
136: this .random = new java.util.Random();
137: this .random.setSeed(seed);
138: }
139: }
140: }
141: }
142:
143: return (this .random);
144:
145: }
146:
147: protected void getRandomBytes(byte bytes[]) {
148: // Generate a byte array containing an identifier
149: getRandom().nextBytes(bytes);
150: }
151:
152: /**
153: * Generate and return a new identifier.
154: */
155: public String generateId() {
156:
157: byte randomBytes[] = new byte[16];
158:
159: // Render the result as a String of hexadecimal digits
160: StringBuffer buffer = new StringBuffer();
161:
162: int resultLenBytes = 0;
163:
164: while (resultLenBytes < this .idLength) {
165:
166: getRandomBytes(randomBytes);
167: randomBytes = getDigest().digest(randomBytes);
168:
169: for (int j = 0; j < randomBytes.length
170: && resultLenBytes < this .idLength; j++) {
171: byte b1 = (byte) ((randomBytes[j] & 0xf0) >> 4);
172: byte b2 = (byte) (randomBytes[j] & 0x0f);
173: if (b1 < 10)
174: buffer.append((char) ('0' + b1));
175: else
176: buffer.append((char) ('A' + (b1 - 10)));
177: if (b2 < 10)
178: buffer.append((char) ('0' + b2));
179: else
180: buffer.append((char) ('A' + (b2 - 10)));
181: resultLenBytes++;
182: }
183:
184: }
185:
186: return buffer.toString();
187:
188: }
189:
190: }
|