1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.id.uuid; 18 19 import org.apache.commons.id.IdentifierGenerator; 20 21 import java.security.NoSuchAlgorithmException; 22 import java.security.NoSuchProviderException; 23 import java.security.SecureRandom; 24 import java.util.Random; 25 26 /** 27 * <p>Class is responsible for generating version 4 UUID's per RFC 4122. 28 * This class attempts to use a java.security.SecureRandom with 29 * the following instantiation 30 * <code>SecureRandom.getInstance("SHA1PRNG", "SUN")</code>. If neither secure 31 * random implementation is avialable or an Exception is raised a java.util.Random 32 * is used.</p> 33 * <p>Note: Instantiation of SecureRandom is an expensive operation. The 34 * constructor therefore creates a static member to hold the SecureRandom. 35 * The first call to getInstance may take time; subsequent calls should return 36 * quickly.</p> 37 * 38 * @author Commons-Id team 39 * @version $Revision: 480488 $ $Date: 2006-11-29 08:57:26 +0000 (Wed, 29 Nov 2006) $ 40 * 41 */ 42 public final class VersionFourGenerator implements IdentifierGenerator, Constants { 43 44 /** Random used to generate UUID's */ 45 private static final Random regularRandom = new Random(); 46 47 /** SecureRandom used to generate UUID's */ 48 private static Random secureRandom; 49 50 /** The pseudo-random number generator to use */ 51 private static String usePRNG = "SHA1PRNG"; 52 53 /** The pseudo-random number generator package name to use */ 54 private static String usePRNGPackage = "SUN"; 55 56 private static VersionFourGenerator generator; 57 58 /** 59 * <p>Constructs a new VersionFourGenerator.</p> 60 */ 61 public VersionFourGenerator() { 62 super(); 63 } 64 65 /** 66 * <p>Returns a singleton instance of the version four UUID generator.</p> 67 * 68 * @return the singleton instance of the version four UUID generator. 69 */ 70 public static VersionFourGenerator getInstance() { 71 if (generator == null) { 72 generator = new VersionFourGenerator(); 73 } 74 return generator; 75 } 76 77 /** 78 * <p>Returns a new version four UUID.</p> 79 * 80 * @return Object a new version 4 UUID. 81 */ 82 public Object nextIdentifier() { 83 return nextUUID(false); 84 } 85 86 /** 87 * <p>Returns a new version four UUID.</p> 88 * <p>This overloaded method may produce both UUID's using a <code>SecureRandom</code> as well as using normal 89 * <code>Random</code> 90 * </p> 91 * 92 * @param secure indicates whether or not to use <code>SecureRandom</code> in generating the random bits. 93 * @return a new version four UUID that was generated by either a <code>Random</code> or <code>SecureRandom</code>. 94 */ 95 public Object nextIdentifier(boolean secure) { 96 return nextUUID(secure); 97 } 98 99 /** 100 * <p>Returns a new version four UUID.</p> 101 * 102 * @return Object a new version 4 UUID. 103 */ 104 public UUID nextUUID() { 105 //Call nextUUID with secure = false 106 return nextUUID(false); 107 } 108 109 /** 110 * <p>Returns a new version four UUID using either <code>SecureRandom</code> or <code>Random</code>.</p> 111 * 112 * @param secure boolean flag indicating whether to use <code>SecureRandom</code> or <code>Random</code>. 113 * @return a new version four UUID using either <code>SecureRandom</code> or <code>Random</code>. 114 */ 115 private UUID nextUUID(boolean secure) { 116 byte[] raw = new byte[UUID_BYTE_LENGTH]; 117 if (secure) { 118 //Initialize the secure random if null. 119 if (secureRandom == null) { 120 try { 121 if (usePRNGPackage != null) { 122 secureRandom = SecureRandom.getInstance(usePRNG, usePRNGPackage); 123 } else { 124 secureRandom = SecureRandom.getInstance(usePRNG); 125 } 126 } catch (NoSuchAlgorithmException nsae) { 127 secure = false; //Fail back to default PRNG/Random 128 } catch (NoSuchProviderException nspe) { 129 secure = false; //Fail back to default PRNG/Random 130 } 131 } 132 if (secureRandom != null) { 133 secureRandom.nextBytes(raw); 134 } 135 } else { 136 regularRandom.nextBytes(raw); 137 } 138 139 raw[TIME_HI_AND_VERSION_BYTE_6] &= 0x0F; 140 raw[TIME_HI_AND_VERSION_BYTE_6] |= (UUID.VERSION_FOUR << 4); 141 142 raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] &= 0x3F; //0011 1111 143 raw[CLOCK_SEQ_HI_AND_RESERVED_BYTE_8] |= 0x80; //1000 0000 144 145 return new UUID(raw); 146 } 147 148 /** 149 * <p>Allows clients to set the pseudo-random number generator implementation used when generating a version four uuid with 150 * the secure option. The secure option uses a <code>SecureRandom</code>. The packageName string may be null to specify 151 * no preferred package.</p> 152 * 153 * @param prngName the pseudo-random number generator implementation name. For example "SHA1PRNG". 154 * @param packageName the package name for the PRNG provider. For example "SUN". 155 */ 156 public static void setPRNGProvider(String prngName, String packageName) { 157 VersionFourGenerator.usePRNG = prngName; 158 VersionFourGenerator.usePRNGPackage = packageName; 159 VersionFourGenerator.secureRandom = null; 160 } 161 }