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