UUID SecureRandom

http://www.javapractices.com/topic/TopicAction.do?Id=56  



When identifiers are used solely within a database, their generation should be left to the database itself. (See Statement.getGeneratedKeys.)

Unique identifiers which are "published" in some way may need special treatment, since the identifier may need to be difficult to guess or forge. A typical example is the value of a cookie used as a session identifier – simply using a series of consecutive integers is generally unacceptable, since one user could easily impersonate another by altering the value of the cookie to some nearby integer.

Style 1 – UUID

When Java 5 is available, the UUID class provides a simple means for generating unique ids. The identifiers generated by UUID are actually universally unique identifiers.

Example

 import java.util.UUID; public class GenerateUUID {    public static final void main(String... aArgs){    //generate random UUIDs    UUID idOne = UUID.randomUUID();    UUID idTwo = UUID.randomUUID();    log("UUID One: " + idOne);    log("UUID Two: " + idTwo);  }    private static void log(Object aObject){    System.out.println( String.valueOf(aObject) );  }}


Example run :
>java -cp . GenerateUUIDUUID One: 067e6162-3b6f-4ae2-a171-2470b63dff00 UUID Two: 54947df8-0e9e-4471-a2f9-9af509fb5889

If Java 5 is not available, then there are other more laborious ways to generate unique ids (see below).

Style 2 – SecureRandom and MessageDigest

The following method uses SecureRandom and MessageDigest :

  • upon startup, initialize SecureRandom (this may be a lengthy operation)
  • when a new identifier is needed, generate a random number using SecureRandom
  • create a MessageDigest of the random number
  • encode the byte[] returned by the MessageDigest into some acceptable textual form
  • check if the result is already being used ; if it is not already taken, it is suitable as a unique identifier
The MessageDigest class is suitable for generating a "one-way hash" of arbitrary data. (Note that hash values never uniquely identify their source data, since different source data can produce the same hash value. The value of hashCode, for example, does not uniquely identify its associated object.) A MessageDigest takes any input, and produces a String which :
  • is of fixed length
  • does not allow the original input to be easily recovered (in fact, this is very hard)
  • does not uniquely identify the input ; however, similar input will produce dissimilar message digests
MessageDigest is often used as a checksum, for verifying that data has not been altered since its creation.

Example

 import java.security.SecureRandom;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException; public class GenerateId {   public static void main (String... arguments) {    try {      //Initialize SecureRandom      //This is a lengthy operation, to be done only upon      //initialization of the application      SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");       //generate a random number      String randomNum = new Integer( prng.nextInt() ).toString();       //get its digest      MessageDigest sha = MessageDigest.getInstance("SHA-1");      byte[] result =  sha.digest( randomNum.getBytes() );       System.out.println("Random number: " + randomNum);      System.out.println("Message digest: " + hexEncode(result) );    }    catch ( NoSuchAlgorithmException ex ) {      System.err.println(ex);    }  }   /**  * The byte[] returned by MessageDigest does not have a nice  * textual representation, so some form of encoding is usually performed.  *  * This implementation follows the example of David Flanagan's book  * "Java In A Nutshell", and converts a byte array into a String  * of hex characters.  *  * Another popular alternative is to use a "Base64" encoding.  */  static private String hexEncode( byte[] aInput){    StringBuilder result = new StringBuilder();    char[] digits = {'0', '1', '2', '3', '4','5','6','7','8','9','a','b','c','d','e','f'};    for ( int idx = 0; idx < aInput.length; ++idx) {      byte b = aInput[idx];      result.append( digits[ (b&0xf0) >> 4 ] );      result.append( digits[ b&0x0f] );    }    return result.toString();  }}


Example run :

>java -cp . GenerateId
Random number: -1103747470
Message digest: c8fff94ba996411079d7114e698b53bac8f7b037

Style 3 – UID

Finally, here is another method, using a java.rmi.server.UID. The Serializable identifiers generated by this class are unique on the host on which they are generated, provided that
  • the host takes more than one millisecond to reboot
  • the host's clock is never set to run backwards
In order to construct a UID that is globally unique, simply pair a UID with an InetAddress.

Example

 import java.rmi.server.UID; public class UniqueId {   /**  * Build and display some UID objects.  */  public static void main (String... arguments) {    for (int idx=0; idx<10; ++idx){      UID userId = new UID();      System.out.println("User Id: " + userId);    }  }}

Example run :

User Id: 3179c3:ec6e28a7ef:-8000
User Id: 3179c3:ec6e28a7ef:-7fff
User Id: 3179c3:ec6e28a7ef:-7ffe
User Id: 3179c3:ec6e28a7ef:-7ffd
User Id: 3179c3:ec6e28a7ef:-7ffc
User Id: 3179c3:ec6e28a7ef:-7ffb
User Id: 3179c3:ec6e28a7ef:-7ffa
User Id: 3179c3:ec6e28a7ef:-7ff9
User Id: 3179c3:ec6e28a7ef:-7ff8
User Id: 3179c3:ec6e28a7ef:-7ff7

Clearly, these are not secure identifiers – knowing one, it is easy to guess another.