Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: net/jxta/impl/id/binaryID/DigestTool.java


1   /*
2    * Copyright (c) 2001 Sun Microsystems, Inc.  All rights
3    * reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    * 1. Redistributions of source code must retain the above copyright
10   *    notice, this list of conditions and the following disclaimer.
11   *
12   * 2. Redistributions in binary form must reproduce the above copyright
13   *    notice, this list of conditions and the following disclaimer in
14   *    the documentation and/or other materials provided with the
15   *    distribution.
16   *
17   * 3. The end-user documentation included with the redistribution,
18   *    if any, must include the following acknowledgment:
19   *       "This product includes software developed by the
20   *       Sun Microsystems, Inc. for Project JXTA."
21   *    Alternately, this acknowledgment may appear in the software itself,
22   *    if and wherever such third-party acknowledgments normally appear.
23   *
24   * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
25   *    not be used to endorse or promote products derived from this
26   *    software without prior written permission. For written
27   *    permission, please contact Project JXTA at http://www.jxta.org.
28   *
29   * 5. Products derived from this software may not be called "JXTA",
30   *    nor may "JXTA" appear in their name, without prior written
31   *    permission of Sun.
32   *
33   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36   * DISCLAIMED.  IN NO EVENT SHALL SUN MICROSYSTEMS OR
37   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44   * SUCH DAMAGE.
45   * ====================================================================
46   *
47   * This software consists of voluntary contributions made by many
48   * individuals on behalf of Project JXTA.  For more
49   * information on Project JXTA, please see
50   * <http://www.jxta.org/>.
51   *
52   * This license is based on the BSD license adopted by the Apache Foundation.
53   *
54   * $Id: DigestTool.java,v 1.6 2004/06/08 21:29:04 bondolo Exp $
55   */
56  
57  package net.jxta.impl.id.binaryID;
58  
59  /**
60   */
61  import net.jxta.impl.id.binaryID.*;
62  import java.io.*;
63  
64  import java.security.*;
65  
66  /**
67   * This is a utility class used to create pipe advertisement named and BinaryID for the pipeID to create
68   * a private address space that can be hosted in the public discovery system or sent over unencrypted
69   * channeds without revealing their intent or purpose. <p>
70   *
71   * We use a one-way hashing algorythum to create an ID from private information like
72   * a user's social security number or a user's email address.
73   * We search for the pipe by with this private information securly by creating the
74   * matching hash using the same methods. <p>
75   *
76   * The purpose of this system is to create a way to search
77   * for a pipe (or other BinaryID based system) without exposing the
78   * pipe owner's clearTextID while allowing for  people that
79   * know what they are looking for to find the right pipe. The
80   * system also has the ability to create pipes that have a specific purpose.
81   * For example, the email address is appended with a function name. Say you
82   * have a pipe for messages and one for administrative purposes. You would
83   * supply the email and a string for the function. The same combination can be
84   * created by another peer to search for either of these pipes. <p>
85   *
86   * This implementation uses the "SHA-1" algorythum. This was selected for relitive
87   * speed. It is used as a one-way conversion that cannot be reversed engineered to
88   * create the original string. This allows you to publish the hash without the
89   * possibility of the contents being decoded. This allows for public indexing of
90   * data that is only known by the parties involved.<p>
91   *
92   * Note that this can also be used to generate safe password verification hash codes.
93   *Sample useage:
94   *<code>
95   *        String clearTextID = "turbogeek@cluck.com";
96   *        String function = "eventPipe";
97   *        System.out.println("clear text ID: "+clearTextID);
98   *        System.out.println("function text: "+function);
99   *        String digest1 = DigestID.generateHashString(clearTextID, function);
100  *        String digest2 = DigestID.generateHashString(clearTextID);
101  *        System.out.println("Digest1: '"+digest1+"'");
102  *        System.out.println("Digest2: '"+digest2+"'");
103  *        System.out.println("test1: "+DigestID.test(clearTextID, function,digest1));
104  *        System.out.println("test2: "+DigestID.test(clearTextID, digest2));
105  *        System.out.println("Digest1 != Digest2: "+DigestID.test(clearTextID, function,digest2));
106  *</code><p>
107  *
108  * To use an algorythum other than SHA-1, you will need stronger encyption.
109  * The BouncyCastle that comes with JXTA is just a minimum implimentation so
110  * a good choice is  the normal bouncy castle (it is much larger, nearing a meg,
111  * which is why it is not a part of the normal JXTA distribution. The full version
112  * of bouncy includes SHA-128, SHA-256, SHA-384, and SHA-512.<p>
113  * 
114  * Here is how you create a provider from the full version of Bouncy. Once you do this, you can access the extended
115  * Digest ecryption levels. 
116  *<code>
117  *       provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
118  *       System.out.println("provider:"+provider.getName());
119  *       Security.addProvider(provider);
120  *</code><p>
121  * Security Note<p>
122  *<p>
123  * This class should have all of its fields and properties marked as 'final' to prevent overriding the default behavior.
124  * Failure to do so could allow a less scrupulous person to cause the BinaryID or hash codes to contain the original information.
125  * Note that the class itself is not final to allow for additional convienience methods to be added. There
126  * a no methods for creating ModuleClassBinaryID, ModuleSpecBinaryID, or CodatID because this is meant for general'
127  * use, not for extending platform (you can write your own using similar code). <p>
128  *
129  * @version $Revision: 1.6 $
130  * @author Daniel Brookshier <a HREF="mailto:turbogeek@cluck.com">turbogeek@cluck.com</a>
131  */
132 public class DigestTool {
133     private  static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DigestTool.class.getName());
134     /** varaible used for conditional compile of debug printing.*/
135     public  static final boolean debug = true;
136     /** Defualt SHA-1 digest algorithm type. This is a 20 byte hash function (note: that MD5 is only 16 so we don't use it). */
137     public  static final String SHAOne  = "SHA-1";
138     /** SHA-128 digest algorithm type. This is a 128 bit hash function (note: must have another provider registered to use). */
139     public  static final String SHA128  = "SHA-128";
140     /** SHA-256 digest algorithm type. This is a 256 bit hash function (note: must have another provider registered to use). */
141     public  static final String SHA256  = "SHA-256";
142     /** SHA-384 digest algorithm type. This is a 384 bit hash function (note: must have another provider registered to use). */
143     public  static final String SHA384  = "SHA-384";
144     /** SHA-512 digest algorithm type. This is a 512 bit hash function (note: must have another provider registered to use). */
145     public  static final String SHA512  = "SHA-512";
146     /** Tilde character used to seperate candidate strings from a function.*/
147     public  final String functionSeperator = "~";
148     String algorithmType;
149     public DigestTool(){
150         algorithmType=SHAOne;
151     }
152     public DigestTool(String algorithmType){
153         this.algorithmType = algorithmType;
154     }
155      
156     /** 
157      * Create a PipeID based on the BinaryID type with a digest of the clearTextID and function.
158      * 
159      * @param peerGroupID Parent peer group ID.
160      * @param clearTextID String used as the significant part of the address
161      * @param function String used to diferentiate different clearTextID addresses (can be null).
162      * @return PipeBinaryID with the digest hash of the string: clearTextID+"~"+function.
163      */
164     public final PipeBinaryID createPipeID(net.jxta.peergroup.PeerGroupID peerGroupID,String clearTextID, String function){
165         byte[] digest = generateHash(clearTextID, function); 
166         PipeBinaryID pipe = new PipeBinaryID(peerGroupID,digest,false); 
167         return pipe;
168     }
169     /** 
170      * Create a PeerGroupID based on the BinaryID type with a digest of the clearTextID and function.
171      * 
172      * @param peerGroupID Parent peer group ID.
173      * @param clearTextID String used as the significant part of the address
174      * @param function String used to diferentiate different clearTextID addresses (can be null).
175      * @return PeerGroupBinaryID with the digest hash of the string: clearTextID+"~"+function.
176      */
177     public final PeerGroupBinaryID createPeerGroupID(net.jxta.peergroup.PeerGroupID parentPeerGroupID,String clearTextID, String function){
178         byte[] digest = generateHash(clearTextID, function); 
179         PeerGroupBinaryID peerGroupID = new PeerGroupBinaryID(parentPeerGroupID,digest,false); 
180         return peerGroupID;
181     }
182     /** 
183      * Create a PeerID based on the BinaryID type with a digest of the clearTextID and function.
184      * 
185      * @param peerGroupID Parent peer group ID.
186      * @param clearTextID String used as the significant part of the address
187      * @param function String used to diferentiate different clearTextID addresses (can be null).
188      * @return PeerBinaryID with the digest hash of the string: clearTextID+"~"+function.
189      */
190     public final PeerBinaryID createPeerID(net.jxta.peergroup.PeerGroupID peerGroupID,String clearTextID, String function){
191         byte[] digest = generateHash(clearTextID, function); 
192         PeerBinaryID peerID = new PeerBinaryID(peerGroupID,digest,false); 
193         return peerID;
194     }
195 
196     /**
197      * Creates a new instance of DigestPipe. Because this is a  utility,
198      * this is private to prevent construction.
199      */
200     /**
201      * Generates a Base64 encoded string of an SHA-1 digest hash of the string: clearTextID.<p>
202      *
203      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
204      *
205      * @return Base64 encoded string containing the hash of the string: clearTextID.
206      */
207     public  final String  generateHashString(String clearTextID){
208         try {
209         java.io.StringWriter base64 = new java.io.StringWriter();
210         net.jxta.impl.util.BASE64OutputStream encode = new net.jxta.impl.util.BASE64OutputStream( base64 );
211         
212         encode.write( generateHash(clearTextID) );
213         encode.close();
214         
215         return base64.toString();
216         } catch( Exception failed ) {
217             LOG.error("Unable to encode hash value.", failed);
218             throw new RuntimeException("Unable to encode hash value."); 
219         }
220     }
221     /**
222      * Generates a Base64 encoded string of an SHA-1 digest hash of the string: clearTextID+"-"+function or: clearTextID if function was blank.<p>
223      *
224      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
225      * @param function A function related to the clearTextID string. This is used to create a hash associated with clearTextID so that it is a uique code.
226      *
227      * @return Base64 encoded string containing the hash of the string: clearTextID+"-"+function or clearTextID if function was blank.
228      */
229     public  final String  generateHashString(String clearTextID, String function){
230         try {
231         java.io.StringWriter base64 = new java.io.StringWriter();
232         net.jxta.impl.util.BASE64OutputStream encode = new net.jxta.impl.util.BASE64OutputStream( base64 );
233         
234         encode.write( generateHash(clearTextID, function) );
235         encode.close();
236         
237         return base64.toString();
238         } catch( Exception failed ) {
239             LOG.error("Unable to encode hash value.", failed);
240             throw new RuntimeException("Unable to encode hash value.");        }
241     }
242     
243     /**
244      * Generates a SHA-1 digest hash of the string: clearTextID.<p>
245      *
246      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
247      *
248      * @return String containing the hash of the string: clearTextID.
249      */
250     public  final byte[] generateHash(String clearTextID) {
251         return generateHash(clearTextID, null);
252     }
253     
254     /**
255      * Generates an SHA-1 digest hash of the string: clearTextID+"-"+function or: clearTextID if function was blank.<p>
256      *
257      * Note that the SHA-1 used only creates a 20 byte hash.<p>
258      *
259      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
260      * @param function A function related to the clearTextID string. This is used to create a hash associated with clearTextID so that it is a uique code.
261      *
262      * @return array of bytes containing the hash of the string: clearTextID+"-"+function or clearTextID if function was blank. Can return null if SHA-1 does not exist on platform.
263      */
264     public  final byte[] generateHash(String clearTextID, String function) {
265         String id;
266         
267         if (function == null) {
268             id = clearTextID;
269         } else {
270             id = clearTextID + functionSeperator + function;
271         }
272         byte[] buffer = id.getBytes();
273         
274         MessageDigest algorithm = null;
275         
276         try {
277             algorithm = MessageDigest.getInstance(algorithmType);
278         } catch (Exception e) {
279             LOG.error("Cannot load selected Digest Hash implementation",e);
280             return null;
281         }
282         
283         
284         // Generate the digest.
285         algorithm.reset();
286         algorithm.update(buffer);
287         
288         try{
289             byte[] digest1 = algorithm.digest(); 
290             return digest1;
291         }catch(Exception de){
292             LOG.error("Failed to creat a digest.",de);
293             return null;
294         }
295     }
296     /**
297      * Generates an SHA-1 digest hash of the string: clearTextID.<p>
298      *
299      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
300      *
301      * @return String containing the hash of the string: clearTextID.
302      */
303     public  final boolean test( String clearTextID, String function, String testHash) {
304         String id = clearTextID + functionSeperator + function;
305         return test(id,testHash);
306         
307     }
308     /** Compares a clear text code or ID with a candidate hash code.
309      * This is used to confirm that the clearTextID can be successfully converted to the hash.
310      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
311      * @param testHash A string of hashed string.
312      * @return true if the hash created from clearTextID is equal to the testHash string.Can return false if SHA-1 does not exist on platform.
313      */
314     public  final boolean test(String clearTextID, String testHash) {
315         
316         byte[] digest1 = generateHash(clearTextID);
317         byte[] digest2;
318         try{
319             java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
320             net.jxta.impl.util.BASE64InputStream decoder = new net.jxta.impl.util.BASE64InputStream( new java.io.StringReader(testHash) );
321             
322             while( true ) {
323                 int c = decoder.read();
324                 if( -1 == c ) {
325                     break;
326                 }
327                 
328                 bos.write( c );
329             }
330 
331             digest2 = bos.toByteArray();
332         }catch(Exception e){
333             LOG.error("Failed to create a digest.",e);
334             return false;
335         }
336         
337         
338         if (digest1.length != digest2.length) {
339             // Not a match! because of length.
340             return false;
341         }
342         
343         for (int i = 0; i < digest1.length; i++) {
344             if (digest1[i] != digest2[i]) {
345                 // Not a match because of byte:"+i+" did not match
346                 return false;
347             }
348         }
349         
350         // Match was ok
351         return true;
352     }
353     /** Compares a clear text code or ID with a candidate hash code.
354      * This is used to confirm that the clearTextID can be successfully converted to the hash.
355      * @param clearTextID A string that is to be hashed. This can be any string used for hashing or hiding data.
356      * @param testHash A string of hashed string.
357      * @return true if the hash created from clearTextID is equal to the testHash string.Can return false if SHA-1 does not exist on platform.
358      */
359     public  final boolean test(String clearTextID,byte[] testHash) {
360         
361         byte[] digest1 = generateHash(clearTextID);
362         
363         
364         
365         if (digest1.length != testHash.length) {
366             // Not a match! because of length.
367             return false;
368         }
369         
370         for (int i = 0; i < testHash.length; i++) {
371             if (digest1[i] != testHash[i]) {
372                 // Not a match because of byte:"+i+" did not match
373                 return false;
374             }
375         }
376         
377         // Match was ok
378         return true;
379     }
380 }