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