// ======================================================================== // $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; } } }