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       * Gets 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       * Gets 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      * Gets 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      * Gets 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      * Gets 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      * Gets 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      * Gets 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              Thrown 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              Thrown 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              Thrown 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              Thrown 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      *                      The InputStream must not be null and will not be closed.
434      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
435      * @throws IOException              Thrown if an I/O error occurs.
436      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
437      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, byte[]).hmacHex(InputStream)}.
438      */
439     @Deprecated
440     public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
441         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
442     }
443 
444     /**
445      * Returns a HmacSHA256 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
446      *
447      * @param key           The key for the keyed digest (must not be null).
448      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
449      * @return HmacSHA256 MAC for the given key and value as hexadecimal string (lowercase).
450      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
451      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_256, String).hmacHex(String)}.
452      */
453     @Deprecated
454     public static String hmacSha256Hex(final String key, final String valueToDigest) {
455         return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
456     }
457 
458     /**
459      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
460      *
461      * @param key           The key for the keyed digest (must not be null).
462      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
463      * @return HmacSHA384 MAC for the given key and value.
464      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
465      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(byte[])}.
466      */
467     @Deprecated
468     public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
469         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
470     }
471 
472     /**
473      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
474      *
475      * @param key           The key for the keyed digest (must not be null).
476      * @param valueToDigest The value (data) which should to digest.
477      *                      The InputStream must not be null and will not be closed.
478      * @return HmacSHA384 MAC for the given key and value.
479      * @throws IOException              Thrown if an I/O error occurs.
480      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
481      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmac(InputStream)}.
482      */
483     @Deprecated
484     public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
485         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
486     }
487 
488     /**
489      * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
490      *
491      * @param key           The key for the keyed digest (must not be null).
492      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
493      * @return HmacSHA384 MAC for the given key and value.
494      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
495      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmac(String)}.
496      */
497     @Deprecated
498     public static byte[] hmacSha384(final String key, final String valueToDigest) {
499         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
500     }
501     // hmacSha384
502 
503     /**
504      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) 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 as hexadecimal string (lowercase).
509      * @throws IllegalArgumentException Thrown if 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, byte[]).hmacHex(byte[])}.
511      */
512     @Deprecated
513     public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
514         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
515     }
516 
517     /**
518      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
519      *
520      * @param key           The key for the keyed digest (must not be null).
521      * @param valueToDigest The value (data) which should to digest.
522      *                      The InputStream must not be null and will not be closed.
523      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
524      * @throws IOException              Thrown if an I/O error occurs.
525      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
526      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, byte[]).hmacHex(InputStream)}.
527      */
528     @Deprecated
529     public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
530         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
531     }
532 
533     /**
534      * Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
535      *
536      * @param key           The key for the keyed digest (must not be null).
537      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
538      * @return HmacSHA384 MAC for the given key and value as hexadecimal string (lowercase).
539      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
540      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_384, String).hmacHex(String)}.
541      */
542     @Deprecated
543     public static String hmacSha384Hex(final String key, final String valueToDigest) {
544         return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
545     }
546 
547     /**
548      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
549      *
550      * @param key           The key for the keyed digest (must not be null).
551      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
552      * @return HmacSHA512 MAC for the given key and value.
553      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
554      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(byte[])}.
555      */
556     @Deprecated
557     public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
558         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
559     }
560 
561     /**
562      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
563      *
564      * @param key           The key for the keyed digest (must not be null).
565      * @param valueToDigest The value (data) which should to digest.
566      *                      The InputStream must not be null and will not be closed.
567      * @return HmacSHA512 MAC for the given key and value.
568      * @throws IOException              Thrown if an I/O error occurs.
569      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
570      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmac(InputStream)}.
571      */
572     @Deprecated
573     public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
574         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
575     }
576 
577     /**
578      * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
579      *
580      * @param key           The key for the keyed digest (must not be null).
581      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
582      * @return HmacSHA512 MAC for the given key and value.
583      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
584      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmac(String)}.
585      */
586     @Deprecated
587     public static byte[] hmacSha512(final String key, final String valueToDigest) {
588         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
589     }
590     // hmacSha512
591 
592     /**
593      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
594      *
595      * @param key           The key for the keyed digest (must not be null).
596      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
597      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
598      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
599      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(byte[])}.
600      */
601     @Deprecated
602     public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
603         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
604     }
605 
606     /**
607      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
608      *
609      * @param key           The key for the keyed digest (must not be null).
610      * @param valueToDigest The value (data) which should to digest.
611      *                      The InputStream must not be null and will not be closed.
612      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
613      * @throws IOException              Thrown if an I/O error occurs.
614      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
615      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, byte[]).hmacHex(InputStream)}.
616      */
617     @Deprecated
618     public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
619         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
620     }
621 
622     /**
623      * Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
624      *
625      * @param key           The key for the keyed digest (must not be null).
626      * @param valueToDigest The value (data) which should to digest (maybe empty or null).
627      * @return HmacSHA512 MAC for the given key and value as hexadecimal string (lowercase).
628      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
629      * @deprecated (1.11) Use {@code new HmacUtils(HmacAlgorithms.HMAC_SHA_512, String).hmacHex(String)}.
630      */
631     @Deprecated
632     public static String hmacSha512Hex(final String key, final String valueToDigest) {
633         return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
634     }
635 
636     /**
637      * Tests whether this algorithm is available.
638      *
639      * @param hmacAlgorithms The HmacAlgorithms to check.
640      * @return whether this algorithm is available.
641      * @since 1.11
642      */
643     public static boolean isAvailable(final HmacAlgorithms hmacAlgorithms) {
644         return isAvailable(hmacAlgorithms.getName());
645     }
646 
647     /**
648      * Tests whether this algorithm is available.
649      *
650      * @param name The name to check.
651      * @return whether this algorithm is available.
652      * @since 1.11
653      */
654     public static boolean isAvailable(final String name) {
655         try {
656             Mac.getInstance(name);
657             return true;
658         } catch (final NoSuchAlgorithmException e) {
659             return false;
660         }
661     }
662 
663     /**
664      * Resets and then updates the given {@link Mac} with the value.
665      *
666      * @param mac           The initialized {@link Mac} to update.
667      * @param valueToDigest The value to update the {@link Mac} with (maybe null or empty).
668      * @return The updated {@link Mac}.
669      * @throws IllegalStateException Thrown if the Mac was not initialized.
670      */
671     public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
672         mac.reset();
673         mac.update(valueToDigest);
674         return mac;
675     }
676 
677     /**
678      * Resets and then updates the given {@link Mac} with the value.
679      *
680      * @param mac           The initialized {@link Mac} to update.
681      * @param valueToDigest The value to update the {@link Mac} with.
682      *                      The InputStream must not be null and will not be closed.
683      * @return The updated {@link Mac}.
684      * @throws IOException           Thrown if an I/O error occurs.
685      * @throws IllegalStateException Thrown if the Mac was not initialized.
686      */
687     public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
688         mac.reset();
689         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
690         int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
691         while (read > -1) {
692             mac.update(buffer, 0, read);
693             read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
694         }
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 (maybe null or empty).
703      * @return The updated {@link Mac}.
704      * @throws IllegalStateException Thrown if the Mac was not initialized.
705      */
706     public static Mac updateHmac(final Mac mac, final String valueToDigest) {
707         mac.reset();
708         mac.update(StringUtils.getBytesUtf8(valueToDigest));
709         return mac;
710     }
711 
712     private final Mac mac;
713 
714     /**
715      * Preserves binary compatibility only. As for previous versions does not provide useful behavior.
716      *
717      * @deprecated Since 1.11; only useful to preserve binary compatibility.
718      */
719     @Deprecated
720     public HmacUtils() {
721         this(null);
722     }
723 
724     /**
725      * Creates an instance using the provided algorithm type.
726      *
727      * @param algorithm to use.
728      * @param key       The key to use.
729      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
730      * @since 1.11
731      */
732     public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
733         this(algorithm.getName(), key);
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 String key) {
745         this(algorithm.getName(), StringUtils.getBytesUtf8(key));
746     }
747 
748     private HmacUtils(final Mac mac) {
749         this.mac = mac;
750     }
751 
752     /**
753      * Creates an instance using the provided algorithm type.
754      *
755      * @param algorithm to use.
756      * @param key       The key to use.
757      * @throws IllegalArgumentException Thrown if a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
758      * @since 1.11
759      */
760     public HmacUtils(final String algorithm, final byte[] key) {
761         this(getInitializedMac(algorithm, key));
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 String key) {
773         this(algorithm, StringUtils.getBytesUtf8(key));
774     }
775 
776     /**
777      * Returns the digest for the input data.
778      *
779      * @param valueToDigest The input to use.
780      * @return The digest as a byte[].
781      * @since 1.11
782      */
783     public byte[] hmac(final byte[] valueToDigest) {
784         return mac.doFinal(valueToDigest);
785     }
786 
787     /**
788      * Returns the digest for the input data.
789      *
790      * @param valueToDigest The input to use.
791      * @return The digest as a byte[].
792      * @since 1.11
793      */
794     public byte[] hmac(final ByteBuffer valueToDigest) {
795         mac.update(valueToDigest);
796         return mac.doFinal();
797     }
798 
799     /**
800      * Returns the digest for the file.
801      *
802      * @param valueToDigest The file to use.
803      * @return The digest.
804      * @throws IOException Thrown if an I/O error occurs.
805      * @since 1.11
806      */
807     public byte[] hmac(final File valueToDigest) throws IOException {
808         return hmac(valueToDigest.toPath());
809     }
810 
811     /**
812      * Returns the digest for the stream.
813      *
814      * @param valueToDigest The data to use.
815      *                      The InputStream must not be null and will not be closed.
816      * @return The digest.
817      * @throws IOException Thrown if an I/O error occurs.
818      * @since 1.11
819      */
820     public byte[] hmac(final InputStream valueToDigest) throws IOException {
821         final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
822         int read;
823         while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH)) > -1) {
824             mac.update(buffer, 0, read);
825         }
826         return mac.doFinal();
827     }
828 
829     /**
830      * Returns the digest for the file.
831      *
832      * @param valueToDigest The path to use.
833      * @return The digest.
834      * @throws IOException Thrown if an I/O error occurs.
835      * @since 1.19.0
836      */
837     public byte[] hmac(final Path valueToDigest) throws IOException {
838         try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(valueToDigest))) {
839             return hmac(stream);
840         }
841     }
842 
843     /**
844      * Returns the digest for the input data.
845      *
846      * @param valueToDigest The input to use, treated as UTF-8.
847      * @return The digest as a byte[].
848      * @since 1.11
849      */
850     public byte[] hmac(final String valueToDigest) {
851         return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
852     }
853 
854     /**
855      * Returns the digest for the input data.
856      *
857      * @param valueToDigest The input to use.
858      * @return The digest as a hexadecimal String.
859      * @since 1.11
860      */
861     public String hmacHex(final byte[] valueToDigest) {
862         return Hex.encodeHexString(hmac(valueToDigest));
863     }
864 
865     /**
866      * Returns the digest for the input data.
867      *
868      * @param valueToDigest The input to use.
869      * @return The digest as a hexadecimal String.
870      * @since 1.11
871      */
872     public String hmacHex(final ByteBuffer valueToDigest) {
873         return Hex.encodeHexString(hmac(valueToDigest));
874     }
875 
876     /**
877      * Returns the digest for the file.
878      *
879      * @param valueToDigest The file to use.
880      * @return The digest as a hexadecimal String.
881      * @throws IOException Thrown if an I/O error occurs.
882      * @since 1.11
883      */
884     public String hmacHex(final File valueToDigest) throws IOException {
885         return Hex.encodeHexString(hmac(valueToDigest));
886     }
887 
888     /**
889      * Returns the digest for the stream.
890      *
891      * @param valueToDigest The data to use.
892      *                      The InputStream must not be null and will not be closed.
893      * @return The digest as a hexadecimal String.
894      * @throws IOException Thrown if an I/O error occurs.
895      * @since 1.11
896      */
897     public String hmacHex(final InputStream valueToDigest) throws IOException {
898         return Hex.encodeHexString(hmac(valueToDigest));
899     }
900 
901     /**
902      * Returns the digest for the path.
903      *
904      * @param valueToDigest The path to use.
905      * @return The digest as a hexadecimal String.
906      * @throws IOException Thrown if an I/O error occurs.
907      * @since 1.19.0
908      */
909     public String hmacHex(final Path valueToDigest) throws IOException {
910         return Hex.encodeHexString(hmac(valueToDigest));
911     }
912 
913     /**
914      * Returns the digest for the input data.
915      *
916      * @param valueToDigest The input to use, treated as UTF-8.
917      * @return The digest as a hexadecimal String.
918      * @since 1.11
919      */
920     public String hmacHex(final String valueToDigest) {
921         return Hex.encodeHexString(hmac(valueToDigest));
922     }
923 }