KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > security > MessageDigest


1 /*
2  * @(#)MessageDigest.java 1.77 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.security;
9
10 import java.util.*;
11 import java.lang.*;
12 import java.io.IOException JavaDoc;
13 import java.io.ByteArrayOutputStream JavaDoc;
14 import java.io.PrintStream JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.io.ByteArrayInputStream JavaDoc;
17
18 import java.nio.ByteBuffer JavaDoc;
19
20 /**
21  * This MessageDigest class provides applications the functionality of a
22  * message digest algorithm, such as MD5 or SHA.
23  * Message digests are secure one-way hash functions that take arbitrary-sized
24  * data and output a fixed-length hash value.
25  *
26  * <p>A MessageDigest object starts out initialized. The data is
27  * processed through it using the {@link #update(byte) update}
28  * methods. At any point {@link #reset() reset} can be called
29  * to reset the digest. Once all the data to be updated has been
30  * updated, one of the {@link #digest() digest} methods should
31  * be called to complete the hash computation.
32  *
33  * <p>The <code>digest</code> method can be called once for a given number
34  * of updates. After <code>digest</code> has been called, the MessageDigest
35  * object is reset to its initialized state.
36  *
37  * <p>Implementations are free to implement the Cloneable interface.
38  * Client applications can test cloneability by attempting cloning
39  * and catching the CloneNotSupportedException: <p>
40  *
41 * <pre>
42 * MessageDigest md = MessageDigest.getInstance("SHA");
43 *
44 * try {
45 * md.update(toChapter1);
46 * MessageDigest tc1 = md.clone();
47 * byte[] toChapter1Digest = tc1.digest();
48 * md.update(toChapter2);
49 * ...etc.
50 * } catch (CloneNotSupportedException cnse) {
51 * throw new DigestException("couldn't make digest of partial content");
52 * }
53 * </pre>
54  *
55  * <p>Note that if a given implementation is not cloneable, it is
56  * still possible to compute intermediate digests by instantiating
57  * several instances, if the number of digests is known in advance.
58  *
59  * <p>Note that this class is abstract and extends from
60  * <code>MessageDigestSpi</code> for historical reasons.
61  * Application developers should only take notice of the methods defined in
62  * this <code>MessageDigest</code> class; all the methods in
63  * the superclass are intended for cryptographic service providers who wish to
64  * supply their own implementations of message digest algorithms.
65  *
66  * @author Benjamin Renaud
67  *
68  * @version 1.77, 12/19/03
69  *
70  * @see DigestInputStream
71  * @see DigestOutputStream
72  */

