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