001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.codec.digest;
019
020import java.io.IOException;
021import java.io.InputStream;
022import java.security.MessageDigest;
023import java.security.NoSuchAlgorithmException;
024
025import org.apache.commons.codec.binary.Hex;
026import org.apache.commons.codec.binary.StringUtils;
027
028/**
029 * Operations to simplifiy common {@link java.security.MessageDigest} tasks. This class is thread safe.
030 * 
031 * @author Apache Software Foundation
032 * @version $Id: DigestUtils.java 801391 2009-08-05 19:55:54Z ggregory $
033 */
034public class DigestUtils {
035
036    private static final int STREAM_BUFFER_LENGTH = 1024;
037
038    /**
039     * Read through an InputStream and returns the digest for the data
040     * 
041     * @param digest
042     *            The MessageDigest to use (e.g. MD5)
043     * @param data
044     *            Data to digest
045     * @return MD5 digest
046     * @throws IOException
047     *             On error reading from the stream
048     */
049    private static byte[] digest(MessageDigest digest, InputStream data) throws IOException {
050        byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
051        int read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
052
053        while (read > -1) {
054            digest.update(buffer, 0, read);
055            read = data.read(buffer, 0, STREAM_BUFFER_LENGTH);
056        }
057
058        return digest.digest();
059    }
060
061    /**
062     * Calls {@link StringUtils#getBytesUtf8(String)}
063     * 
064     * @param string
065     *            the String to encode
066     * @return encoded bytes
067     */
068    private static byte[] getBytesUtf8(String data) {
069        return StringUtils.getBytesUtf8(data);
070    }
071
072    /**
073     * Returns a <code>MessageDigest</code> for the given <code>algorithm</code>.
074     * 
075     * @param algorithm
076     *            the name of the algorithm requested. See <a
077     *            href="http://java.sun.com/j2se/1.3/docs/guide/security/CryptoSpec.html#AppA">Appendix A in the Java
078     *            Cryptography Architecture API Specification & Reference</a> for information about standard algorithm
079     *            names.
080     * @return An MD5 digest instance.
081     * @see MessageDigest#getInstance(String)
082     * @throws RuntimeException
083     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
084     */
085    static MessageDigest getDigest(String algorithm) {
086        try {
087            return MessageDigest.getInstance(algorithm);
088        } catch (NoSuchAlgorithmException e) {
089            throw new RuntimeException(e.getMessage());
090        }
091    }
092
093    /**
094     * Returns an MD5 MessageDigest.
095     * 
096     * @return An MD5 digest instance.
097     * @throws RuntimeException
098     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
099     */
100    private static MessageDigest getMd5Digest() {
101        return getDigest("MD5");
102    }
103
104    /**
105     * Returns an SHA-256 digest.
106     * <p>
107     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
108     * </p>
109     * 
110     * @return An SHA-256 digest instance.
111     * @throws RuntimeException
112     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
113     */
114    private static MessageDigest getSha256Digest() {
115        return getDigest("SHA-256");
116    }
117
118    /**
119     * Returns an SHA-384 digest.
120     * <p>
121     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
122     * </p>
123     * 
124     * @return An SHA-384 digest instance.
125     * @throws RuntimeException
126     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
127     */
128    private static MessageDigest getSha384Digest() {
129        return getDigest("SHA-384");
130    }
131
132    /**
133     * Returns an SHA-512 digest.
134     * <p>
135     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
136     * </p>
137     * 
138     * @return An SHA-512 digest instance.
139     * @throws RuntimeException
140     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
141     */
142    private static MessageDigest getSha512Digest() {
143        return getDigest("SHA-512");
144    }
145
146    /**
147     * Returns an SHA-1 digest.
148     * 
149     * @return An SHA-1 digest instance.
150     * @throws RuntimeException
151     *             when a {@link java.security.NoSuchAlgorithmException} is caught.
152     */
153    private static MessageDigest getShaDigest() {
154        return getDigest("SHA");
155    }
156
157    /**
158     * Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
159     * 
160     * @param data
161     *            Data to digest
162     * @return MD5 digest
163     */
164    public static byte[] md5(byte[] data) {
165        return getMd5Digest().digest(data);
166    }
167
168    /**
169     * Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
170     * 
171     * @param data
172     *            Data to digest
173     * @return MD5 digest
174     * @throws IOException
175     *             On error reading from the stream
176     * @since 1.4
177     */
178    public static byte[] md5(InputStream data) throws IOException {
179        return digest(getMd5Digest(), data);
180    }
181
182    /**
183     * Calculates the MD5 digest and returns the value as a 16 element <code>byte[]</code>.
184     * 
185     * @param data
186     *            Data to digest
187     * @return MD5 digest
188     */
189    public static byte[] md5(String data) {
190        return md5(getBytesUtf8(data));
191    }
192
193    /**
194     * Calculates the MD5 digest and returns the value as a 32 character hex string.
195     * 
196     * @param data
197     *            Data to digest
198     * @return MD5 digest as a hex string
199     */
200    public static String md5Hex(byte[] data) {
201        return Hex.encodeHexString(md5(data));
202    }
203
204    /**
205     * Calculates the MD5 digest and returns the value as a 32 character hex string.
206     * 
207     * @param data
208     *            Data to digest
209     * @return MD5 digest as a hex string
210     * @throws IOException
211     *             On error reading from the stream
212     * @since 1.4
213     */
214    public static String md5Hex(InputStream data) throws IOException {
215        return Hex.encodeHexString(md5(data));
216    }
217
218    /**
219     * Calculates the MD5 digest and returns the value as a 32 character hex string.
220     * 
221     * @param data
222     *            Data to digest
223     * @return MD5 digest as a hex string
224     */
225    public static String md5Hex(String data) {
226        return Hex.encodeHexString(md5(data));
227    }
228
229    /**
230     * Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
231     * 
232     * @param data
233     *            Data to digest
234     * @return SHA-1 digest
235     */
236    public static byte[] sha(byte[] data) {
237        return getShaDigest().digest(data);
238    }
239
240    /**
241     * Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
242     * 
243     * @param data
244     *            Data to digest
245     * @return SHA-1 digest
246     * @throws IOException
247     *             On error reading from the stream
248     * @since 1.4
249     */
250    public static byte[] sha(InputStream data) throws IOException {
251        return digest(getShaDigest(), data);
252    }
253
254    /**
255     * Calculates the SHA-1 digest and returns the value as a <code>byte[]</code>.
256     * 
257     * @param data
258     *            Data to digest
259     * @return SHA-1 digest
260     */
261    public static byte[] sha(String data) {
262        return sha(getBytesUtf8(data));
263    }
264
265    /**
266     * Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
267     * <p>
268     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
269     * </p>
270     * 
271     * @param data
272     *            Data to digest
273     * @return SHA-256 digest
274     * @since 1.4
275     */
276    public static byte[] sha256(byte[] data) {
277        return getSha256Digest().digest(data);
278    }
279
280    /**
281     * Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
282     * <p>
283     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
284     * </p>
285     * 
286     * @param data
287     *            Data to digest
288     * @return SHA-256 digest
289     * @throws IOException
290     *             On error reading from the stream
291     * @since 1.4
292     */
293    public static byte[] sha256(InputStream data) throws IOException {
294        return digest(getSha256Digest(), data);
295    }
296
297    /**
298     * Calculates the SHA-256 digest and returns the value as a <code>byte[]</code>.
299     * <p>
300     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
301     * </p>
302     * 
303     * @param data
304     *            Data to digest
305     * @return SHA-256 digest
306     * @since 1.4
307     */
308    public static byte[] sha256(String data) {
309        return sha256(getBytesUtf8(data));
310    }
311
312    /**
313     * Calculates the SHA-256 digest and returns the value as a hex string.
314     * <p>
315     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
316     * </p>
317     * 
318     * @param data
319     *            Data to digest
320     * @return SHA-256 digest as a hex string
321     * @since 1.4
322     */
323    public static String sha256Hex(byte[] data) {
324        return Hex.encodeHexString(sha256(data));
325    }
326
327    /**
328     * Calculates the SHA-256 digest and returns the value as a hex string.
329     * <p>
330     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
331     * </p>
332     * 
333     * @param data
334     *            Data to digest
335     * @return SHA-256 digest as a hex string
336     * @throws IOException
337     *             On error reading from the stream
338     * @since 1.4
339     */
340    public static String sha256Hex(InputStream data) throws IOException {
341        return Hex.encodeHexString(sha256(data));
342    }
343
344    /**
345     * Calculates the SHA-256 digest and returns the value as a hex string.
346     * <p>
347     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
348     * </p>
349     * 
350     * @param data
351     *            Data to digest
352     * @return SHA-256 digest as a hex string
353     * @since 1.4
354     */
355    public static String sha256Hex(String data) {
356        return Hex.encodeHexString(sha256(data));
357    }
358
359    /**
360     * Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
361     * <p>
362     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
363     * </p>
364     * 
365     * @param data
366     *            Data to digest
367     * @return SHA-384 digest
368     * @since 1.4
369     */
370    public static byte[] sha384(byte[] data) {
371        return getSha384Digest().digest(data);
372    }
373
374    /**
375     * Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
376     * <p>
377     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
378     * </p>
379     * 
380     * @param data
381     *            Data to digest
382     * @return SHA-384 digest
383     * @throws IOException
384     *             On error reading from the stream
385     * @since 1.4
386     */
387    public static byte[] sha384(InputStream data) throws IOException {
388        return digest(getSha384Digest(), data);
389    }
390
391    /**
392     * Calculates the SHA-384 digest and returns the value as a <code>byte[]</code>.
393     * <p>
394     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
395     * </p>
396     * 
397     * @param data
398     *            Data to digest
399     * @return SHA-384 digest
400     * @since 1.4
401     */
402    public static byte[] sha384(String data) {
403        return sha384(getBytesUtf8(data));
404    }
405
406    /**
407     * Calculates the SHA-384 digest and returns the value as a hex string.
408     * <p>
409     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
410     * </p>
411     * 
412     * @param data
413     *            Data to digest
414     * @return SHA-384 digest as a hex string
415     * @since 1.4
416     */
417    public static String sha384Hex(byte[] data) {
418        return Hex.encodeHexString(sha384(data));
419    }
420
421    /**
422     * Calculates the SHA-384 digest and returns the value as a hex string.
423     * <p>
424     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
425     * </p>
426     * 
427     * @param data
428     *            Data to digest
429     * @return SHA-384 digest as a hex string
430     * @throws IOException
431     *             On error reading from the stream
432     * @since 1.4
433     */
434    public static String sha384Hex(InputStream data) throws IOException {
435        return Hex.encodeHexString(sha384(data));
436    }
437
438    /**
439     * Calculates the SHA-384 digest and returns the value as a hex string.
440     * <p>
441     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
442     * </p>
443     * 
444     * @param data
445     *            Data to digest
446     * @return SHA-384 digest as a hex string
447     * @since 1.4
448     */
449    public static String sha384Hex(String data) {
450        return Hex.encodeHexString(sha384(data));
451    }
452
453    /**
454     * Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
455     * <p>
456     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
457     * </p>
458     * 
459     * @param data
460     *            Data to digest
461     * @return SHA-512 digest
462     * @since 1.4
463     */
464    public static byte[] sha512(byte[] data) {
465        return getSha512Digest().digest(data);
466    }
467
468    /**
469     * Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
470     * <p>
471     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
472     * </p>
473     * 
474     * @param data
475     *            Data to digest
476     * @return SHA-512 digest
477     * @throws IOException
478     *             On error reading from the stream
479     * @since 1.4
480     */
481    public static byte[] sha512(InputStream data) throws IOException {
482        return digest(getSha512Digest(), data);
483    }
484
485    /**
486     * Calculates the SHA-512 digest and returns the value as a <code>byte[]</code>.
487     * <p>
488     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
489     * </p>
490     * 
491     * @param data
492     *            Data to digest
493     * @return SHA-512 digest
494     * @since 1.4
495     */
496    public static byte[] sha512(String data) {
497        return sha512(getBytesUtf8(data));
498    }
499
500    /**
501     * Calculates the SHA-512 digest and returns the value as a hex string.
502     * <p>
503     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
504     * </p>
505     * 
506     * @param data
507     *            Data to digest
508     * @return SHA-512 digest as a hex string
509     * @since 1.4
510     */
511    public static String sha512Hex(byte[] data) {
512        return Hex.encodeHexString(sha512(data));
513    }
514
515    /**
516     * Calculates the SHA-512 digest and returns the value as a hex string.
517     * <p>
518     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
519     * </p>
520     * 
521     * @param data
522     *            Data to digest
523     * @return SHA-512 digest as a hex string
524     * @throws IOException
525     *             On error reading from the stream
526     * @since 1.4
527     */
528    public static String sha512Hex(InputStream data) throws IOException {
529        return Hex.encodeHexString(sha512(data));
530    }
531
532    /**
533     * Calculates the SHA-512 digest and returns the value as a hex string.
534     * <p>
535     * Throws a <code>RuntimeException</code> on JRE versions prior to 1.4.0.
536     * </p>
537     * 
538     * @param data
539     *            Data to digest
540     * @return SHA-512 digest as a hex string
541     * @since 1.4
542     */
543    public static String sha512Hex(String data) {
544        return Hex.encodeHexString(sha512(data));
545    }
546
547    /**
548     * Calculates the SHA-1 digest and returns the value as a hex string.
549     * 
550     * @param data
551     *            Data to digest
552     * @return SHA-1 digest as a hex string
553     */
554    public static String shaHex(byte[] data) {
555        return Hex.encodeHexString(sha(data));
556    }
557
558    /**
559     * Calculates the SHA-1 digest and returns the value as a hex string.
560     * 
561     * @param data
562     *            Data to digest
563     * @return SHA-1 digest as a hex string
564     * @throws IOException
565     *             On error reading from the stream
566     * @since 1.4
567     */
568    public static String shaHex(InputStream data) throws IOException {
569        return Hex.encodeHexString(sha(data));
570    }
571
572    /**
573     * Calculates the SHA-1 digest and returns the value as a hex string.
574     * 
575     * @param data
576     *            Data to digest
577     * @return SHA-1 digest as a hex string
578     */
579    public static String shaHex(String data) {
580        return Hex.encodeHexString(sha(data));
581    }
582}