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    
018    package org.apache.commons.codec.digest;
019    
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.security.MessageDigest;
023    import java.security.NoSuchAlgorithmException;
024    
025    import org.apache.commons.codec.binary.Hex;
026    import 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     */
034    public 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    }