View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.digest;
19  
20  import java.io.BufferedInputStream;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.nio.ByteBuffer;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.security.InvalidKeyException;
28  import java.security.Key;
29  import java.security.NoSuchAlgorithmException;
30  
31  import javax.crypto.Mac;
32  import javax.crypto.spec.SecretKeySpec;
33  
34  import org.apache.commons.codec.binary.Hex;
35  import org.apache.commons.codec.binary.StringUtils;
36  
37  /**
38   * Simplifies common {@link Mac} tasks. This class is immutable and thread-safe. However the Mac may not be.
39   * <p>
40   * <strong>Note: Not all JCE implementations support all algorithms. If not supported, an IllegalArgumentException is thrown.</strong>
41   * </p>
42   * <p>
43   * Sample usage:
44   * </p>
45   *
46   * <pre>
47   * import static HmacAlgorithms.*;
48   * byte[] key = {1,2,3,4}; // don't use this actual key!
49   * String valueToDigest = "The quick brown fox jumps over the lazy dog";
50   * byte[] hmac = new HmacUtils(HMAC_SHA_224, key).hmac(valueToDigest);
51   * // Mac reuse
52   * HmacUtils hm1 = new HmacUtils("HmacAlgoName", key); // use a valid name here!
53   * String hexPom = hm1.hmacHex(new File("pom.xml"));
54   * String hexNot = hm1.hmacHex(new File("NOTICE.txt"));
55   * </pre>
56   *
57   * @since 1.10
58   */
59  public final class HmacUtils {
60  
61      private static final int STREAM_BUFFER_LENGTH = 1024;
62  
63      /**
64       * Returns an initialized {@link Mac} for the HmacMD5 algorithm.
65       * <p>
66       * Every implementation of the Java platform is required to support this standard Mac algorithm.
67       * </p>
68       *
69       * @param key The key for the keyed digest (must not be null).
70       * @return A Mac instance initialized with the given key.
71       * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
72       * @see Mac#getInstance(String)
73       * @see Mac#init(Key)
74       * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_MD5, byte[])}.
75       */
76      @Deprecated
77      public static Mac getHmacMd5(final byte[] key) {
78          return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
79      }
80  
81      /**
82       * Returns an initialized {@link Mac} for the HmacSHA1 algorithm.
83       * <p>
84       * Every implementation of the Java platform is required to support this standard Mac algorithm.
85       * </p>
86       *
87       * @param key The key for the keyed digest (must not be null).
88       * @return A Mac instance initialized with the given key.
89       * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
90       * @see Mac#getInstance(String)
91       * @see Mac#init(Key)
92       * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_1, byte[])}.
93       */
94      @Deprecated
95      public static Mac getHmacSha1(final byte[] key) {
96          return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
97      }
98  
99      /**
100      * Returns an initialized {@link Mac} for the HmacSHA256 algorithm.
101      * <p>
102      * Every implementation of the Java platform is required to support this standard Mac algorithm.
103      * </p>
104      *
105      * @param key The key for the keyed digest (must not be null).
106      * @return A Mac instance initialized with the given key.
107      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
108      * @see Mac#getInstance(String)
109      * @see Mac#init(Key)
110      * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_256, byte[])}.
111      */
112     @Deprecated
113     public static Mac getHmacSha256(final byte[] key) {
114         return getInitializedMac(HmacAlgorithms.HMAC_SHA_256, key);
115     }
116 
117     /**
118      * Returns an initialized {@link Mac} for the HmacSHA384 algorithm.
119      * <p>
120      * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
121      * </p>
122      *
123      * @param key The key for the keyed digest (must not be null).
124      * @return A Mac instance initialized with the given key.
125      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
126      * @see Mac#getInstance(String)
127      * @see Mac#init(Key)
128      * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_384, byte[])}.
129      */
130     @Deprecated
131     public static Mac getHmacSha384(final byte[] key) {
132         return getInitializedMac(HmacAlgorithms.HMAC_SHA_384, key);
133     }
134 
135     /**
136      * Returns an initialized {@link Mac} for the HmacSHA512 algorithm.
137      * <p>
138      * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
139      * </p>
140      *
141      * @param key The key for the keyed digest (must not be null).
142      * @return A Mac instance initialized with the given key.
143      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
144      * @see Mac#getInstance(String)
145      * @see Mac#init(Key)
146      * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_512, byte[])}.
147      */
148     @Deprecated
149     public static Mac getHmacSha512(final byte[] key) {
150         return getInitializedMac(HmacAlgorithms.HMAC_SHA_512, key);
151     }
152 
153     /**
154      * Returns an initialized {@link Mac} for the given {@code algorithm}.
155      *
156      * @param algorithm The name of the algorithm requested. See
157      *                  <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix A in the Java
158      *                  Cryptography Architecture Reference Guide</a> for information about standard algorithm names.
159      * @param key       The key for the keyed digest (must not be null).
160      * @return A Mac instance initialized with the given key.
161      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
162      * @see Mac#getInstance(String)
163      * @see Mac#init(Key)
164      */
165     public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] key) {
166         return getInitializedMac(algorithm.getName(), key);
167     }
168 
169     /**
170      * Returns an initialized {@link Mac} for the given {@code algorithm}.
171      *
172      * @param algorithm The name of the algorithm requested. See
173      *                  <a href= "https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix A in the Java
174      *                  Cryptography Architecture Reference Guide</a> for information about standard algorithm names.
175      * @param key       The key for the keyed digest (must not be null).
176      * @return A Mac instance initialized with the given key.
177      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
178      * @see Mac#getInstance(String)
179      * @see Mac#init(Key)
180      */
181     public static Mac getInitializedMac(final String algorithm, final byte[] key) {
182         if (key == null) {
183             throw new IllegalArgumentException("Null key");
184         }
185         try {
186             final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
187             final Mac mac = Mac.getInstance(algorithm);
188             mac.init(keySpec);
189             return mac;
190         } catch (final NoSuchAlgorithmException | InvalidKeyException e) {
191             throw new IllegalArgumentException(e);
192         }
193     }
194 
195     /**
196      * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
197      *
198      * @param key           The key for the keyed digest (must not be null).
199      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
200      * @return HmacMD5 MAC for the given key and value.
201      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
202      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(byte[])}.
203      */
204     @Deprecated
205     public static byte[] hmacMd5(final byte[] key, final byte[] valueToDigest) {
206         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
207     }
208 
209     /**
210      * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
211      *
212      * @param key           The key for the keyed digest (must not be null).
213      * @param valueToDigest The value (data) which should to digest.
214      *                      The InputStream must not be null and will not be closed.
215      * @return HmacMD5 MAC for the given key and value.
216      * @throws IOException              If an I/O error occurs.
217      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
218      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(InputStream)}.
219      */
220     @Deprecated
221     public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
222         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
223     }
224 
225     /**
226      * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
227      *
228      * @param key           The key for the keyed digest (must not be null).
229      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
230      * @return HmacMD5 MAC for the given key and value.
231      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
232      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmac(String)}.
233      */
234     @Deprecated
235     public static byte[] hmacMd5(final String key, final String valueToDigest) {
236         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
237     }
238 
239     /**
240      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
241      *
242      * @param key           The key for the keyed digest (must not be null).
243      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
244      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
245      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
246      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(byte[])}.
247      */
248     @Deprecated
249     public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
250         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
251     }
252 
253     /**
254      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
255      *
256      * @param key           The key for the keyed digest (must not be null).
257      * @param valueToDigest The value (data) which should to digest.
258      *                      The InputStream must not be null and will not be closed.
259      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
260      * @throws IOException              Thrown if an I/O error occurs.
261      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
262      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(InputStream)}.
263      */
264     @Deprecated
265     public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
266         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
267     }
268 
269     /**
270      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
271      *
272      * @param key           The key for the keyed digest (must not be null).
273      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
274      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
275      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
276      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmacHex(String)}.
277      */
278     @Deprecated
279     public static String hmacMd5Hex(final String key, final String valueToDigest) {
280         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
281     }
282 
283     /**
284      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
285      *
286      * @param key           The key for the keyed digest (must not be null).
287      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
288      * @return HmacSHA1 MAC for the given key and value.
289      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
290      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(byte[])}.
291      */
292     @Deprecated
293     public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
294         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
295     }
296 
297     /**
298      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
299      *
300      * @param key           The key for the keyed digest (must not be null).
301      * @param valueToDigest The value (data) which should to digest.
302      *                      The InputStream must not be null and will not be closed.
303      * @return HmacSHA1 MAC for the given key and value.
304      * @throws IOException              If an I/O error occurs.
305      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
306      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(InputStream)}.
307      */
308     @Deprecated
309     public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
310         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
311     }
312 
313     /**
314      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
315      *
316      * @param key           The key for the keyed digest (must not be null).
317      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
318      * @return HmacSHA1 MAC for the given key and value.
319      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
320      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmac(String)}.
321      */
322     @Deprecated
323     public static byte[] hmacSha1(final String key, final String valueToDigest) {
324         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
325     }
326 
327     /**
328      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
329      *
330      * @param key           The key for the keyed digest (must not be null).
331      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
332      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
333      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
334      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(byte[])}
335      */
336     @Deprecated
337     public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
338         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
339     }
340 
341     /**
342      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
343      *
344      * @param key           The key for the keyed digest (must not be null).
345      * @param valueToDigest The value (data) which should to digest.
346      *                      The InputStream must not be null and will not be closed.
347      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
348      * @throws IOException              If an I/O error occurs.
349      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
350      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(InputStream)}.
351      */
352     @Deprecated
353     public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
354         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
355     }
356 
357     /**
358      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
359      *
360      * @param key           The key for the keyed digest (must not be null).
361      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
362      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
363      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
364      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmacHex(String)}.
365      */
366     @Deprecated
367     public static String hmacSha1Hex(final String key, final String valueToDigest) {
368         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
369     }
370 
371     /**
372      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
373      *
374      * @param key           The key for the keyed digest (must not be null).
375      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
376      * @return HmacSHA256 MAC for the given key and value.
377      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
378      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(byte[])}.
379      */
380     @Deprecated
381     public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
382         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
383     }
384 
385     /**
386      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
387      *
388      * @param key           The key for the keyed digest (must not be null).
389      * @param valueToDigest The value (data) which should to digest. The InputStream must not be null and will not be closed.
390      * @return HmacSHA256 MAC for the given key and value.
391      * @throws IOException              If an I/O error occurs.
392      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
393      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(InputStream)}.
394      */
395     @Deprecated
396     public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
397         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
398     }
399 
400     /**
401      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
402      *
403      * @param key           The key for the keyed digest (must not be null).
404      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
405      * @return HmacSHA256 MAC for the given key and value.
406      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
407      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmac(String)}.
408      */
409     @Deprecated
410     public static byte[] hmacSha256(final String key, final String valueToDigest) {
411         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
412     }
413 
414     /**
415      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
416      *
417      * @param key           The key for the keyed digest (must not be null).
418      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
419      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
420      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
421      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(byte[])}.
422      */
423     @Deprecated
424     public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
425         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
426     }
427 
428     /**
429      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
430      *
431      * @param key           The key for the keyed digest (must not be null).
432      * @param valueToDigest The value (data) which should to digest.
433      *                      <p>
434      *                      The InputStream must not be null and will not be closed.
435      *                      </p>
436      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
437      * @throws IOException              If an I/O error occurs.
438      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
439      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}.
440      */
441     @Deprecated
442     public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
443         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
444     }
445 
446     /**
447      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
448      *
449      * @param key           The key for the keyed digest (must not be null).
450      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
451      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
452      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
453      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}.
454      */
455     @Deprecated
456     public static String hmacSha256Hex(final String key, final String valueToDigest) {
457         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
458     }
459 
460     /**
461      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
462      *
463      * @param key           The key for the keyed digest (must not be null).
464      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
465      * @return HmacSHA384 MAC for the given key and value.
466      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
467      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}.
468      */
469     @Deprecated
470     public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
471         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
472     }
473 
474     /**
475      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
476      *
477      * @param key           The key for the keyed digest (must not be null).
478      * @param valueToDigest The value (data) which should to digest.
479      *                      <p>
480      *                      The InputStream must not be null and will not be closed.
481      *                      </p>
482      * @return HmacSHA384 MAC for the given key and value.
483      * @throws IOException              If an I/O error occurs.
484      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
485      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}.
486      */
487     @Deprecated
488     public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
489         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
490     }
491 
492     /**
493      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
494      *
495      * @param key           The key for the keyed digest (must not be null).
496      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
497      * @return HmacSHA384 MAC for the given key and value.
498      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
499      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}.
500      */
501     @Deprecated
502     public static byte[] hmacSha384(final String key, final String valueToDigest) {
503         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
504     }
505     // hmacSha384
506 
507     /**
508      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
509      *
510      * @param key           The key for the keyed digest (must not be null).
511      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
512      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
513      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
514      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(byte[])}.
515      */
516     @Deprecated
517     public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
518         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
519     }
520 
521     /**
522      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
523      *
524      * @param key           The key for the keyed digest (must not be null).
525      * @param valueToDigest The value (data) which should to digest.
526      *                      <p>
527      *                      The InputStream must not be null and will not be closed.
528      *                      </p>
529      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
530      * @throws IOException              If an I/O error occurs.
531      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
532      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}.
533      */
534     @Deprecated
535     public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
536         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
537     }
538 
539     /**
540      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
541      *
542      * @param key           The key for the keyed digest (must not be null).
543      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
544      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
545      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
546      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}.
547      */
548     @Deprecated
549     public static String hmacSha384Hex(final String key, final String valueToDigest) {
550         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
551     }
552 
553     /**
554      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
555      *
556      * @param key           The key for the keyed digest (must not be null).
557      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
558      * @return HmacSHA512 MAC for the given key and value.
559      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
560      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}.
561      */
562     @Deprecated
563     public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
564         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
565     }
566 
567     /**
568      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
569      *
570      * @param key           The key for the keyed digest (must not be null).
571      * @param valueToDigest The value (data) which should to digest.
572      *                      <p>
573      *                      The InputStream must not be null and will not be closed.
574      *                      </p>
575      * @return HmacSHA512 MAC for the given key and value.
576      * @throws IOException              If an I/O error occurs.
577      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
578      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}.
579      */
580     @Deprecated
581     public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
582         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
583     }
584 
585     /**
586      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
587      *
588      * @param key           The key for the keyed digest (must not be null).
589      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
590      * @return HmacSHA512 MAC for the given key and value.
591      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
592      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}.
593      */
594     @Deprecated
595     public static byte[] hmacSha512(final String key, final String valueToDigest) {
596         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
597     }
598     // hmacSha512
599 
600     /**
601      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
602      *
603      * @param key           The key for the keyed digest (must not be null).
604      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
605      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
606      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
607      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}.
608      */
609     @Deprecated
610     public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
611         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
612     }
613 
614     /**
615      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
616      *
617      * @param key           The key for the keyed digest (must not be null).
618      * @param valueToDigest The value (data) which should to digest.
619      *                      <p>
620      *                      The InputStream must not be null and will not be closed.
621      *                      </p>
622      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
623      * @throws IOException              If an I/O error occurs.
624      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
625      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}.
626      */
627     @Deprecated
628     public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
629         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
630     }
631 
632     /**
633      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
634      *
635      * @param key           The key for the keyed digest (must not be null).
636      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
637      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
638      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
639      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}.
640      */
641     @Deprecated
642     public static String hmacSha512Hex(final String key, final String valueToDigest) {
643         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
644     }
645 
646     /**
647      * Tests whether this algorithm is available
648      *
649      * @param hmacAlgorithms The HmacAlgorithms to check.
650      * @return whether this algorithm is available.
651      * @since 1.11
652      */
653     public static boolean isAvailable(final HmacAlgorithms hmacAlgorithms) {
654         return isAvailable(hmacAlgorithms.getName());
655     }
656 
657     /**
658      * Tests whether this algorithm is available
659      *
660      * @param name The name to check.
661      * @return whether this algorithm is available.
662      * @since 1.11
663      */
664     public static boolean isAvailable(final String name) {
665         try {
666             Mac.getInstance(name);
667             return true;
668         } catch (final NoSuchAlgorithmException e) {
669             return false;
670         }
671     }
672 
673     /**
674      * Resets and then updates the given {@link Mac} with the value.
675      *
676      * @param mac           The initialized {@link Mac} to update.
677      * @param valueToDigest The value to update the {@link Mac} with (maybe null or empty).
678      * @return The updated {@link Mac}.
679      * @throws IllegalStateException if the Mac was not initialized.
680      */
681     public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
682         mac.reset();
683         mac.update(valueToDigest);
684         return mac;
685     }
686 
687     /**
688      * Resets and then updates the given {@link Mac} with the value.
689      *
690      * @param mac           The initialized {@link Mac} to update.
691      * @param valueToDigest The value to update the {@link Mac} with.
692      *                      <p>
693      *                      The InputStream must not be null and will not be closed.
694      *                      </p>
695      * @return The updated {@link Mac}.
696      * @throws IOException           If an I/O error occurs.
697      * @throws IllegalStateException If the Mac was not initialized.
698      */
699     public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
700         mac.reset();
701         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
702         int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
703         while (read > -1) {
704             mac.update(buffer, 0, read);
705             read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
706         }
707         return mac;
708     }
709 
710     /**
711      * Resets and then updates the given {@link Mac} with the value.
712      *
713      * @param mac           The initialized {@link Mac} to update.
714      * @param valueToDigest The value to update the {@link Mac} with (maybe null or empty).
715      * @return The updated {@link Mac}.
716      * @throws IllegalStateException if the Mac was not initialized.
717      */
718     public static Mac updateHmac(final Mac mac, final String valueToDigest) {
719         mac.reset();
720         mac.update(StringUtils.getBytesUtf8(valueToDigest));
721         return mac;
722     }
723 
724     private final Mac mac;
725 
726     /**
727      * Preserves binary compatibility only. As for previous versions does not provide useful behavior.
728      *
729      * @deprecated Since 1.11; only useful to preserve binary compatibility.
730      */
731     @Deprecated
732     public HmacUtils() {
733         this(null);
734     }
735 
736     /**
737      * Creates an instance using the provided algorithm type.
738      *
739      * @param algorithm to use.
740      * @param key       The key to use.
741      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
742      * @since 1.11
743      */
744     public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
745         this(algorithm.getName(), key);
746     }
747 
748     /**
749      * Creates an instance using the provided algorithm type.
750      *
751      * @param algorithm to use.
752      * @param key       The key to use.
753      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
754      * @since 1.11
755      */
756     public HmacUtils(final HmacAlgorithms algorithm, final String key) {
757         this(algorithm.getName(), StringUtils.getBytesUtf8(key));
758     }
759 
760     private HmacUtils(final Mac mac) {
761         this.mac = mac;
762     }
763 
764     /**
765      * Creates an instance using the provided algorithm type.
766      *
767      * @param algorithm to use.
768      * @param key       The key to use.
769      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
770      * @since 1.11
771      */
772     public HmacUtils(final String algorithm, final byte[] key) {
773         this(getInitializedMac(algorithm, key));
774     }
775 
776     /**
777      * Creates an instance using the provided algorithm type.
778      *
779      * @param algorithm to use.
780      * @param key       The key to use.
781      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
782      * @since 1.11
783      */
784     public HmacUtils(final String algorithm, final String key) {
785         this(algorithm, StringUtils.getBytesUtf8(key));
786     }
787 
788     /**
789      * Returns the digest for the input data.
790      *
791      * @param valueToDigest The input to use.
792      * @return The digest as a byte[].
793      * @since 1.11
794      */
795     public byte[] hmac(final byte[] valueToDigest) {
796         return mac.doFinal(valueToDigest);
797     }
798 
799     /**
800      * Returns the digest for the input data.
801      *
802      * @param valueToDigest The input to use.
803      * @return The digest as a byte[].
804      * @since 1.11
805      */
806     public byte[] hmac(final ByteBuffer valueToDigest) {
807         mac.update(valueToDigest);
808         return mac.doFinal();
809     }
810 
811     /**
812      * Returns the digest for the file.
813      *
814      * @param valueToDigest The file to use.
815      * @return The digest.
816      * @throws IOException If an I/O error occurs.
817      * @since 1.11
818      */
819     public byte[] hmac(final File valueToDigest) throws IOException {
820         return hmac(valueToDigest.toPath());
821     }
822 
823     /**
824      * Returns the digest for the stream.
825      *
826      * @param valueToDigest The data to use.
827      *                      <p>
828      *                      The InputStream must not be null and will not be closed.
829      *                      </p>
830      * @return The digest.
831      * @throws IOException If an I/O error occurs.
832      * @since 1.11
833      */
834     public byte[] hmac(final InputStream valueToDigest) throws IOException {
835         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
836         int read;
837         while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
838             mac.update(buffer, 0, read);
839         }
840         return mac.doFinal();
841     }
842 
843     /**
844      * Returns the digest for the file.
845      *
846      * @param valueToDigest The path to use.
847      * @return The digest.
848      * @throws IOException If an I/O error occurs.
849      * @since 1.19.0
850      */
851     public byte[] hmac(final Path valueToDigest) throws IOException {
852         try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(valueToDigest))) {
853             return hmac(stream);
854         }
855     }
856 
857     /**
858      * Returns the digest for the input data.
859      *
860      * @param valueToDigest The input to use, treated as UTF-8.
861      * @return The digest as a byte[].
862      * @since 1.11
863      */
864     public byte[] hmac(final String valueToDigest) {
865         return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
866     }
867 
868     /**
869      * Returns the digest for the input data.
870      *
871      * @param valueToDigest The input to use.
872      * @return The digest as a hexadecimal String.
873      * @since 1.11
874      */
875     public String hmacHex(final byte[] valueToDigest) {
876         return Hex.encodeHexString(hmac(valueToDigest));
877     }
878 
879     /**
880      * Returns the digest for the input data.
881      *
882      * @param valueToDigest The input to use.
883      * @return The digest as a hexadecimal String.
884      * @since 1.11
885      */
886     public String hmacHex(final ByteBuffer valueToDigest) {
887         return Hex.encodeHexString(hmac(valueToDigest));
888     }
889 
890     /**
891      * Returns the digest for the file.
892      *
893      * @param valueToDigest The file to use.
894      * @return The digest as a hexadecimal String.
895      * @throws IOException If an I/O error occurs.
896      * @since 1.11
897      */
898     public String hmacHex(final File valueToDigest) throws IOException {
899         return Hex.encodeHexString(hmac(valueToDigest));
900     }
901 
902     /**
903      * Returns the digest for the stream.
904      *
905      * @param valueToDigest The data to use.
906      *                      <p>
907      *                      The InputStream must not be null and will not be closed.
908      *                      </p>
909      * @return The digest as a hexadecimal String.
910      * @throws IOException If an I/O error occurs.
911      * @since 1.11
912      */
913     public String hmacHex(final InputStream valueToDigest) throws IOException {
914         return Hex.encodeHexString(hmac(valueToDigest));
915     }
916 
917     /**
918      * Returns the digest for the path.
919      *
920      * @param valueToDigest The path to use.
921      * @return The digest as a hexadecimal String.
922      * @throws IOException If an I/O error occurs.
923      * @since 1.19.0
924      */
925     public String hmacHex(final Path valueToDigest) throws IOException {
926         return Hex.encodeHexString(hmac(valueToDigest));
927     }
928 
929     /**
930      * Returns the digest for the input data.
931      *
932      * @param valueToDigest The input to use, treated as UTF-8.
933      * @return The digest as a hexadecimal String.
934      * @since 1.11
935      */
936     public String hmacHex(final String valueToDigest) {
937         return Hex.encodeHexString(hmac(valueToDigest));
938     }
939 }