73
74 public abstract class MessageDigest extends MessageDigestSpi JavaDoc {
75
76     private String JavaDoc algorithm;
77
78     // The state of this digest
79
private static final int INITIAL = 0;
80     private static final int IN_PROGRESS = 1;
81     private int state = INITIAL;
82
83     // The provider
84
private Provider JavaDoc provider;
85
86     /**
87      * Creates a message digest with the specified algorithm name.
88      *
89      * @param algorithm the standard name of the digest algorithm.
90      * See Appendix A in the <a HREF=
91      * "../../../guide/security/CryptoSpec.html#AppA">
92      * Java Cryptography Architecture API Specification &amp; Reference </a>
93      * for information about standard algorithm names.
94      */

95     protected MessageDigest(String JavaDoc algorithm) {
96     this.algorithm = algorithm;
97     }
98
99     /**
100      * Generates a MessageDigest object that implements the specified digest
101      * algorithm. If the default provider package
102      * provides an implementation of the requested digest algorithm,
103      * an instance of MessageDigest containing that implementation is returned.
104      * If the algorithm is not available in the default
105      * package, other packages are searched.
106      *
107      * @param algorithm the name of the algorithm requested.
108      * See Appendix A in the <a HREF=
109      * "../../../guide/security/CryptoSpec.html#AppA">
110      * Java Cryptography Architecture API Specification &amp; Reference </a>
111      * for information about standard algorithm names.
112      *
113      * @return a Message Digest object implementing the specified
114      * algorithm.
115      *
116      * @exception NoSuchAlgorithmException if the algorithm is
117      * not available in the caller's environment.
118      */

119     public static MessageDigest JavaDoc getInstance(String JavaDoc algorithm)
120     throws NoSuchAlgorithmException JavaDoc {
121     try {
122         Object JavaDoc[] objs = Security.getImpl(algorithm, "MessageDigest",
123                          (String JavaDoc)null);
124         if (objs[0] instanceof MessageDigest JavaDoc) {
125         MessageDigest JavaDoc md = (MessageDigest JavaDoc)objs[0];
126         md.provider = (Provider JavaDoc)objs[1];
127         return md;
128         } else {
129         MessageDigest JavaDoc delegate =
130             new Delegate((MessageDigestSpi JavaDoc)objs[0], algorithm);
131         delegate.provider = (Provider JavaDoc)objs[1];
132         return delegate;
133         }
134     } catch(NoSuchProviderException JavaDoc e) {
135         throw new NoSuchAlgorithmException JavaDoc(algorithm + " not found");
136     }
137     }
138
139     /**
140      * Generates a MessageDigest object implementing the specified
141      * algorithm, as supplied from the specified provider, if such an
142      * algorithm is available from the provider.
143      *
144      * @param algorithm the name of the algorithm requested.
145      * See Appendix A in the <a HREF=
146      * "../../../guide/security/CryptoSpec.html#AppA">
147      * Java Cryptography Architecture API Specification &amp; Reference </a>
148      * for information about standard algorithm names.
149      *
150      * @param provider the name of the provider.
151      *
152      * @return a Message Digest object implementing the specified
153      * algorithm.
154      *
155      * @exception NoSuchAlgorithmException if the algorithm is
156      * not available in the package supplied by the requested
157      * provider.
158      *
159      * @exception NoSuchProviderException if the provider is not
160      * available in the environment.
161      *
162      * @exception IllegalArgumentException if the provider name is null
163      * or empty.
164      *
165      * @see Provider
166      */

167     public static MessageDigest JavaDoc getInstance(String JavaDoc algorithm, String JavaDoc provider)
168     throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc
169     {
170     if (provider == null || provider.length() == 0)
171         throw new IllegalArgumentException JavaDoc("missing provider");
172     Object JavaDoc[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
173     if (objs[0] instanceof MessageDigest JavaDoc) {
174         MessageDigest JavaDoc md = (MessageDigest JavaDoc)objs[0];
175         md.provider = (Provider JavaDoc)objs[1];
176         return md;
177     } else {
178         MessageDigest JavaDoc delegate =
179         new Delegate((MessageDigestSpi JavaDoc)objs[0], algorithm);
180         delegate.provider = (Provider JavaDoc)objs[1];
181         return delegate;
182     }
183     }
184
185     /**
186      * Generates a MessageDigest object implementing the specified
187      * algorithm, as supplied from the specified provider, if such an
188      * algorithm is available from the provider. Note: the
189      * <code>provider</code> doesn't have to be registered.
190      *
191      * @param algorithm the name of the algorithm requested.
192      * See Appendix A in the <a HREF=
193      * "../../../guide/security/CryptoSpec.html#AppA">
194      * Java Cryptography Architecture API Specification &amp; Reference </a>
195      * for information about standard algorithm names.
196      *
197      * @param provider the provider.
198      *
199      * @return a Message Digest object implementing the specified
200      * algorithm.
201      *
202      * @exception NoSuchAlgorithmException if the algorithm is
203      * not available in the package supplied by the requested
204      * provider.
205      *
206      * @exception IllegalArgumentException if the <code>provider</code> is
207      * null.
208      *
209      * @see Provider
210      *
211      * @since 1.4
212      */

213     public static MessageDigest JavaDoc getInstance(String JavaDoc algorithm,
214                         Provider JavaDoc provider)
215     throws NoSuchAlgorithmException JavaDoc
216     {
217     if (provider == null)
218         throw new IllegalArgumentException JavaDoc("missing provider");
219     Object JavaDoc[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
220     if (objs[0] instanceof MessageDigest JavaDoc) {
221         MessageDigest JavaDoc md = (MessageDigest JavaDoc)objs[0];
222         md.provider = (Provider JavaDoc)objs[1];
223         return md;
224     } else {
225         MessageDigest JavaDoc delegate =
226         new Delegate((MessageDigestSpi JavaDoc)objs[0], algorithm);
227         delegate.provider = (Provider JavaDoc)objs[1];
228         return delegate;
229     }
230     }
231
232     /**
233      * Returns the provider of this message digest object.
234      *
235      * @return the provider of this message digest object
236      */

237     public final Provider JavaDoc getProvider() {
238     return this.provider;
239     }
240
241     /**
242      * Updates the digest using the specified byte.
243      *
244      * @param input the byte with which to update the digest.
245      */

246     public void update(byte input) {
247     engineUpdate(input);
248     state = IN_PROGRESS;
249     }
250
251     /**
252      * Updates the digest using the specified array of bytes, starting
253      * at the specified offset.
254      *
255      * @param input the array of bytes.
256      *
257      * @param offset the offset to start from in the array of bytes.
258      *
259      * @param len the number of bytes to use, starting at
260      * <code>offset</code>.
261      */

262     public void update(byte[] input, int offset, int len) {
263     if (input == null) {
264         throw new IllegalArgumentException JavaDoc("No input buffer given");
265     }
266     if (input.length - offset < len) {
267         throw new IllegalArgumentException JavaDoc("Input buffer too short");
268     }
269     engineUpdate(input, offset, len);
270     state = IN_PROGRESS;
271     }
272
273     /**
274      * Updates the digest using the specified array of bytes.
275      *
276      * @param input the array of bytes.
277      */

278     public void update(byte[] input) {
279     engineUpdate(input, 0, input.length);
280     state = IN_PROGRESS;
281     }
282
283     /**
284      * Update the digest using the specified ByteBuffer. The digest is
285      * updated using the <code>input.remaining()</code> bytes starting
286      * at <code>input.position()</code>.
287      * Upon return, the buffer's position will be equal to its limit;
288      * its limit will not have changed.
289      *
290      * @param input the ByteBuffer
291      * @since 1.5
292      */

293     public final void update(ByteBuffer JavaDoc input) {
294     if (input == null) {
295         throw new NullPointerException JavaDoc();
296     }
297     engineUpdate(input);
298     state = IN_PROGRESS;
299     }
300
301     /**
302      * Completes the hash computation by performing final operations
303      * such as padding. The digest is reset after this call is made.
304      *
305      * @return the array of bytes for the resulting hash value.
306      */

307     public byte[] digest() {
308     /* Resetting is the responsibility of implementors. */
309     byte[] result = engineDigest();
310     state = INITIAL;
311     return result;
312     }
313
314     /**
315      * Completes the hash computation by performing final operations
316      * such as padding. The digest is reset after this call is made.
317      *
318      * @param buf output buffer for the computed digest
319      *
320      * @param offset offset into the output buffer to begin storing the digest
321      *
322      * @param len number of bytes within buf allotted for the digest
323      *
324      * @return the number of bytes placed into <code>buf</code>
325      *
326      * @exception DigestException if an error occurs.
327      */

328     public int digest(byte[] buf, int offset, int len) throws DigestException JavaDoc {
329     if (buf == null) {
330         throw new IllegalArgumentException JavaDoc("No output buffer given");
331     }
332     if (buf.length - offset < len) {
333         throw new IllegalArgumentException JavaDoc
334         ("Output buffer too small for specified offset and length");
335     }
336     int numBytes = engineDigest(buf, offset, len);
337     state = INITIAL;
338     return numBytes;
339     }
340
341     /**
342      * Performs a final update on the digest using the specified array
343      * of bytes, then completes the digest computation. That is, this
344      * method first calls {@link #update(byte[]) update(input)},
345      * passing the <i>input</i> array to the <code>update</code> method,
346      * then calls {@link #digest() digest()}.
347      *
348      * @param input the input to be updated before the digest is
349      * completed.
350      *
351      * @return the array of bytes for the resulting hash value.
352      */

353     public byte[] digest(byte[] input) {
354     update(input);
355     return digest();
356     }
357
358     /**
359      * Returns a string representation of this message digest object.
360      */

361     public String JavaDoc toString() {
362     ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
363     PrintStream JavaDoc p = new PrintStream JavaDoc(baos);
364     p.print(algorithm+" Message Digest from "+provider.getName()+", ");
365     switch (state) {
366     case INITIAL:
367         p.print("<initialized>");
368         break;
369     case IN_PROGRESS:
370         p.print("<in progress>");
371         break;
372     }
373     p.println();
374     return (baos.toString());
375     }
376
377     /**
378      * Compares two digests for equality. Does a simple byte compare.
379      *
380      * @param digesta one of the digests to compare.
381      *
382      * @param digestb the other digest to compare.
383      *
384      * @return true if the digests are equal, false otherwise.
385      */

386     public static boolean isEqual(byte digesta[], byte digestb[]) {
387     if (digesta.length != digestb.length)
388         return false;
389
390     for (int i = 0; i < digesta.length; i++) {
391         if (digesta[i] != digestb[i]) {
392         return false;
393         }
394     }
395     return true;
396     }
397
398     /**
399      * Resets the digest for further use.
400      */

401     public void reset() {
402     engineReset();
403     state = INITIAL;
404     }
405
406     /**
407      * Returns a string that identifies the algorithm, independent of
408      * implementation details. The name should be a standard
409      * Java Security name (such as "SHA", "MD5", and so on).
410      * See Appendix A in the <a HREF=
411      * "../../../guide/security/CryptoSpec.html#AppA">
412      * Java Cryptography Architecture API Specification &amp; Reference </a>
413      * for information about standard algorithm names.
414      *
415      * @return the name of the algorithm
416      */

417     public final String JavaDoc getAlgorithm() {
418     return this.algorithm;
419     }
420
421     /**
422      * Returns the length of the digest in bytes, or 0 if this operation is
423      * not supported by the provider and the implementation is not cloneable.
424      *
425      * @return the digest length in bytes, or 0 if this operation is not
426      * supported by the provider and the implementation is not cloneable.
427      *
428      * @since 1.2
429      */

430     public final int getDigestLength() {
431     int digestLen = engineGetDigestLength();
432     if (digestLen == 0) {
433         try {
434         MessageDigest JavaDoc md = (MessageDigest JavaDoc)clone();
435         byte[] digest = md.digest();
436         return digest.length;
437         } catch (CloneNotSupportedException JavaDoc e) {
438         return digestLen;
439         }
440     }
441     return digestLen;
442     }
443
444     /**
445      * Returns a clone if the implementation is cloneable.
446      *
447      * @return a clone if the implementation is cloneable.
448      *
449      * @exception CloneNotSupportedException if this is called on an
450      * implementation that does not support <code>Cloneable</code>.
451      */

452     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
453     if (this instanceof Cloneable JavaDoc) {
454         return super.clone();
455     } else {
456         throw new CloneNotSupportedException JavaDoc();
457     }
458     }
459
460
461
462
463     /*
464      * The following class allows providers to extend from MessageDigestSpi
465      * rather than from MessageDigest. It represents a MessageDigest with an
466      * encapsulated, provider-supplied SPI object (of type MessageDigestSpi).
467      * If the provider implementation is an instance of MessageDigestSpi,
468      * the getInstance() methods above return an instance of this class, with
469      * the SPI object encapsulated.
470      *
471      * Note: All SPI methods from the original MessageDigest class have been
472      * moved up the hierarchy into a new class (MessageDigestSpi), which has
473      * been interposed in the hierarchy between the API (MessageDigest)
474      * and its original parent (Object).
475      */

476
477     static class Delegate extends MessageDigest JavaDoc {
478
479     // The provider implementation (delegate)
480
private MessageDigestSpi JavaDoc digestSpi;
481
482     // constructor
483
public Delegate(MessageDigestSpi JavaDoc digestSpi, String JavaDoc algorithm) {
484         super(algorithm);
485         this.digestSpi = digestSpi;
486     }
487
488     /*
489      * Returns a clone if the delegate is cloneable.
490      *
491      * @return a clone if the delegate is cloneable.
492      *
493      * @exception CloneNotSupportedException if this is called on a
494      * delegate that does not support <code>Cloneable</code>.
495      */

496     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
497         if (digestSpi instanceof Cloneable JavaDoc) {
498         MessageDigestSpi JavaDoc digestSpiClone =
499             (MessageDigestSpi JavaDoc)digestSpi.clone();
500         // Because 'algorithm', 'provider', and 'state' are private
501
// members of our supertype, we must perform a cast to
502
// access them.
503
MessageDigest JavaDoc that =
504             new Delegate(digestSpiClone,
505                  ((MessageDigest JavaDoc)this).algorithm);
506         that.provider = ((MessageDigest JavaDoc)this).provider;
507         that.state = ((MessageDigest JavaDoc)this).state;
508         return that;
509         } else {
510         throw new CloneNotSupportedException JavaDoc();
511         }
512     }
513
514     protected int engineGetDigestLength() {
515         return digestSpi.engineGetDigestLength();
516     }
517
518     protected void engineUpdate(byte input) {
519         digestSpi.engineUpdate(input);
520     }
521
522     protected void engineUpdate(byte[] input, int offset, int len) {
523         digestSpi.engineUpdate(input, offset, len);
524     }
525
526     protected void engineUpdate(ByteBuffer JavaDoc input) {
527         digestSpi.engineUpdate(input);
528     }
529
530     protected byte[] engineDigest() {
531         return digestSpi.engineDigest();
532     }
533
534     protected int engineDigest(byte[] buf, int offset, int len)
535         throws DigestException JavaDoc {
536         return digestSpi.engineDigest(buf, offset, len);
537     }
538
539     protected void engineReset() {
540         digestSpi.engineReset();
541     }
542     }
543 }
544
Popular Tags