001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.uml.core.support.umlsupport;
043:
044: /*
045: * RandomGUID
046: * @version 1.2.1 11/05/02
047: * @author Marc A. Mnich
048: *
049: * From www.JavaExchange.com, Open Software licensing
050: *
051: * 11/05/02 -- Performance enhancement from Mike Dubman.
052: * Moved InetAddr.getLocal to static block. Mike has measured
053: * a 10 fold improvement in run time.
054: * 01/29/02 -- Bug fix: Improper seeding of nonsecure Random object
055: * caused duplicate GUIDs to be produced. Random object
056: * is now only created once per JVM.
057: * 01/19/02 -- Modified random seeding and added new constructor
058: * to allow secure random feature.
059: * 01/14/02 -- Added random function seeding with JVM run time
060: *
061: */
062:
063: import org.netbeans.modules.uml.common.ETSystem;
064:
065: import java.net.*;
066: import java.util.*;
067: import java.security.*;
068:
069: /*
070: * In the multitude of java GUID generators, I found none that
071: * guaranteed randomness. GUIDs are guaranteed to be globally unique
072: * by using ethernet MACs, IP addresses, time elements, and sequential
073: * numbers. GUIDs are not expected to be random and most often are
074: * easy/possible to guess given a sample from a given generator.
075: * SQL Server, for example generates GUID that are unique but
076: * sequencial within a given instance.
077: *
078: * GUIDs can be used as security devices to hide things such as
079: * files within a filesystem where listings are unavailable (e.g. files
080: * that are served up from a Web server with indexing turned off).
081: * This may be desireable in cases where standard authentication is not
082: * appropriate. In this scenario, the RandomGUIDs are used as directories.
083: * Another example is the use of GUIDs for primary keys in a database
084: * where you want to ensure that the keys are secret. Random GUIDs can
085: * then be used in a URL to prevent hackers (or users) from accessing
086: * records by guessing or simply by incrementing sequential numbers.
087: *
088: * There are many other possiblities of using GUIDs in the realm of
089: * security and encryption where the element of randomness is important.
090: * This class was written for these purposes but can also be used as a
091: * general purpose GUID generator as well.
092: *
093: * RandomGUID generates truly random GUIDs by using the system's
094: * IP address (name/IP), system time in milliseconds (as an integer),
095: * and a very large random number joined together in a single String
096: * that is passed through an MD5 hash. The IP address and system time
097: * make the MD5 seed globally unique and the random number guarantees
098: * that the generated GUIDs will have no discernable pattern and
099: * cannot be guessed given any number of previously generated GUIDs.
100: * It is generally not possible to access the seed information (IP, time,
101: * random number) from the resulting GUIDs as the MD5 hash algorithm
102: * provides one way encryption.
103: *
104: * ----> Security of RandomGUID: <-----
105: * RandomGUID can be called one of two ways -- with the basic java Random
106: * number generator or a cryptographically strong random generator
107: * (SecureRandom). The choice is offered because the secure random
108: * generator takes about 3.5 times longer to generate its random numbers
109: * and this performance hit may not be worth the added security
110: * especially considering the basic generator is seeded with a
111: * cryptographically strong random seed.
112: *
113: * Seeding the basic generator in this way effectively decouples
114: * the random numbers from the time component making it virtually impossible
115: * to predict the random number component even if one had absolute knowledge
116: * of the System time. Thanks to Ashutosh Narhari for the suggestion
117: * of using the static method to prime the basic random generator.
118: *
119: * Using the secure random option, this class compies with the statistical
120: * random number generator tests specified in FIPS 140-2, Security
121: * Requirements for Cryptographic Modules, secition 4.9.1.
122: *
123: * I converted all the pieces of the seed to a String before handing
124: * it over to the MD5 hash so that you could print it out to make
125: * sure it contains the data you expect to see and to give a nice
126: * warm fuzzy. If you need better performance, you may want to stick
127: * to byte[] arrays.
128: *
129: * I believe that it is important that the algorithm for
130: * generating random GUIDs be open for inspection and modification.
131: * This class is free for all uses.
132: *
133: *
134: * - Marc
135: */
136:
137: public class RandomGUID extends Object {
138:
139: public String valueBeforeMD5 = "";
140: public String valueAfterMD5 = "";
141: private static Random myRand;
142: private static SecureRandom mySecureRand;
143:
144: private static String s_id;
145: private static RandomGUID m_Instance = null;
146:
147: /*
148: * Static block to take care of one time secureRandom seed.
149: * It takes a few seconds to initialize SecureRandom. You might
150: * want to consider removing this static block or replacing
151: * it with a "time since first loaded" seed to reduce this time.
152: * This block will run only once per JVM instance.
153: */
154:
155: static {
156: mySecureRand = new SecureRandom();
157: long secureInitializer = mySecureRand.nextLong();
158: myRand = new Random(secureInitializer);
159: try {
160: s_id = InetAddress.getLocalHost().toString();
161: } catch (UnknownHostException e) {
162: e.printStackTrace();
163: }
164:
165: }
166:
167: public static RandomGUID instance() {
168: if (m_Instance == null) {
169: m_Instance = new RandomGUID();
170: }
171: return m_Instance;
172: }
173:
174: /*
175: * Default constructor. With no specification of security option,
176: * this constructor defaults to lower security, high performance.
177: */
178: public RandomGUID() {
179: getRandomGUID(false);
180: }
181:
182: /*
183: * Constructor with security option. Setting secure true
184: * enables each random number generated to be cryptographically
185: * strong. Secure false defaults to the standard Random function seeded
186: * with a single cryptographically strong random number.
187: */
188: public RandomGUID(boolean secure) {
189: getRandomGUID(secure);
190: }
191:
192: /*
193: * Method to generate the random GUID
194: */
195: private void getRandomGUID(boolean secure) {
196: MessageDigest md5 = null;
197: StringBuffer sbValueBeforeMD5 = new StringBuffer();
198:
199: try {
200: md5 = MessageDigest.getInstance("MD5");
201: } catch (NoSuchAlgorithmException e) {
202: ETSystem.out.println("Error: " + e);
203: }
204:
205: try {
206: long time = System.currentTimeMillis();
207: long rand = 0;
208:
209: if (secure) {
210: rand = mySecureRand.nextLong();
211: } else {
212: rand = myRand.nextLong();
213: }
214:
215: // This StringBuffer can be a long as you need; the MD5
216: // hash will always return 128 bits. You can change
217: // the seed to include anything you want here.
218: // You could even stream a file through the MD5 making
219: // the odds of guessing it at least as great as that
220: // of guessing the contents of the file!
221: sbValueBeforeMD5.append(s_id);
222: sbValueBeforeMD5.append(":");
223: sbValueBeforeMD5.append(Long.toString(time));
224: sbValueBeforeMD5.append(":");
225: sbValueBeforeMD5.append(Long.toString(rand));
226:
227: valueBeforeMD5 = sbValueBeforeMD5.toString();
228: md5.update(valueBeforeMD5.getBytes());
229:
230: byte[] array = md5.digest();
231: StringBuffer sb = new StringBuffer();
232: for (int j = 0; j < array.length; ++j) {
233: int b = array[j] & 0xFF;
234: if (b < 0x10)
235: sb.append('0');
236: sb.append(Integer.toHexString(b));
237: }
238:
239: valueAfterMD5 = sb.toString();
240:
241: } catch (Exception e) {
242: ETSystem.out.println("Error:" + e);
243: }
244: }
245:
246: public static String getGUID() {
247: String str = null;
248: //str = RandomGUID.instance();
249: return str;
250: }
251:
252: /*
253: * Convert to the standard format for GUID
254: * (Useful for SQL Server UniqueIdentifiers, etc.)
255: * Example: C2FEEEAC-CFCD-11D1-8B05-00600806D9B6
256: */
257: public String toString() {
258: String raw = valueAfterMD5.toUpperCase();
259: StringBuffer sb = new StringBuffer();
260: sb.append(raw.substring(0, 8));
261: sb.append("-");
262: sb.append(raw.substring(8, 12));
263: sb.append("-");
264: sb.append(raw.substring(12, 16));
265: sb.append("-");
266: sb.append(raw.substring(16, 20));
267: sb.append("-");
268: sb.append(raw.substring(20));
269:
270: return sb.toString();
271: }
272:
273: /*
274: * Demonstraton and self test of class
275: */
276: public static void main(String args[]) {
277: for (int i = 0; i < 100; i++) {
278: RandomGUID myGUID = new RandomGUID();
279: ETSystem.out.println("Seeding String="
280: + myGUID.valueBeforeMD5);
281: ETSystem.out.println("rawGUID=" + myGUID.valueAfterMD5);
282: ETSystem.out.println("RandomGUID=" + myGUID.toString());
283: }
284: }
285: }
|