KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > webflow > util > RandomGuid


1 /*
2  * Copyright 2002-2006 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.webflow.util;
17
18 /*
19  * RandomGUID from http://www.javaexchange.com/aboutRandomGUID.html
20  * @version 1.2.1 11/05/02
21  * @author Marc A. Mnich
22  *
23  * From www.JavaExchange.com, Open Software licensing
24  *
25  * 11/05/02 -- Performance enhancement from Mike Dubman.
26  * Moved InetAddr.getLocal to static block. Mike has measured
27  * a 10 fold improvement in run time.
28  * 01/29/02 -- Bug fix: Improper seeding of nonsecure Random object
29  * caused duplicate GUIDs to be produced. Random object
30  * is now only created once per JVM.
31  * 01/19/02 -- Modified random seeding and added new constructor
32  * to allow secure random feature.
33  * 01/14/02 -- Added random function seeding with JVM run time
34  */

35
36 import java.net.InetAddress JavaDoc;
37 import java.net.UnknownHostException JavaDoc;
38 import java.security.MessageDigest JavaDoc;
39 import java.security.NoSuchAlgorithmException JavaDoc;
40 import java.security.SecureRandom JavaDoc;
41 import java.util.Random JavaDoc;
42
43 /**
44  * Globally unique identifier generator.
45  * <p>
46  * In the multitude of java GUID generators, I found none that guaranteed
47  * randomness. GUIDs are guaranteed to be globally unique by using ethernet
48  * MACs, IP addresses, time elements, and sequential numbers. GUIDs are not
49  * expected to be random and most often are easy/possible to guess given a
50  * sample from a given generator. SQL Server, for example generates GUID that
51  * are unique but sequencial within a given instance.
52  * <p>
53  * GUIDs can be used as security devices to hide things such as files within a
54  * filesystem where listings are unavailable (e.g. files that are served up from
55  * a Web server with indexing turned off). This may be desireable in cases where
56  * standard authentication is not appropriate. In this scenario, the RandomGuids
57  * are used as directories. Another example is the use of GUIDs for primary keys
58  * in a database where you want to ensure that the keys are secret. Random GUIDs
59  * can then be used in a URL to prevent hackers (or users) from accessing
60  * records by guessing or simply by incrementing sequential numbers.
61  * <p>
62  * There are many other possiblities of using GUIDs in the realm of security and
63  * encryption where the element of randomness is important. This class was
64  * written for these purposes but can also be used as a general purpose GUID
65  * generator as well.
66  * <p>
67  * RandomGuid generates truly random GUIDs by using the system's IP address
68  * (name/IP), system time in milliseconds (as an integer), and a very large
69  * random number joined together in a single String that is passed through an
70  * MD5 hash. The IP address and system time make the MD5 seed globally unique
71  * and the random number guarantees that the generated GUIDs will have no
72  * discernable pattern and cannot be guessed given any number of previously
73  * generated GUIDs. It is generally not possible to access the seed information
74  * (IP, time, random number) from the resulting GUIDs as the MD5 hash algorithm
75  * provides one way encryption.
76  * <p>
77  * <b>Security of RandomGuid</b>: RandomGuid can be called one of two ways --
78  * with the basic java Random number generator or a cryptographically strong
79  * random generator (SecureRandom). The choice is offered because the secure
80  * random generator takes about 3.5 times longer to generate its random numbers
81  * and this performance hit may not be worth the added security especially
82  * considering the basic generator is seeded with a cryptographically strong
83  * random seed.
84  * <p>
85  * Seeding the basic generator in this way effectively decouples the random
86  * numbers from the time component making it virtually impossible to predict the
87  * random number component even if one had absolute knowledge of the System
88  * time. Thanks to Ashutosh Narhari for the suggestion of using the static
89  * method to prime the basic random generator.
90  * <p>
91  * Using the secure random option, this class complies with the statistical
92  * random number generator tests specified in FIPS 140-2, Security Requirements
93  * for Cryptographic Modules, secition 4.9.1.
94  * <p>
95  * I converted all the pieces of the seed to a String before handing it over to
96  * the MD5 hash so that you could print it out to make sure it contains the data
97  * you expect to see and to give a nice warm fuzzy. If you need better
98  * performance, you may want to stick to byte[] arrays.
99  * <p>
100  * I believe that it is important that the algorithm for generating random GUIDs
101  * be open for inspection and modification. This class is free for all uses.
102  *
103  * @version 1.2.1 11/05/02
104  * @author Marc A. Mnich
105  */

