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.BufferedInputStream;
021import java.io.File;
022import java.io.FileInputStream;
023import java.io.IOException;
024import java.io.InputStream;
025import java.nio.ByteBuffer;
026import java.security.InvalidKeyException;
027import java.security.Key;
028import java.security.NoSuchAlgorithmException;
029
030import javax.crypto.Mac;
031import javax.crypto.spec.SecretKeySpec;
032
033import org.apache.commons.codec.binary.Hex;
034import org.apache.commons.codec.binary.StringUtils;
035
036/**
037 * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable and thread-safe.
038 * However the Mac may not be.
039 * <p>
040 * <strong>Note: Not all JCE implementations support all algorithms. If not supported, an IllegalArgumentException is
041 * thrown.</strong>
042 * <p>
043 * Sample usage:
044 * <pre>
045 * import static HmacAlgorithms.*;
046 * byte[] key = {1,2,3,4}; // don't use this actual key!
047 * String valueToDigest = "The quick brown fox jumps over the lazy dog";
048 * byte[] hmac = new HmacUtils(HMAC_SHA_224, key).hmac(valueToDigest);
049 * // Mac re-use
050 * HmacUtils hm1 = new HmacUtils("HmacAlgoName", key); // use a valid name here!
051 * String hexPom = hm1.hmacHex(new File("pom.xml"));
052 * String hexNot = hm1.hmacHex(new File("NOTICE.txt"));
053 * </pre>
054 * @since 1.10
055 * @version $Id: HmacUtils.java 1811344 2017-10-06 15:19:57Z ggregory $
056 */
057public final class HmacUtils {
058
059    private static final int STREAM_BUFFER_LENGTH = 1024;
060
061    /**
062    * Returns whether this algorithm is available
063    *
064    *@param name the name to check
065    * @return whether this algorithm is available
066    * @since 1.11
067    */
068    public static boolean isAvailable(final String name) {
069        try {
070            Mac.getInstance(name);
071            return true;
072        } catch (final NoSuchAlgorithmException e) {
073            return false;
074        }
075    }
076
077    /**
078    * Returns whether this algorithm is available
079    *
080    *@param name the name to check
081    * @return whether this algorithm is available
082    * @since 1.11
083    */
084    public static boolean isAvailable(final HmacAlgorithms name) {
085        try {
086            Mac.getInstance(name.getName());
087            return true;
088        } catch (final NoSuchAlgorithmException e) {
089            return false;
090        }
091    }
092
093    /**
094     * Returns an initialized <code>Mac</code> for the HmacMD5 algorithm.
095     * <p>
096     * Every implementation of the Java platform is required to support this standard Mac algorithm.
097     * </p>
098     *
099     * @param key
100     *            They key for the keyed digest (must not be null)
101     * @return A Mac instance initialized with the given key.
102     * @see Mac#getInstance(String)
103     * @see Mac#init(Key)
104     * @throws IllegalArgumentException
105     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
106     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_MD5, byte[])}
107     */
108    @Deprecated
109    public static Mac getHmacMd5(final byte[] key) {
110        return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
111    }
112
113    /**
114     * Returns an initialized <code>Mac</code> for the HmacSHA1 algorithm.
115     * <p>
116     * Every implementation of the Java platform is required to support this standard Mac algorithm.
117     * </p>
118     *
119     * @param key
120     *            They key for the keyed digest (must not be null)
121     * @return A Mac instance initialized with the given key.
122     * @see Mac#getInstance(String)
123     * @see Mac#init(Key)
124     * @throws IllegalArgumentException
125     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
126     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_1, byte[])}
127     */
128    @Deprecated
129    public static Mac getHmacSha1(final byte[] key) {
130        return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
131    }
132
133    /**
134     * Returns an initialized <code>Mac</code> for the HmacSHA256 algorithm.
135     * <p>
136     * Every implementation of the Java platform is required to support this standard Mac algorithm.
137     * </p>
138     *
139     * @param key
140     *            They key for the keyed digest (must not be null)
141     * @return A Mac instance initialized with the given key.
142     * @see Mac#getInstance(String)
143     * @see Mac#init(Key)
144     * @throws IllegalArgumentException
145     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
146     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_256, byte[])}
147     */
148    @Deprecated
149    public static Mac getHmacSha256(final byte[] key) {
150        return getInitializedMac(HmacAlgorithms.HMAC_SHA_256, key);
151    }
152
153    /**
154     * Returns an initialized <code>Mac</code> for the HmacSHA384 algorithm.
155     * <p>
156     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
157     * </p>
158     *
159     * @param key
160     *            They key for the keyed digest (must not be null)
161     * @return A Mac instance initialized with the given key.
162     * @see Mac#getInstance(String)
163     * @see Mac#init(Key)
164     * @throws IllegalArgumentException
165     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
166     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_384, byte[])}
167     */
168    @Deprecated
169    public static Mac getHmacSha384(final byte[] key) {
170        return getInitializedMac(HmacAlgorithms.HMAC_SHA_384, key);
171    }
172
173    /**
174     * Returns an initialized <code>Mac</code> for the HmacSHA512 algorithm.
175     * <p>
176     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
177     * </p>
178     *
179     * @param key
180     *            They key for the keyed digest (must not be null)
181     * @return A Mac instance initialized with the given key.
182     * @see Mac#getInstance(String)
183     * @see Mac#init(Key)
184     * @throws IllegalArgumentException
185     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
186     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_512, byte[])}
187     */
188    @Deprecated
189    public static Mac getHmacSha512(final byte[] key) {
190        return getInitializedMac(HmacAlgorithms.HMAC_SHA_512, key);
191    }
192
193    /**
194     * Returns an initialized <code>Mac</code> for the given <code>algorithm</code>.
195     *
196     * @param algorithm
197     *            the name of the algorithm requested. See
198     *            <a href= "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"
199     *            >Appendix A in the Java Cryptography Architecture Reference Guide</a> for information about standard
200     *            algorithm names.
201     * @param key
202     *            They key for the keyed digest (must not be null)
203     * @return A Mac instance initialized with the given key.
204     * @see Mac#getInstance(String)
205     * @see Mac#init(Key)
206     * @throws IllegalArgumentException
207     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
208     */
209    public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] key) {
210        return getInitializedMac(algorithm.getName(), key);
211    }
212
213    /**
214     * Returns an initialized <code>Mac</code> for the given <code>algorithm</code>.
215     *
216     * @param algorithm
217     *            the name of the algorithm requested. See
218     *            <a href= "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"
219     *            >Appendix A in the Java Cryptography Architecture Reference Guide</a> for information about standard
220     *            algorithm names.
221     * @param key
222     *            They key for the keyed digest (must not be null)
223     * @return A Mac instance initialized with the given key.
224     * @see Mac#getInstance(String)
225     * @see Mac#init(Key)
226     * @throws IllegalArgumentException
227     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
228     */
229    public static Mac getInitializedMac(final String algorithm, final byte[] key) {
230
231        if (key == null) {
232            throw new IllegalArgumentException("Null key");
233        }
234
235        try {
236            final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
237            final Mac mac = Mac.getInstance(algorithm);
238            mac.init(keySpec);
239            return mac;
240        } catch (final NoSuchAlgorithmException e) {
241            throw new IllegalArgumentException(e);
242        } catch (final InvalidKeyException e) {
243            throw new IllegalArgumentException(e);
244        }
245    }
246
247    // hmacMd5
248
249    /**
250     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
251     *
252     * @param key
253     *            They key for the keyed digest (must not be null)
254     * @param valueToDigest
255     *            The value (data) which should to digest (maybe empty or null)
256     * @return HmacMD5 MAC for the given key and value
257     * @throws IllegalArgumentException
258     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
259     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(byte[])}
260     */
261    @Deprecated
262    public static byte[] hmacMd5(final byte[] key, final byte[] valueToDigest) {
263        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
264    }
265
266    /**
267     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
268     *
269     * @param key
270     *            They key for the keyed digest (must not be null)
271     * @param valueToDigest
272     *            The value (data) which should to digest
273     *            <p>
274     *            The InputStream must not be null and will not be closed
275     *            </p>
276     * @return HmacMD5 MAC for the given key and value
277     * @throws IOException
278     *             If an I/O error occurs.
279     * @throws IllegalArgumentException
280     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
281     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(InputStream)}
282     */
283    @Deprecated
284    public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
285        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
286    }
287
288    /**
289     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
290     *
291     * @param key
292     *            They key for the keyed digest (must not be null)
293     * @param valueToDigest
294     *            The value (data) which should to digest (maybe empty or null)
295     * @return HmacMD5 MAC for the given key and value
296     * @throws IllegalArgumentException
297     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
298     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmac(String)}
299     */
300    @Deprecated
301    public static byte[] hmacMd5(final String key, final String valueToDigest) {
302        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
303    }
304
305    /**
306     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
307     *
308     * @param key
309     *            They key for the keyed digest (must not be null)
310     * @param valueToDigest
311     *            The value (data) which should to digest (maybe empty or null)
312     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
313     * @throws IllegalArgumentException
314     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
315     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(byte[])}
316     */
317    @Deprecated
318    public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
319        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
320    }
321
322    /**
323     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
324     *
325     * @param key
326     *            They key for the keyed digest (must not be null)
327     * @param valueToDigest
328     *            The value (data) which should to digest
329     *            <p>
330     *            The InputStream must not be null and will not be closed
331     *            </p>
332     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
333     * @throws IOException
334     *             If an I/O error occurs.
335     * @throws IllegalArgumentException
336     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
337     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(InputStream)}
338     */
339    @Deprecated
340    public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
341        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
342    }
343
344    /**
345     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
346     *
347     * @param key
348     *            They key for the keyed digest (must not be null)
349     * @param valueToDigest
350     *            The value (data) which should to digest (maybe empty or null)
351     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
352     * @throws IllegalArgumentException
353     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
354     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmacHex(String)}
355     */
356    @Deprecated
357    public static String hmacMd5Hex(final String key, final String valueToDigest) {
358        return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
359    }
360
361    // hmacSha1
362
363    /**
364     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
365     *
366     * @param key
367     *            They key for the keyed digest (must not be null)
368     * @param valueToDigest
369     *            The value (data) which should to digest (maybe empty or null)
370     * @return HmacSHA1 MAC for the given key and value
371     * @throws IllegalArgumentException
372     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
373     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(byte[])}
374     */
375    @Deprecated
376    public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
377        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
378    }
379
380    /**
381     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
382     *
383     * @param key
384     *            They key for the keyed digest (must not be null)
385     * @param valueToDigest
386     *            The value (data) which should to digest
387     *            <p>
388     *            The InputStream must not be null and will not be closed
389     *            </p>
390     * @return HmacSHA1 MAC for the given key and value
391     * @throws IOException
392     *             If an I/O error occurs.
393     * @throws IllegalArgumentException
394     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
395     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(InputStream)}
396     */
397    @Deprecated
398    public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
399        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
400    }
401
402    /**
403     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
404     *
405     * @param key
406     *            They key for the keyed digest (must not be null)
407     * @param valueToDigest
408     *            The value (data) which should to digest (maybe empty or null)
409     * @return HmacSHA1 MAC for the given key and value
410     * @throws IllegalArgumentException
411     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
412     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmac(String)}
413     */
414    @Deprecated
415    public static byte[] hmacSha1(final String key, final String valueToDigest) {
416        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
417    }
418
419    /**
420     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
421     *
422     * @param key
423     *            They key for the keyed digest (must not be null)
424     * @param valueToDigest
425     *            The value (data) which should to digest (maybe empty or null)
426     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
427     * @throws IllegalArgumentException
428     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
429     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(byte[])}
430     */
431    @Deprecated
432    public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
433        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
434    }
435
436    /**
437     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
438     *
439     * @param key
440     *            They key for the keyed digest (must not be null)
441     * @param valueToDigest
442     *            The value (data) which should to digest
443     *            <p>
444     *            The InputStream must not be null and will not be closed
445     *            </p>
446     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
447     * @throws IOException
448     *             If an I/O error occurs.
449     * @throws IllegalArgumentException
450     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
451     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(InputStream)}
452     */
453    @Deprecated
454    public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
455        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
456    }
457
458    /**
459     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
460     *
461     * @param key
462     *            They key for the keyed digest (must not be null)
463     * @param valueToDigest
464     *            The value (data) which should to digest (maybe empty or null)
465     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
466     * @throws IllegalArgumentException
467     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
468     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmacHex(String)}
469     */
470    @Deprecated
471    public static String hmacSha1Hex(final String key, final String valueToDigest) {
472        return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
473    }
474
475    // hmacSha256
476
477    /**
478     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
479     *
480     * @param key
481     *            They key for the keyed digest (must not be null)
482     * @param valueToDigest
483     *            The value (data) which should to digest (maybe empty or null)
484     * @return HmacSHA256 MAC for the given key and value
485     * @throws IllegalArgumentException
486     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
487     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(byte[])}
488     */
489    @Deprecated
490    public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
491        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
492    }
493
494    /**
495     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
496     *
497     * @param key
498     *            They key for the keyed digest (must not be null)
499     * @param valueToDigest
500     *            The value (data) which should to digest
501     *            <p>
502     *            The InputStream must not be null and will not be closed
503     *            </p>
504     * @return HmacSHA256 MAC for the given key and value
505     * @throws IOException
506     *             If an I/O error occurs.
507     * @throws IllegalArgumentException
508     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
509     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(InputStream)}
510     */
511    @Deprecated
512    public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
513        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
514    }
515
516    /**
517     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
518     *
519     * @param key
520     *            They key for the keyed digest (must not be null)
521     * @param valueToDigest
522     *            The value (data) which should to digest (maybe empty or null)
523     * @return HmacSHA256 MAC for the given key and value
524     * @throws IllegalArgumentException
525     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
526     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmac(String)}
527     */
528    @Deprecated
529    public static byte[] hmacSha256(final String key, final String valueToDigest) {
530        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
531    }
532
533    /**
534     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
535     *
536     * @param key
537     *            They key for the keyed digest (must not be null)
538     * @param valueToDigest
539     *            The value (data) which should to digest (maybe empty or null)
540     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
541     * @throws IllegalArgumentException
542     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
543     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(byte[])}
544     */
545    @Deprecated
546    public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
547        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
548    }
549
550    /**
551     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
552     *
553     * @param key
554     *            They key for the keyed digest (must not be null)
555     * @param valueToDigest
556     *            The value (data) which should to digest
557     *            <p>
558     *            The InputStream must not be null and will not be closed
559     *            </p>
560     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
561     * @throws IOException
562     *             If an I/O error occurs.
563     * @throws IllegalArgumentException
564     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
565     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}
566     */
567    @Deprecated
568    public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
569        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
570    }
571
572    /**
573     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
574     *
575     * @param key
576     *            They key for the keyed digest (must not be null)
577     * @param valueToDigest
578     *            The value (data) which should to digest (maybe empty or null)
579     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
580     * @throws IllegalArgumentException
581     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
582     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}
583     */
584    @Deprecated
585    public static String hmacSha256Hex(final String key, final String valueToDigest) {
586        return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
587    }
588
589    // hmacSha384
590
591    /**
592     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
593     *
594     * @param key
595     *            They key for the keyed digest (must not be null)
596     * @param valueToDigest
597     *            The value (data) which should to digest (maybe empty or null)
598     * @return HmacSHA384 MAC for the given key and value
599     * @throws IllegalArgumentException
600     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
601     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}
602     */
603    @Deprecated
604    public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
605        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
606    }
607
608    /**
609     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
610     *
611     * @param key
612     *            They key for the keyed digest (must not be null)
613     * @param valueToDigest
614     *            The value (data) which should to digest
615     *            <p>
616     *            The InputStream must not be null and will not be closed
617     *            </p>
618     * @return HmacSHA384 MAC for the given key and value
619     * @throws IOException
620     *             If an I/O error occurs.
621     * @throws IllegalArgumentException
622     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
623     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}
624     */
625    @Deprecated
626    public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
627        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
628    }
629
630    /**
631     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
632     *
633     * @param key
634     *            They key for the keyed digest (must not be null)
635     * @param valueToDigest
636     *            The value (data) which should to digest (maybe empty or null)
637     * @return HmacSHA384 MAC for the given key and value
638     * @throws IllegalArgumentException
639     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
640     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}
641     */
642    @Deprecated
643    public static byte[] hmacSha384(final String key, final String valueToDigest) {
644        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
645    }
646
647    /**
648     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
649     *
650     * @param key
651     *            They key for the keyed digest (must not be null)
652     * @param valueToDigest
653     *            The value (data) which should to digest (maybe empty or null)
654     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
655     * @throws IllegalArgumentException
656     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
657     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(byte[])}
658     */
659    @Deprecated
660    public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
661        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
662    }
663
664    /**
665     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
666     *
667     * @param key
668     *            They key for the keyed digest (must not be null)
669     * @param valueToDigest
670     *            The value (data) which should to digest
671     *            <p>
672     *            The InputStream must not be null and will not be closed
673     *            </p>
674     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
675     * @throws IOException
676     *             If an I/O error occurs.
677     * @throws IllegalArgumentException
678     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
679     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}
680     */
681    @Deprecated
682    public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
683        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
684    }
685
686    /**
687     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
688     *
689     * @param key
690     *            They key for the keyed digest (must not be null)
691     * @param valueToDigest
692     *            The value (data) which should to digest (maybe empty or null)
693     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
694     * @throws IllegalArgumentException
695     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
696     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}
697     */
698    @Deprecated
699    public static String hmacSha384Hex(final String key, final String valueToDigest) {
700        return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
701    }
702
703    // hmacSha512
704
705    /**
706     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
707     *
708     * @param key
709     *            They key for the keyed digest (must not be null)
710     * @param valueToDigest
711     *            The value (data) which should to digest (maybe empty or null)
712     * @return HmacSHA512 MAC for the given key and value
713     * @throws IllegalArgumentException
714     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
715     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}
716     */
717    @Deprecated
718    public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
719        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
720    }
721
722    /**
723     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
724     *
725     * @param key
726     *            They key for the keyed digest (must not be null)
727     * @param valueToDigest
728     *            The value (data) which should to digest
729     *            <p>
730     *            The InputStream must not be null and will not be closed
731     *            </p>
732     * @return HmacSHA512 MAC for the given key and value
733     * @throws IOException
734     *             If an I/O error occurs.
735     * @throws IllegalArgumentException
736     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
737     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}
738     */
739    @Deprecated
740    public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
741        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
742    }
743
744    /**
745     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
746     *
747     * @param key
748     *            They key for the keyed digest (must not be null)
749     * @param valueToDigest
750     *            The value (data) which should to digest (maybe empty or null)
751     * @return HmacSHA512 MAC for the given key and value
752     * @throws IllegalArgumentException
753     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
754     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}
755     */
756    @Deprecated
757    public static byte[] hmacSha512(final String key, final String valueToDigest) {
758        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
759    }
760
761    /**
762     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
763     *
764     * @param key
765     *            They key for the keyed digest (must not be null)
766     * @param valueToDigest
767     *            The value (data) which should to digest (maybe empty or null)
768     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
769     * @throws IllegalArgumentException
770     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
771     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}
772     */
773    @Deprecated
774    public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
775        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
776    }
777
778    /**
779     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
780     *
781     * @param key
782     *            They key for the keyed digest (must not be null)
783     * @param valueToDigest
784     *            The value (data) which should to digest
785     *            <p>
786     *            The InputStream must not be null and will not be closed
787     *            </p>
788     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
789     * @throws IOException
790     *             If an I/O error occurs.
791     * @throws IllegalArgumentException
792     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
793     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}
794     */
795    @Deprecated
796    public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
797        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
798    }
799
800    /**
801     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
802     *
803     * @param key
804     *            They key for the keyed digest (must not be null)
805     * @param valueToDigest
806     *            The value (data) which should to digest (maybe empty or null)
807     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
808     * @throws IllegalArgumentException
809     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
810     * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}
811     */
812    @Deprecated
813    public static String hmacSha512Hex(final String key, final String valueToDigest) {
814        return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
815    }
816
817    // update
818
819    /**
820     * Resets and then updates the given {@link Mac} with the value.
821     *
822     * @param mac
823     *            the initialized {@link Mac} to update
824     * @param valueToDigest
825     *            the value to update the {@link Mac} with (maybe null or empty)
826     * @return the updated {@link Mac}
827     * @throws IllegalStateException
828     *             if the Mac was not initialized
829     */
830    public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
831        mac.reset();
832        mac.update(valueToDigest);
833        return mac;
834    }
835
836    /**
837     * Resets and then updates the given {@link Mac} with the value.
838     *
839     * @param mac
840     *            the initialized {@link Mac} to update
841     * @param valueToDigest
842     *            the value to update the {@link Mac} with
843     *            <p>
844     *            The InputStream must not be null and will not be closed
845     *            </p>
846     * @return the updated {@link Mac}
847     * @throws IOException
848     *             If an I/O error occurs.
849     * @throws IllegalStateException
850     *             If the Mac was not initialized
851     */
852    public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
853        mac.reset();
854        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
855        int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
856
857        while (read > -1) {
858            mac.update(buffer, 0, read);
859            read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
860        }
861
862        return mac;
863    }
864
865    /**
866     * Resets and then updates the given {@link Mac} with the value.
867     *
868     * @param mac
869     *            the initialized {@link Mac} to update
870     * @param valueToDigest
871     *            the value to update the {@link Mac} with (maybe null or empty)
872     * @return the updated {@link Mac}
873     * @throws IllegalStateException
874     *             if the Mac was not initialized
875     */
876    public static Mac updateHmac(final Mac mac, final String valueToDigest) {
877        mac.reset();
878        mac.update(StringUtils.getBytesUtf8(valueToDigest));
879        return mac;
880    }
881
882    /**
883     * Preserves binary compatibity only.
884     * As for previous versions does not provide useful behaviour
885     * @deprecated since 1.11; only useful to preserve binary compatibility
886     */
887    @Deprecated
888    public HmacUtils() {
889        this(null);
890    }
891
892    private final Mac mac;
893
894    private HmacUtils(final Mac mac) {
895        this.mac = mac;
896    }
897
898    /**
899     * Creates an instance using the provided algorithm type.
900     *
901     * @param algorithm to use
902     * @param  key the key to use
903     * @throws IllegalArgumentException
904     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
905     * @since 1.11
906     */
907    public HmacUtils(final String algorithm, final byte[] key) {
908        this(getInitializedMac(algorithm, key));
909    }
910
911    /**
912     * Creates an instance using the provided algorithm type.
913     *
914     * @param algorithm to use
915     * @param  key the key to use
916     * @throws IllegalArgumentException
917     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
918     * @since 1.11
919     */
920    public HmacUtils(final String algorithm, final String key) {
921        this(algorithm, StringUtils.getBytesUtf8(key));
922    }
923
924    /**
925     * Creates an instance using the provided algorithm type.
926     *
927     * @param algorithm to use
928     * @param  key the key to use
929     * @throws IllegalArgumentException
930     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
931     * @since 1.11
932     */
933    public HmacUtils(final HmacAlgorithms algorithm, final String key) {
934        this(algorithm.getName(), StringUtils.getBytesUtf8(key));
935    }
936
937    /**
938     * Creates an instance using the provided algorithm type.
939     *
940     * @param algorithm to use.
941     * @param key the key to use
942     * @throws IllegalArgumentException
943     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
944     * @since 1.11
945     */
946    public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
947        this(algorithm.getName(), key);
948    }
949
950    /**
951     * Returns the digest for the input data.
952     *
953     * @param valueToDigest the input to use
954     * @return the digest as a byte[]
955     * @since 1.11
956     */
957    public byte[] hmac(final byte[] valueToDigest) {
958        return mac.doFinal(valueToDigest);
959    }
960
961    /**
962     * Returns the digest for the input data.
963     *
964     * @param valueToDigest the input to use
965     * @return the digest as a hex String
966     * @since 1.11
967     */
968    public String hmacHex(final byte[] valueToDigest) {
969        return Hex.encodeHexString(hmac(valueToDigest));
970    }
971
972    /**
973     * Returns the digest for the input data.
974     *
975     * @param valueToDigest the input to use, treated as UTF-8
976     * @return the digest as a byte[]
977     * @since 1.11
978     */
979    public byte[] hmac(final String valueToDigest) {
980        return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
981    }
982
983    /**
984     * Returns the digest for the input data.
985     *
986     * @param valueToDigest the input to use, treated as UTF-8
987     * @return the digest as a hex String
988     * @since 1.11
989     */
990    public String hmacHex(final String valueToDigest) {
991        return Hex.encodeHexString(hmac(valueToDigest));
992    }
993
994    /**
995     * Returns the digest for the input data.
996     *
997     * @param valueToDigest the input to use
998     * @return the digest as a byte[]
999     * @since 1.11
1000     */
1001    public byte[] hmac(final ByteBuffer valueToDigest) {
1002        mac.update(valueToDigest);
1003        return mac.doFinal();
1004    }
1005
1006    /**
1007     * Returns the digest for the input data.
1008     *
1009     * @param valueToDigest the input to use
1010     * @return the digest as a hex String
1011     * @since 1.11
1012     */
1013    public String hmacHex(final ByteBuffer valueToDigest) {
1014        return Hex.encodeHexString(hmac(valueToDigest));
1015    }
1016
1017    /**
1018     * Returns the digest for the stream.
1019     *
1020     * @param valueToDigest
1021     *            the data to use
1022     *            <p>
1023     *            The InputStream must not be null and will not be closed
1024     *            </p>
1025     * @return the digest
1026     * @throws IOException
1027     *             If an I/O error occurs.
1028     * @since 1.11
1029     */
1030    public byte[] hmac(final InputStream valueToDigest) throws IOException {
1031        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
1032        int read;
1033
1034        while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH) ) > -1) {
1035            mac.update(buffer, 0, read);
1036        }
1037        return mac.doFinal();
1038    }
1039
1040    /**
1041     * Returns the digest for the stream.
1042     *
1043     * @param valueToDigest
1044     *            the data to use
1045     *            <p>
1046     *            The InputStream must not be null and will not be closed
1047     *            </p>
1048     * @return the digest as a hex String
1049     * @throws IOException
1050     *             If an I/O error occurs.
1051     * @since 1.11
1052     */
1053    public String hmacHex(final InputStream valueToDigest) throws IOException {
1054        return Hex.encodeHexString(hmac(valueToDigest));
1055    }
1056
1057    /**
1058     * Returns the digest for the file.
1059     *
1060     * @param valueToDigest the file to use
1061     * @return the digest
1062     * @throws IOException
1063     *             If an I/O error occurs.
1064     * @since 1.11
1065     */
1066    public byte[] hmac(final File valueToDigest) throws IOException {
1067        final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(valueToDigest));
1068        try {
1069            return hmac(stream);
1070        } finally {
1071            stream.close();
1072        }
1073    }
1074
1075    /**
1076     * Returns the digest for the file.
1077     *
1078     * @param valueToDigest the file to use
1079     * @return the digest as a hex String
1080     * @throws IOException
1081     *             If an I/O error occurs.
1082     * @since 1.11
1083     */
1084    public String hmacHex(final File valueToDigest) throws IOException {
1085        return Hex.encodeHexString(hmac(valueToDigest));
1086    }
1087
1088}