// ========================================================================
// $Id: GUIDGenerator.java,v 1.4 2004/05/09 20:30:47 gregwilkins Exp $
// Copyright 2002-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.mortbay.j2ee.session;
// shamelessly distilled from
// org.jboss.ha.httpsession.server.ClusteredHTTPSessionService
// written by : sacha.labourey@cogito-info.ch
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import javax.servlet.http.HttpServletRequest;
import org.jboss.logging.Logger;
public class GUIDGenerator implements IdGenerator
{
protected static final Logger _log = Logger.getLogger(GUIDGenerator.class);
protected final static int SESSION_ID_BYTES = 16; // We want 16 Bytes for
// the session-id
protected final static String SESSION_ID_HASH_ALGORITHM = "MD5";
protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
protected MessageDigest _digest = null;
protected Random _random = null;
/**
* Generate a session-id that is not guessable
*
* @return generated session-id
*/
public synchronized String nextId(HttpServletRequest request)
{
if (_digest == null)
{
_digest = getDigest();
}
if (_random == null)
{
_random = getRandom();
}
byte[] bytes = new byte[SESSION_ID_BYTES];
// get random bytes
_random.nextBytes(bytes);
// Hash the random bytes
bytes = _digest.digest(bytes);
// Render the result as a String of hexadecimal digits
return encode(bytes);
}
/**
* Encode the bytes into a String with a slightly modified Base64-algorithm
* This code was written by Kevin Kelley <kelley@ruralnet.net> and adapted
* by Thomas Peuss <jboss@peuss.de>
*
* @param data The bytes you want to encode
* @return the encoded String
*/
protected String encode(byte[] data)
{
char[] out = new char[((data.length + 2) / 3) * 4];
char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*"
.toCharArray();
//
// 3 bytes encode to 4 chars. Output is always an even
// multiple of 4 characters.
//
for (int i = 0, index = 0; i < data.length; i += 3, index += 4)
{
boolean quad = false;
boolean trip = false;
int val = (0xFF & (int) data[i]);
val <<= 8;
if ((i + 1) < data.length)
{
val |= (0xFF & (int) data[i + 1]);
trip = true;
}
val <<= 8;
if ((i + 2) < data.length)
{
val |= (0xFF & (int) data[i + 2]);
quad = true;
}
out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
val >>= 6;
out[index + 1] = alphabet[val & 0x3F];
val >>= 6;
out[index + 0] = alphabet[val & 0x3F];
}
return new String(out);
}
/**
* get a random-number generator
*
* @return a random-number generator
*/
protected synchronized Random getRandom()
{
long seed;
Random random = null;
// Mix up the seed a bit
seed = System.currentTimeMillis();
seed ^= Runtime.getRuntime().freeMemory();
try
{
random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
}
catch (NoSuchAlgorithmException e)
{
try
{
random = SecureRandom
.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
}
catch (NoSuchAlgorithmException e_alt)
{
_log
.error(
"Could not generate SecureRandom for session-id randomness",
e);
_log
.error(
"Could not generate SecureRandom for session-id randomness",
e_alt);
return null;
}
}
// set the generated seed for this PRNG
random.setSeed(seed);
return random;
}
/**
get a MessageDigest hash-generator
@return a hash generator
*/
protected synchronized MessageDigest getDigest()
{
MessageDigest digest = null;
try
{
digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM);
}
catch (NoSuchAlgorithmException e)
{
_log.error(
"Could not generate MessageDigest for session-id hashing",
e);
return null;
}
return digest;
}
public synchronized Object clone()
{
try
{
return super.clone();
}
catch (CloneNotSupportedException e)
{
_log.warn("could not clone IdGenerator", e);
return null;
}
}
}