    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.codec.digest;
    019
    020import java.io.BufferedInputStream;
    021import java.io.File;
    022import java.io.IOException;
    023import java.io.InputStream;
    024import java.nio.ByteBuffer;
    025import java.nio.file.Files;
    026import java.nio.file.Path;
    027import java.security.InvalidKeyException;
    028import java.security.Key;
    029import java.security.NoSuchAlgorithmException;
    030
    031import javax.crypto.Mac;
    032import javax.crypto.spec.SecretKeySpec;
    033
    034import org.apache.commons.codec.binary.Hex;
    035import org.apache.commons.codec.binary.StringUtils;
    036
    037/**
    038 * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable and thread-safe. However the Mac may not be.
    039 * <p>
    040 * <strong>Note: Not all JCE implementations support all algorithms. If not supported, an IllegalArgumentException is thrown.</strong>
    041 * </p>
    042 * <p>
    043 * Sample usage:
    044 * </p>
    045 *
    046 * <pre>
    047 * import static HmacAlgorithms.*;
    048 * byte[] key = {1,2,3,4}; // don't use this actual key!
    049 * String valueToDigest = "The quick brown fox jumps over the lazy dog";
    050 * byte[] hmac = new HmacUtils(HMAC_SHA_224, key).hmac(valueToDigest);
    051 * // Mac re-use
    052 * HmacUtils hm1 = new HmacUtils("HmacAlgoName", key); // use a valid name here!
    053 * String hexPom = hm1.hmacHex(new File("pom.xml"));
    054 * String hexNot = hm1.hmacHex(new File("NOTICE.txt"));
    055 * </pre>
    056 *
    057 * @since 1.10
    058 */
    059public final class HmacUtils {
    060
    061    private static final int STREAM_BUFFER_LENGTH = 1024;
    062
    063    /**
    064     * Returns an initialized {@code Mac} for the HmacMD5 algorithm.
    065     * <p>
    066     * Every implementation of the Java platform is required to support this standard Mac algorithm.
    067     * </p>
    068     *
    069     * @param key The key for the keyed digest (must not be null).
    070     * @return A Mac instance initialized with the given key.
    071     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    072     * @see Mac#getInstance(String)
    073     * @see Mac#init(Key)
    074     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_MD5, byte[])}.
    075     */
    076    @Deprecated
    077    public static Mac getHmacMd5(final byte[] key) {
    078        return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
    079    }
    080
    081    /**
    082     * Returns an initialized {@code Mac} for the HmacSHA1 algorithm.
    083     * <p>
    084     * Every implementation of the Java platform is required to support this standard Mac algorithm.
    085     * </p>
    086     *
    087     * @param key The key for the keyed digest (must not be null).
    088     * @return A Mac instance initialized with the given key.
    089     * @throws IllegalArgumentException when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    090     * @see Mac#getInstance(String)
    091     * @see Mac#init(Key)
    092     * @deprecated (1.11) Use {@code getInitializedMac(HmacAlgorithms.HMAC_SHA_1, byte[])}.
    093     */
    094    @Deprecated
    095    public static Mac getHmacSha1(final byte[] key) {
    096        return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
    097    }
    098
    099    /**
    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}