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 javax.crypto.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 re-use
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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 {@code 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 when 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 when 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      *                      <p>
215      *                      The InputStream must not be null and will not be closed.
216      *                      </p>
217      * @return HmacMD5 MAC for the given key and value.
218      * @throws IOException              If an I/O error occurs.
219      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
220      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmac(InputStream)}.
221      */
222     @Deprecated
223     public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
224         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
225     }
226 
227     /**
228      * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
229      *
230      * @param key           The key for the keyed digest (must not be null).
231      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
232      * @return HmacMD5 MAC for the given key and value.
233      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
234      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, String).hmac(String)}.
235      */
236     @Deprecated
237     public static byte[] hmacMd5(final String key, final String valueToDigest) {
238         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmac(valueToDigest);
239     }
240 
241     /**
242      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
243      *
244      * @param key           The key for the keyed digest (must not be null).
245      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
246      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
247      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
248      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(byte[])}.
249      */
250     @Deprecated
251     public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
252         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
253     }
254 
255     /**
256      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
257      *
258      * @param key           The key for the keyed digest (must not be null).
259      * @param valueToDigest The value (data) which should to digest
260      *                      <p>
261      *                      The InputStream must not be null and will not be closed.
262      *                      </p>
263      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
264      * @throws IOException              If an I/O error occurs.
265      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
266      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_MD5, byte[]).hmacHex(InputStream)}.
267      */
268     @Deprecated
269     public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
270         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
271     }
272 
273     /**
274      * Returns a HmacMD5 Message Authentication Code (MAC) as a hexadecimal string (lowercase) for the given key and value.
275      *
276      * @param key           The key for the keyed digest (must not be null).
277      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
278      * @return HmacMD5 MAC for the given key and value as a hexadecimal string (lowercase).
279      * @throws IllegalArgumentException 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, String).hmacHex(String)}.
281      */
282     @Deprecated
283     public static String hmacMd5Hex(final String key, final String valueToDigest) {
284         return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
285     }
286 
287     /**
288      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
289      *
290      * @param key           The key for the keyed digest (must not be null).
291      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
292      * @return HmacSHA1 MAC for the given key and value.
293      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
294      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(byte[])}.
295      */
296     @Deprecated
297     public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
298         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
299     }
300 
301     /**
302      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
303      *
304      * @param key           The key for the keyed digest (must not be null).
305      * @param valueToDigest The value (data) which should to digest
306      *                      <p>
307      *                      The InputStream must not be null and will not be closed.
308      *                      </p>
309      * @return HmacSHA1 MAC for the given key and value.
310      * @throws IOException              If an I/O error occurs.
311      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
312      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmac(InputStream)}.
313      */
314     @Deprecated
315     public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
316         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
317     }
318 
319     /**
320      * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
321      *
322      * @param key           The key for the keyed digest (must not be null).
323      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
324      * @return HmacSHA1 MAC for the given key and value.
325      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
326      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, String).hmac(String)}.
327      */
328     @Deprecated
329     public static byte[] hmacSha1(final String key, final String valueToDigest) {
330         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
331     }
332 
333     /**
334      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
335      *
336      * @param key           The key for the keyed digest (must not be null).
337      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
338      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
339      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
340      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(byte[])}
341      */
342     @Deprecated
343     public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
344         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
345     }
346 
347     /**
348      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
349      *
350      * @param key           The key for the keyed digest (must not be null).
351      * @param valueToDigest The value (data) which should to digest.
352      *                      <p>
353      *                      The InputStream must not be null and will not be closed.
354      *                      </p>
355      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
356      * @throws IOException              If an I/O error occurs.
357      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
358      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_1, byte[]).hmacHex(InputStream)}.
359      */
360     @Deprecated
361     public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
362         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
363     }
364 
365     /**
366      * Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
367      *
368      * @param key           The key for the keyed digest (must not be null).
369      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
370      * @return HmacSHA1 MAC for the given key and value as hexadecimal string (lowercase).
371      * @throws IllegalArgumentException 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, String).hmacHex(String)}.
373      */
374     @Deprecated
375     public static String hmacSha1Hex(final String key, final String valueToDigest) {
376         return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmacHex(valueToDigest);
377     }
378 
379     /**
380      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
381      *
382      * @param key           The key for the keyed digest (must not be null).
383      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
384      * @return HmacSHA256 MAC for the given key and value.
385      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
386      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(byte[])}.
387      */
388     @Deprecated
389     public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
390         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
391     }
392 
393     /**
394      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
395      *
396      * @param key           The key for the keyed digest (must not be null).
397      * @param valueToDigest The value (data) which should to digest.
398      *                      <p>
399      *                      The InputStream must not be null and will not be closed.
400      *                      </p>
401      * @return HmacSHA256 MAC for the given key and value.
402      * @throws IOException              If an I/O error occurs.
403      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
404      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmac(InputStream)}.
405      */
406     @Deprecated
407     public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
408         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
409     }
410 
411     /**
412      * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
413      *
414      * @param key           The key for the keyed digest (must not be null).
415      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
416      * @return HmacSHA256 MAC for the given key and value.
417      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
418      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmac(String)}.
419      */
420     @Deprecated
421     public static byte[] hmacSha256(final String key, final String valueToDigest) {
422         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmac(valueToDigest);
423     }
424 
425     /**
426      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
427      *
428      * @param key           The key for the keyed digest (must not be null).
429      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
430      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
431      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
432      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(byte[])}.
433      */
434     @Deprecated
435     public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
436         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
437     }
438 
439     /**
440      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
441      *
442      * @param key           The key for the keyed digest (must not be null).
443      * @param valueToDigest The value (data) which should to digest.
444      *                      <p>
445      *                      The InputStream must not be null and will not be closed.
446      *                      </p>
447      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
448      * @throws IOException              If an I/O error occurs.
449      * @throws IllegalArgumentException 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_256, byte[]).hmacHex(InputStream)}.
451      */
452     @Deprecated
453     public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
454         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
455     }
456 
457     /**
458      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
459      *
460      * @param key           The key for the keyed digest (must not be null).
461      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
462      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
463      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
464      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}.
465      */
466     @Deprecated
467     public static String hmacSha256Hex(final String key, final String valueToDigest) {
468         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
469     }
470 
471     /**
472      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
473      *
474      * @param key           The key for the keyed digest (must not be null).
475      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
476      * @return HmacSHA384 MAC for the given key and value.
477      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
478      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}.
479      */
480     @Deprecated
481     public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
482         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
483     }
484 
485     /**
486      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
487      *
488      * @param key           The key for the keyed digest (must not be null).
489      * @param valueToDigest The value (data) which should to digest.
490      *                      <p>
491      *                      The InputStream must not be null and will not be closed.
492      *                      </p>
493      * @return HmacSHA384 MAC for the given key and value.
494      * @throws IOException              If an I/O error occurs.
495      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
496      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}.
497      */
498     @Deprecated
499     public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
500         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
501     }
502 
503     /**
504      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
505      *
506      * @param key           The key for the keyed digest (must not be null).
507      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
508      * @return HmacSHA384 MAC for the given key and value.
509      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
510      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}.
511      */
512     @Deprecated
513     public static byte[] hmacSha384(final String key, final String valueToDigest) {
514         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
515     }
516     // hmacSha384
517 
518     /**
519      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
520      *
521      * @param key           The key for the keyed digest (must not be null).
522      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
523      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
524      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
525      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(byte[])}.
526      */
527     @Deprecated
528     public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
529         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
530     }
531 
532     /**
533      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
534      *
535      * @param key           The key for the keyed digest (must not be null).
536      * @param valueToDigest The value (data) which should to digest.
537      *                      <p>
538      *                      The InputStream must not be null and will not be closed.
539      *                      </p>
540      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
541      * @throws IOException              If an I/O error occurs.
542      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
543      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}.
544      */
545     @Deprecated
546     public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
547         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
548     }
549 
550     /**
551      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
552      *
553      * @param key           The key for the keyed digest (must not be null).
554      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
555      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
556      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
557      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}.
558      */
559     @Deprecated
560     public static String hmacSha384Hex(final String key, final String valueToDigest) {
561         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
562     }
563 
564     /**
565      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
566      *
567      * @param key           The key for the keyed digest (must not be null).
568      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
569      * @return HmacSHA512 MAC for the given key and value.
570      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
571      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}.
572      */
573     @Deprecated
574     public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
575         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
576     }
577 
578     /**
579      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
580      *
581      * @param key           The key for the keyed digest (must not be null).
582      * @param valueToDigest The value (data) which should to digest.
583      *                      <p>
584      *                      The InputStream must not be null and will not be closed.
585      *                      </p>
586      * @return HmacSHA512 MAC for the given key and value.
587      * @throws IOException              If an I/O error occurs.
588      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
589      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}.
590      */
591     @Deprecated
592     public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
593         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
594     }
595 
596     /**
597      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
598      *
599      * @param key           The key for the keyed digest (must not be null).
600      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
601      * @return HmacSHA512 MAC for the given key and value.
602      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
603      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}.
604      */
605     @Deprecated
606     public static byte[] hmacSha512(final String key, final String valueToDigest) {
607         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
608     }
609     // hmacSha512
610 
611     /**
612      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
613      *
614      * @param key           The key for the keyed digest (must not be null).
615      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
616      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
617      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
618      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}.
619      */
620     @Deprecated
621     public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
622         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
623     }
624 
625     /**
626      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
627      *
628      * @param key           The key for the keyed digest (must not be null).
629      * @param valueToDigest The value (data) which should to digest.
630      *                      <p>
631      *                      The InputStream must not be null and will not be closed.
632      *                      </p>
633      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
634      * @throws IOException              If an I/O error occurs.
635      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
636      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}.
637      */
638     @Deprecated
639     public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
640         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
641     }
642 
643     /**
644      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
645      *
646      * @param key           The key for the keyed digest (must not be null).
647      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
648      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
649      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
650      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}.
651      */
652     @Deprecated
653     public static String hmacSha512Hex(final String key, final String valueToDigest) {
654         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
655     }
656 
657     /**
658      * Tests whether this algorithm is available
659      *
660      * @param hmacAlgorithms the HmacAlgorithms to check.
661      * @return whether this algorithm is available.
662      * @since 1.11
663      */
664     public static boolean isAvailable(final HmacAlgorithms hmacAlgorithms) {
665         return isAvailable(hmacAlgorithms.getName());
666     }
667 
668     /**
669      * Tests whether this algorithm is available
670      *
671      * @param name the name to check.
672      * @return whether this algorithm is available.
673      * @since 1.11
674      */
675     public static boolean isAvailable(final String name) {
676         try {
677             Mac.getInstance(name);
678             return true;
679         } catch (final NoSuchAlgorithmException e) {
680             return false;
681         }
682     }
683 
684     /**
685      * Resets and then updates the given {@link Mac} with the value.
686      *
687      * @param mac           the initialized {@link Mac} to update.
688      * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty).
689      * @return the updated {@link Mac}.
690      * @throws IllegalStateException if the Mac was not initialized.
691      */
692     public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
693         mac.reset();
694         mac.update(valueToDigest);
695         return mac;
696     }
697 
698     /**
699      * Resets and then updates the given {@link Mac} with the value.
700      *
701      * @param mac           the initialized {@link Mac} to update.
702      * @param valueToDigest the value to update the {@link Mac} with.
703      *                      <p>
704      *                      The InputStream must not be null and will not be closed.
705      *                      </p>
706      * @return the updated {@link Mac}.
707      * @throws IOException           If an I/O error occurs.
708      * @throws IllegalStateException If the Mac was not initialized.
709      */
710     public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
711         mac.reset();
712         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
713         int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
714         while (read > -1) {
715             mac.update(buffer, 0, read);
716             read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
717         }
718         return mac;
719     }
720 
721     /**
722      * Resets and then updates the given {@link Mac} with the value.
723      *
724      * @param mac           the initialized {@link Mac} to update.
725      * @param valueToDigest the value to update the {@link Mac} with (maybe null or empty).
726      * @return the updated {@link Mac}.
727      * @throws IllegalStateException if the Mac was not initialized.
728      */
729     public static Mac updateHmac(final Mac mac, final String valueToDigest) {
730         mac.reset();
731         mac.update(StringUtils.getBytesUtf8(valueToDigest));
732         return mac;
733     }
734 
735     private final Mac mac;
736 
737     /**
738      * Preserves binary compatibility only. As for previous versions does not provide useful behavior.
739      *
740      * @deprecated Since 1.11; only useful to preserve binary compatibility.
741      */
742     @Deprecated
743     public HmacUtils() {
744         this(null);
745     }
746 
747     /**
748      * Creates an instance using the provided algorithm type.
749      *
750      * @param algorithm to use.
751      * @param key       the key to use.
752      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
753      * @since 1.11
754      */
755     public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
756         this(algorithm.getName(), key);
757     }
758 
759     /**
760      * Creates an instance using the provided algorithm type.
761      *
762      * @param algorithm to use.
763      * @param key       the key to use.
764      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
765      * @since 1.11
766      */
767     public HmacUtils(final HmacAlgorithms algorithm, final String key) {
768         this(algorithm.getName(), StringUtils.getBytesUtf8(key));
769     }
770 
771     private HmacUtils(final Mac mac) {
772         this.mac = mac;
773     }
774 
775     /**
776      * Creates an instance using the provided algorithm type.
777      *
778      * @param algorithm to use.
779      * @param key       the key to use.
780      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
781      * @since 1.11
782      */
783     public HmacUtils(final String algorithm, final byte[] key) {
784         this(getInitializedMac(algorithm, key));
785     }
786 
787     /**
788      * Creates an instance using the provided algorithm type.
789      *
790      * @param algorithm to use.
791      * @param key       the key to use.
792      * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
793      * @since 1.11
794      */
795     public HmacUtils(final String algorithm, final String key) {
796         this(algorithm, StringUtils.getBytesUtf8(key));
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 byte[] valueToDigest) {
807         return mac.doFinal(valueToDigest);
808     }
809 
810     /**
811      * Returns the digest for the input data.
812      *
813      * @param valueToDigest the input to use.
814      * @return the digest as a byte[].
815      * @since 1.11
816      */
817     public byte[] hmac(final ByteBuffer valueToDigest) {
818         mac.update(valueToDigest);
819         return mac.doFinal();
820     }
821 
822     /**
823      * Returns the digest for the file.
824      *
825      * @param valueToDigest the file to use.
826      * @return the digest.
827      * @throws IOException If an I/O error occurs.
828      * @since 1.11
829      */
830     public byte[] hmac(final File valueToDigest) throws IOException {
831         return hmac(valueToDigest.toPath());
832     }
833 
834     /**
835      * Returns the digest for the stream.
836      *
837      * @param valueToDigest the data to use.
838      *                      <p>
839      *                      The InputStream must not be null and will not be closed.
840      *                      </p>
841      * @return the digest.
842      * @throws IOException If an I/O error occurs.
843      * @since 1.11
844      */
845     public byte[] hmac(final InputStream valueToDigest) throws IOException {
846         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
847         int read;
848         while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
849             mac.update(buffer, 0, read);
850         }
851         return mac.doFinal();
852     }
853 
854     /**
855      * Returns the digest for the file.
856      *
857      * @param valueToDigest the path to use.
858      * @return the digest.
859      * @throws IOException If an I/O error occurs.
860      * @since 1.19.0
861      */
862     public byte[] hmac(final Path valueToDigest) throws IOException {
863         try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(valueToDigest))) {
864             return hmac(stream);
865         }
866     }
867 
868     /**
869      * Returns the digest for the input data.
870      *
871      * @param valueToDigest the input to use, treated as UTF-8.
872      * @return the digest as a byte[].
873      * @since 1.11
874      */
875     public byte[] hmac(final String valueToDigest) {
876         return mac.doFinal(StringUtils.getBytesUtf8(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 byte[] valueToDigest) {
887         return Hex.encodeHexString(hmac(valueToDigest));
888     }
889 
890     /**
891      * Returns the digest for the input data.
892      *
893      * @param valueToDigest the input to use.
894      * @return the digest as a hexadecimal String.
895      * @since 1.11
896      */
897     public String hmacHex(final ByteBuffer valueToDigest) {
898         return Hex.encodeHexString(hmac(valueToDigest));
899     }
900 
901     /**
902      * Returns the digest for the file.
903      *
904      * @param valueToDigest the file to use.
905      * @return the digest as a hexadecimal String.
906      * @throws IOException If an I/O error occurs.
907      * @since 1.11
908      */
909     public String hmacHex(final File valueToDigest) throws IOException {
910         return Hex.encodeHexString(hmac(valueToDigest));
911     }
912 
913     /**
914      * Returns the digest for the stream.
915      *
916      * @param valueToDigest the data to use.
917      *                      <p>
918      *                      The InputStream must not be null and will not be closed.
919      *                      </p>
920      * @return the digest as a hexadecimal String.
921      * @throws IOException If an I/O error occurs.
922      * @since 1.11
923      */
924     public String hmacHex(final InputStream valueToDigest) throws IOException {
925         return Hex.encodeHexString(hmac(valueToDigest));
926     }
927 
928     /**
929      * Returns the digest for the path.
930      *
931      * @param valueToDigest the path to use.
932      * @return the digest as a hexadecimal String.
933      * @throws IOException If an I/O error occurs.
934      * @since 1.19.0
935      */
936     public String hmacHex(final Path valueToDigest) throws IOException {
937         return Hex.encodeHexString(hmac(valueToDigest));
938     }
939 
940     /**
941      * Returns the digest for the input data.
942      *
943      * @param valueToDigest the input to use, treated as UTF-8.
944      * @return the digest as a hexadecimal String.
945      * @since 1.11
946      */
947     public String hmacHex(final String valueToDigest) {
948         return Hex.encodeHexString(hmac(valueToDigest));
949     }
950 }