106 public class RandomGuid extends Object JavaDoc {
107
108     private static Random JavaDoc random;
109
110     private static SecureRandom JavaDoc secureRandom;
111
112     private static String JavaDoc id;
113
114     private String JavaDoc valueBeforeMD5 = "";
115
116     private String JavaDoc valueAfterMD5 = "";
117
118     /*
119      * Static block to take care of one time secureRandom seed. It takes a few
120      * seconds to initialize SecureRandom. You might want to consider removing
121      * this static block or replacing it with a "time since first loaded" seed
122      * to reduce this time. This block will run only once per JVM instance.
123      */

124     static {
125         secureRandom = new SecureRandom JavaDoc();
126         long secureInitializer = secureRandom.nextLong();
127         random = new Random JavaDoc(secureInitializer);
128         try {
129             id = InetAddress.getLocalHost().toString();
130         }
131         catch (UnknownHostException JavaDoc e) {
132             throw new RuntimeException JavaDoc(e);
133         }
134     }
135
136     /**
137      * Default constructor. With no specification of security option, this
138      * constructor defaults to lower security, high performance.
139      */

140     public RandomGuid() {
141         getRandomGuid(false);
142     }
143
144     /**
145      * Constructor with security option. Setting secure true enables each random
146      * number generated to be cryptographically strong. Secure false defaults to
147      * the standard Random function seeded with a single cryptographically
148      * strong random number.
149      */

150     public RandomGuid(boolean secure) {
151         getRandomGuid(secure);
152     }
153
154     /**
155      * Method to generate the random GUID.
156      */

157     private void getRandomGuid(boolean secure) {
158         MessageDigest JavaDoc md5 = null;
159         StringBuffer JavaDoc sbValueBeforeMD5 = new StringBuffer JavaDoc();
160
161         try {
162             md5 = MessageDigest.getInstance("MD5");
163         }
164         catch (NoSuchAlgorithmException JavaDoc e) {
165             throw new RuntimeException JavaDoc(e);
166         }
167
168         long time = System.currentTimeMillis();
169         long rand = 0;
170
171         if (secure) {
172             rand = secureRandom.nextLong();
173         }
174         else {
175             rand = random.nextLong();
176         }
177
178         // This StringBuffer can be a long as you need; the MD5
179
// hash will always return 128 bits. You can change
180
// the seed to include anything you want here.
181
// You could even stream a file through the MD5 making
182
// the odds of guessing it at least as great as that
183
// of guessing the contents of the file!
184
sbValueBeforeMD5.append(id);
185         sbValueBeforeMD5.append(":");
186         sbValueBeforeMD5.append(Long.toString(time));
187         sbValueBeforeMD5.append(":");
188         sbValueBeforeMD5.append(Long.toString(rand));
189
190         valueBeforeMD5 = sbValueBeforeMD5.toString();
191         md5.update(valueBeforeMD5.getBytes());
192
193         byte[] array = md5.digest();
194         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
195         for (int j = 0; j < array.length; ++j) {
196             int b = array[j] & 0xFF;
197             if (b < 0x10)
198                 sb.append('0');
199             sb.append(Integer.toHexString(b));
200         }
201         valueAfterMD5 = sb.toString();
202     }
203
204     /**
205      * Convert to the standard format for GUID (Useful for SQL Server
206      * UniqueIdentifiers, etc).
207      * Example: "C2FEEEAC-CFCD-11D1-8B05-00600806D9B6".
208      */

209     public String JavaDoc toString() {
210         String JavaDoc raw = valueAfterMD5.toUpperCase();
211         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
212         sb.append(raw.substring(0, 8));
213         sb.append("-");
214         sb.append(raw.substring(8, 12));
215         sb.append("-");
216         sb.append(raw.substring(12, 16));
217         sb.append("-");
218         sb.append(raw.substring(16, 20));
219         sb.append("-");
220         sb.append(raw.substring(20));
221         return sb.toString();
222     }
223 }
Popular Tags