    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.IOException;
    021import java.io.InputStream;
    022import java.security.InvalidKeyException;
    023import java.security.Key;
    024import java.security.NoSuchAlgorithmException;
    025
    026import javax.crypto.Mac;
    027import javax.crypto.spec.SecretKeySpec;
    028
    029import org.apache.commons.codec.binary.Hex;
    030import org.apache.commons.codec.binary.StringUtils;
    031
    032/**
    033 * Simplifies common {@link javax.crypto.Mac} tasks. This class is immutable and thread-safe.
    034 *
    035 *
    036 * <p>
    037 * <strong>Note: Not all JCE implementations supports all algorithms. If not supported, an IllegalArgumentException is
    038 * thrown.</strong>
    039 * </p>
    040 *
    041 * @since 1.10
    042 * @version $Id: HmacUtils.java 1634411 2014-10-27 00:35:43Z ggregory $
    043 */
    044public final class HmacUtils {
    045
    046    private static final int STREAM_BUFFER_LENGTH = 1024;
    047
    048    /**
    049     * Returns an initialized <code>Mac</code> for the HmacMD5 algorithm.
    050     * <p>
    051     * Every implementation of the Java platform is required to support this standard Mac algorithm.
    052     * </p>
    053     *
    054     * @param key
    055     *            They key for the keyed digest (must not be null)
    056     * @return A Mac instance initialized with the given key.
    057     * @see Mac#getInstance(String)
    058     * @see Mac#init(Key)
    059     * @throws IllegalArgumentException
    060     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    061     */
    062    public static Mac getHmacMd5(final byte[] key) {
    063        return getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
    064    }
    065
    066    /**
    067     * Returns an initialized <code>Mac</code> for the HmacSHA1 algorithm.
    068     * <p>
    069     * Every implementation of the Java platform is required to support this standard Mac algorithm.
    070     * </p>
    071     *
    072     * @param key
    073     *            They key for the keyed digest (must not be null)
    074     * @return A Mac instance initialized with the given key.
    075     * @see Mac#getInstance(String)
    076     * @see Mac#init(Key)
    077     * @throws IllegalArgumentException
    078     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    079     */
    080    public static Mac getHmacSha1(final byte[] key) {
    081        return getInitializedMac(HmacAlgorithms.HMAC_SHA_1, key);
    082    }
    083
    084    /**
    085     * Returns an initialized <code>Mac</code> for the HmacSHA256 algorithm.
    086     * <p>
    087     * Every implementation of the Java platform is required to support this standard Mac algorithm.
    088     * </p>
    089     *
    090     * @param key
    091     *            They key for the keyed digest (must not be null)
    092     * @return A Mac instance initialized with the given key.
    093     * @see Mac#getInstance(String)
    094     * @see Mac#init(Key)
    095     * @throws IllegalArgumentException
    096     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    097     */
    098    public static Mac getHmacSha256(final byte[] key) {
    099        return getInitializedMac(HmacAlgorithms.HMAC_SHA_256, key);
    100    }
    101
    102    /**
    103     * Returns an initialized <code>Mac</code> for the HmacSHA384 algorithm.
    104     * <p>
    105     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
    106     * </p>
    107     *
    108     * @param key
    109     *            They 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     */
    116    public static Mac getHmacSha384(final byte[] key) {
    117        return getInitializedMac(HmacAlgorithms.HMAC_SHA_384, key);
    118    }
    119
    120    /**
    121     * Returns an initialized <code>Mac</code> for the HmacSHA512 algorithm.
    122     * <p>
    123     * Every implementation of the Java platform is <em>not</em> required to support this Mac algorithm.
    124     * </p>
    125     *
    126     * @param key
    127     *            They key for the keyed digest (must not be null)
    128     * @return A Mac instance initialized with the given key.
    129     * @see Mac#getInstance(String)
    130     * @see Mac#init(Key)
    131     * @throws IllegalArgumentException
    132     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    133     */
    134    public static Mac getHmacSha512(final byte[] key) {
    135        return getInitializedMac(HmacAlgorithms.HMAC_SHA_512, key);
    136    }
    137
    138    /**
    139     * Returns an initialized <code>Mac</code> for the given <code>algorithm</code>.
    140     *
    141     * @param algorithm
    142     *            the name of the algorithm requested. See <a href=
    143     *            "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix
    144     *            A in the Java Cryptography Architecture Reference Guide</a> for information about standard algorithm
    145     *            names.
    146     * @param key
    147     *            They key for the keyed digest (must not be null)
    148     * @return A Mac instance initialized with the given key.
    149     * @see Mac#getInstance(String)
    150     * @see Mac#init(Key)
    151     * @throws IllegalArgumentException
    152     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    153     */
    154    public static Mac getInitializedMac(final HmacAlgorithms algorithm, final byte[] key) {
    155        return getInitializedMac(algorithm.toString(), key);
    156    }
    157
    158    /**
    159     * Returns an initialized <code>Mac</code> for the given <code>algorithm</code>.
    160     *
    161     * @param algorithm
    162     *            the name of the algorithm requested. See <a href=
    163     *            "http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA" >Appendix
    164     *            A in the Java Cryptography Architecture Reference Guide</a> for information about standard algorithm
    165     *            names.
    166     * @param key
    167     *            They key for the keyed digest (must not be null)
    168     * @return A Mac instance initialized with the given key.
    169     * @see Mac#getInstance(String)
    170     * @see Mac#init(Key)
    171     * @throws IllegalArgumentException
    172     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    173     */
    174    public static Mac getInitializedMac(final String algorithm, final byte[] key) {
    175
    176        if (key == null) {
    177            throw new IllegalArgumentException("Null key");
    178        }
    179
    180        try {
    181            final SecretKeySpec keySpec = new SecretKeySpec(key, algorithm);
    182            final Mac mac = Mac.getInstance(algorithm);
    183            mac.init(keySpec);
    184            return mac;
    185        } catch (final NoSuchAlgorithmException e) {
    186            throw new IllegalArgumentException(e);
    187        } catch (final InvalidKeyException e) {
    188            throw new IllegalArgumentException(e);
    189        }
    190    }
    191
    192    // hmacMd5
    193
    194    /**
    195     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
    196     *
    197     * @param key
    198     *            They key for the keyed digest (must not be null)
    199     * @param valueToDigest
    200     *            The value (data) which should to digest (maybe empty or null)
    201     * @return HmacMD5 MAC for the given key and value
    202     * @throws IllegalArgumentException
    203     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    204     */
    205    public static byte[] hmacMd5(final byte[] key, final byte[] valueToDigest) {
    206        try {
    207            return getHmacMd5(key).doFinal(valueToDigest);
    208        } catch (final IllegalStateException e) {
    209            // cannot happen
    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     *            They key for the keyed digest (must not be null)
    219     * @param valueToDigest
    220     *            The value (data) which should to digest
    221     *            <p>
    222     *            The InputStream must not be null and will not be closed
    223     *            </p>
    224     * @return HmacMD5 MAC for the given key and value
    225     * @throws IOException
    226     *             If an I/O error occurs.
    227     * @throws IllegalArgumentException
    228     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    229     */
    230    public static byte[] hmacMd5(final byte[] key, final InputStream valueToDigest) throws IOException {
    231        return updateHmac(getHmacMd5(key), valueToDigest).doFinal();
    232    }
    233
    234    /**
    235     * Returns a HmacMD5 Message Authentication Code (MAC) for the given key and value.
    236     *
    237     * @param key
    238     *            They key for the keyed digest (must not be null)
    239     * @param valueToDigest
    240     *            The value (data) which should to digest (maybe empty or null)
    241     * @return HmacMD5 MAC for the given key and value
    242     * @throws IllegalArgumentException
    243     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    244     */
    245    public static byte[] hmacMd5(final String key, final String valueToDigest) {
    246        return hmacMd5(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
    247    }
    248
    249    /**
    250     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
    251     *
    252     * @param key
    253     *            They key for the keyed digest (must not be null)
    254     * @param valueToDigest
    255     *            The value (data) which should to digest (maybe empty or null)
    256     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
    257     * @throws IllegalArgumentException
    258     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    259     */
    260    public static String hmacMd5Hex(final byte[] key, final byte[] valueToDigest) {
    261        return Hex.encodeHexString(hmacMd5(key, valueToDigest));
    262    }
    263
    264    /**
    265     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
    266     *
    267     * @param key
    268     *            They key for the keyed digest (must not be null)
    269     * @param valueToDigest
    270     *            The value (data) which should to digest
    271     *            <p>
    272     *            The InputStream must not be null and will not be closed
    273     *            </p>
    274     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
    275     * @throws IOException
    276     *             If an I/O error occurs.
    277     * @throws IllegalArgumentException
    278     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    279     */
    280    public static String hmacMd5Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
    281        return Hex.encodeHexString(hmacMd5(key, valueToDigest));
    282    }
    283
    284    /**
    285     * Returns a HmacMD5 Message Authentication Code (MAC) as a hex string (lowercase) for the given key and value.
    286     *
    287     * @param key
    288     *            They key for the keyed digest (must not be null)
    289     * @param valueToDigest
    290     *            The value (data) which should to digest (maybe empty or null)
    291     * @return HmacMD5 MAC for the given key and value as a hex string (lowercase)
    292     * @throws IllegalArgumentException
    293     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    294     */
    295    public static String hmacMd5Hex(final String key, final String valueToDigest) {
    296        return Hex.encodeHexString(hmacMd5(key, valueToDigest));
    297    }
    298
    299    // hmacSha1
    300
    301    /**
    302     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
    303     *
    304     * @param key
    305     *            They key for the keyed digest (must not be null)
    306     * @param valueToDigest
    307     *            The value (data) which should to digest (maybe empty or null)
    308     * @return HmacSHA1 MAC for the given key and value
    309     * @throws IllegalArgumentException
    310     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    311     */
    312    public static byte[] hmacSha1(final byte[] key, final byte[] valueToDigest) {
    313        try {
    314            return getHmacSha1(key).doFinal(valueToDigest);
    315        } catch (final IllegalStateException e) {
    316            // cannot happen
    317            throw new IllegalArgumentException(e);
    318        }
    319    }
    320
    321    /**
    322     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
    323     *
    324     * @param key
    325     *            They key for the keyed digest (must not be null)
    326     * @param valueToDigest
    327     *            The value (data) which should to digest
    328     *            <p>
    329     *            The InputStream must not be null and will not be closed
    330     *            </p>
    331     * @return HmacSHA1 MAC for the given key and value
    332     * @throws IOException
    333     *             If an I/O error occurs.
    334     * @throws IllegalArgumentException
    335     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    336     */
    337    public static byte[] hmacSha1(final byte[] key, final InputStream valueToDigest) throws IOException {
    338        return updateHmac(getHmacSha1(key), valueToDigest).doFinal();
    339    }
    340
    341    /**
    342     * Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
    343     *
    344     * @param key
    345     *            They key for the keyed digest (must not be null)
    346     * @param valueToDigest
    347     *            The value (data) which should to digest (maybe empty or null)
    348     * @return HmacSHA1 MAC for the given key and value
    349     * @throws IllegalArgumentException
    350     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    351     */
    352    public static byte[] hmacSha1(final String key, final String valueToDigest) {
    353        return hmacSha1(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
    354    }
    355
    356    /**
    357     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    358     *
    359     * @param key
    360     *            They key for the keyed digest (must not be null)
    361     * @param valueToDigest
    362     *            The value (data) which should to digest (maybe empty or null)
    363     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
    364     * @throws IllegalArgumentException
    365     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    366     */
    367    public static String hmacSha1Hex(final byte[] key, final byte[] valueToDigest) {
    368        return Hex.encodeHexString(hmacSha1(key, valueToDigest));
    369    }
    370
    371    /**
    372     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    373     *
    374     * @param key
    375     *            They key for the keyed digest (must not be null)
    376     * @param valueToDigest
    377     *            The value (data) which should to digest
    378     *            <p>
    379     *            The InputStream must not be null and will not be closed
    380     *            </p>
    381     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
    382     * @throws IOException
    383     *             If an I/O error occurs.
    384     * @throws IllegalArgumentException
    385     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    386     */
    387    public static String hmacSha1Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
    388        return Hex.encodeHexString(hmacSha1(key, valueToDigest));
    389    }
    390
    391    /**
    392     * Returns a HmacSHA1 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    393     *
    394     * @param key
    395     *            They key for the keyed digest (must not be null)
    396     * @param valueToDigest
    397     *            The value (data) which should to digest (maybe empty or null)
    398     * @return HmacSHA1 MAC for the given key and value as hex string (lowercase)
    399     * @throws IllegalArgumentException
    400     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    401     */
    402    public static String hmacSha1Hex(final String key, final String valueToDigest) {
    403        return Hex.encodeHexString(hmacSha1(key, valueToDigest));
    404    }
    405
    406    // hmacSha256
    407
    408    /**
    409     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
    410     *
    411     * @param key
    412     *            They key for the keyed digest (must not be null)
    413     * @param valueToDigest
    414     *            The value (data) which should to digest (maybe empty or null)
    415     * @return HmacSHA256 MAC for the given key and value
    416     * @throws IllegalArgumentException
    417     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    418     */
    419    public static byte[] hmacSha256(final byte[] key, final byte[] valueToDigest) {
    420        try {
    421            return getHmacSha256(key).doFinal(valueToDigest);
    422        } catch (final IllegalStateException e) {
    423            // cannot happen
    424            throw new IllegalArgumentException(e);
    425        }
    426    }
    427
    428    /**
    429     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
    430     *
    431     * @param key
    432     *            They key for the keyed digest (must not be null)
    433     * @param valueToDigest
    434     *            The value (data) which should to digest
    435     *            <p>
    436     *            The InputStream must not be null and will not be closed
    437     *            </p>
    438     * @return HmacSHA256 MAC for the given key and value
    439     * @throws IOException
    440     *             If an I/O error occurs.
    441s     * @throws IllegalArgumentException
    442     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    443     */
    444    public static byte[] hmacSha256(final byte[] key, final InputStream valueToDigest) throws IOException {
    445        return updateHmac(getHmacSha256(key), valueToDigest).doFinal();
    446    }
    447
    448    /**
    449     * Returns a HmacSHA256 Message Authentication Code (MAC) for the given key and value.
    450     *
    451     * @param key
    452     *            They key for the keyed digest (must not be null)
    453     * @param valueToDigest
    454     *            The value (data) which should to digest (maybe empty or null)
    455     * @return HmacSHA256 MAC for the given key and value
    456     * @throws IllegalArgumentException
    457     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    458     */
    459    public static byte[] hmacSha256(final String key, final String valueToDigest) {
    460        return hmacSha256(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
    461    }
    462
    463    /**
    464     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    465     *
    466     * @param key
    467     *            They key for the keyed digest (must not be null)
    468     * @param valueToDigest
    469     *            The value (data) which should to digest (maybe empty or null)
    470     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
    471     * @throws IllegalArgumentException
    472     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    473     */
    474    public static String hmacSha256Hex(final byte[] key, final byte[] valueToDigest) {
    475        return Hex.encodeHexString(hmacSha256(key, valueToDigest));
    476    }
    477
    478    /**
    479     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    480     *
    481     * @param key
    482     *            They key for the keyed digest (must not be null)
    483     * @param valueToDigest
    484     *            The value (data) which should to digest
    485     *            <p>
    486     *            The InputStream must not be null and will not be closed
    487     *            </p>
    488     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
    489     * @throws IOException
    490     *             If an I/O error occurs.
    491     * @throws IllegalArgumentException
    492     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    493     */
    494    public static String hmacSha256Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
    495        return Hex.encodeHexString(hmacSha256(key, valueToDigest));
    496    }
    497
    498    /**
    499     * Returns a HmacSHA256 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    500     *
    501     * @param key
    502     *            They key for the keyed digest (must not be null)
    503     * @param valueToDigest
    504     *            The value (data) which should to digest (maybe empty or null)
    505     * @return HmacSHA256 MAC for the given key and value as hex string (lowercase)
    506     * @throws IllegalArgumentException
    507     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    508     */
    509    public static String hmacSha256Hex(final String key, final String valueToDigest) {
    510        return Hex.encodeHexString(hmacSha256(key, valueToDigest));
    511    }
    512
    513    // hmacSha384
    514
    515    /**
    516     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
    517     *
    518     * @param key
    519     *            They key for the keyed digest (must not be null)
    520     * @param valueToDigest
    521     *            The value (data) which should to digest (maybe empty or null)
    522     * @return HmacSHA384 MAC for the given key and value
    523     * @throws IllegalArgumentException
    524     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    525     */
    526    public static byte[] hmacSha384(final byte[] key, final byte[] valueToDigest) {
    527        try {
    528            return getHmacSha384(key).doFinal(valueToDigest);
    529        } catch (final IllegalStateException e) {
    530            // cannot happen
    531            throw new IllegalArgumentException(e);
    532        }
    533    }
    534
    535    /**
    536     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
    537     *
    538     * @param key
    539     *            They key for the keyed digest (must not be null)
    540     * @param valueToDigest
    541     *            The value (data) which should to digest
    542     *            <p>
    543     *            The InputStream must not be null and will not be closed
    544     *            </p>
    545     * @return HmacSHA384 MAC for the given key and value
    546     * @throws IOException
    547     *             If an I/O error occurs.
    548     * @throws IllegalArgumentException
    549     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    550     */
    551    public static byte[] hmacSha384(final byte[] key, final InputStream valueToDigest) throws IOException {
    552        return updateHmac(getHmacSha384(key), valueToDigest).doFinal();
    553    }
    554
    555    /**
    556     * Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
    557     *
    558     * @param key
    559     *            They key for the keyed digest (must not be null)
    560     * @param valueToDigest
    561     *            The value (data) which should to digest (maybe empty or null)
    562     * @return HmacSHA384 MAC for the given key and value
    563     * @throws IllegalArgumentException
    564     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    565     */
    566    public static byte[] hmacSha384(final String key, final String valueToDigest) {
    567        return hmacSha384(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
    568    }
    569
    570    /**
    571     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    572     *
    573     * @param key
    574     *            They key for the keyed digest (must not be null)
    575     * @param valueToDigest
    576     *            The value (data) which should to digest (maybe empty or null)
    577     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
    578     * @throws IllegalArgumentException
    579     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    580     */
    581    public static String hmacSha384Hex(final byte[] key, final byte[] valueToDigest) {
    582        return Hex.encodeHexString(hmacSha384(key, valueToDigest));
    583    }
    584
    585    /**
    586     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    587     *
    588     * @param key
    589     *            They key for the keyed digest (must not be null)
    590     * @param valueToDigest
    591     *            The value (data) which should to digest
    592     *            <p>
    593     *            The InputStream must not be null and will not be closed
    594     *            </p>
    595     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
    596     * @throws IOException
    597     *             If an I/O error occurs.
    598     * @throws IllegalArgumentException
    599     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    600     */
    601    public static String hmacSha384Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
    602        return Hex.encodeHexString(hmacSha384(key, valueToDigest));
    603    }
    604
    605    /**
    606     * Returns a HmacSHA384 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    607     *
    608     * @param key
    609     *            They key for the keyed digest (must not be null)
    610     * @param valueToDigest
    611     *            The value (data) which should to digest (maybe empty or null)
    612     * @return HmacSHA384 MAC for the given key and value as hex string (lowercase)
    613     * @throws IllegalArgumentException
    614     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    615     */
    616    public static String hmacSha384Hex(final String key, final String valueToDigest) {
    617        return Hex.encodeHexString(hmacSha384(key, valueToDigest));
    618    }
    619
    620    // hmacSha512
    621
    622    /**
    623     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
    624     *
    625     * @param key
    626     *            They key for the keyed digest (must not be null)
    627     * @param valueToDigest
    628     *            The value (data) which should to digest (maybe empty or null)
    629     * @return HmacSHA512 MAC for the given key and value
    630     * @throws IllegalArgumentException
    631     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    632     */
    633    public static byte[] hmacSha512(final byte[] key, final byte[] valueToDigest) {
    634        try {
    635            return getHmacSha512(key).doFinal(valueToDigest);
    636        } catch (final IllegalStateException e) {
    637            // cannot happen
    638            throw new IllegalArgumentException(e);
    639        }
    640    }
    641
    642    /**
    643     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
    644     *
    645     * @param key
    646     *            They key for the keyed digest (must not be null)
    647     * @param valueToDigest
    648     *            The value (data) which should to digest
    649     *            <p>
    650     *            The InputStream must not be null and will not be closed
    651     *            </p>
    652     * @return HmacSHA512 MAC for the given key and value
    653     * @throws IOException
    654     *             If an I/O error occurs.
    655     * @throws IllegalArgumentException
    656     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    657     */
    658    public static byte[] hmacSha512(final byte[] key, final InputStream valueToDigest) throws IOException {
    659        return updateHmac(getHmacSha512(key), valueToDigest).doFinal();
    660    }
    661
    662    /**
    663     * Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
    664     *
    665     * @param key
    666     *            They key for the keyed digest (must not be null)
    667     * @param valueToDigest
    668     *            The value (data) which should to digest (maybe empty or null)
    669     * @return HmacSHA512 MAC for the given key and value
    670     * @throws IllegalArgumentException
    671     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    672     */
    673    public static byte[] hmacSha512(final String key, final String valueToDigest) {
    674        return hmacSha512(StringUtils.getBytesUtf8(key), StringUtils.getBytesUtf8(valueToDigest));
    675    }
    676
    677    /**
    678     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    679     *
    680     * @param key
    681     *            They key for the keyed digest (must not be null)
    682     * @param valueToDigest
    683     *            The value (data) which should to digest (maybe empty or null)
    684     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
    685     * @throws IllegalArgumentException
    686     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    687     */
    688    public static String hmacSha512Hex(final byte[] key, final byte[] valueToDigest) {
    689        return Hex.encodeHexString(hmacSha512(key, valueToDigest));
    690    }
    691
    692    /**
    693     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    694     *
    695     * @param key
    696     *            They key for the keyed digest (must not be null)
    697     * @param valueToDigest
    698     *            The value (data) which should to digest
    699     *            <p>
    700     *            The InputStream must not be null and will not be closed
    701     *            </p>
    702     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
    703     * @throws IOException
    704     *             If an I/O error occurs.
    705     * @throws IllegalArgumentException
    706     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    707     */
    708    public static String hmacSha512Hex(final byte[] key, final InputStream valueToDigest) throws IOException {
    709        return Hex.encodeHexString(hmacSha512(key, valueToDigest));
    710    }
    711
    712    /**
    713     * Returns a HmacSHA512 Message Authentication Code (MAC) as hex string (lowercase) for the given key and value.
    714     *
    715     * @param key
    716     *            They key for the keyed digest (must not be null)
    717     * @param valueToDigest
    718     *            The value (data) which should to digest (maybe empty or null)
    719     * @return HmacSHA512 MAC for the given key and value as hex string (lowercase)
    720     * @throws IllegalArgumentException
    721     *             when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
    722     */
    723    public static String hmacSha512Hex(final String key, final String valueToDigest) {
    724        return Hex.encodeHexString(hmacSha512(key, valueToDigest));
    725    }
    726
    727    // update
    728
    729    /**
    730     * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
    731     *
    732     * @param mac
    733     *            the initialized {@link Mac} to update
    734     * @param valueToDigest
    735     *            the value to update the {@link Mac} with (maybe null or empty)
    736     * @return the updated {@link Mac}
    737     * @throws IllegalStateException
    738     *             if the Mac was not initialized
    739     * @since 1.x
    740     */
    741    public static Mac updateHmac(final Mac mac, final byte[] valueToDigest) {
    742        mac.reset();
    743        mac.update(valueToDigest);
    744        return mac;
    745    }
    746
    747    /**
    748     * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
    749     *
    750     * @param mac
    751     *            the initialized {@link Mac} to update
    752     * @param valueToDigest
    753     *            the value to update the {@link Mac} with
    754     *            <p>
    755     *            The InputStream must not be null and will not be closed
    756     *            </p>
    757     * @return the updated {@link Mac}
    758     * @throws IOException
    759     *             If an I/O error occurs.
    760     * @throws IllegalStateException
    761     *             If the Mac was not initialized
    762     * @since 1.x
    763     */
    764    public static Mac updateHmac(final Mac mac, final InputStream valueToDigest) throws IOException {
    765        mac.reset();
    766        final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
    767        int read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
    768
    769        while (read > -1) {
    770            mac.update(buffer, 0, read);
    771            read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH);
    772        }
    773
    774        return mac;
    775    }
    776
    777    /**
    778     * Updates the given {@link Mac}. This generates a digest for valueToDigest and the key the Mac was initialized
    779     *
    780     * @param mac
    781     *            the initialized {@link Mac} to update
    782     * @param valueToDigest
    783     *            the value to update the {@link Mac} with (maybe null or empty)
    784     * @return the updated {@link Mac}
    785     * @throws IllegalStateException
    786     *             if the Mac was not initialized
    787     * @since 1.x
    788     */
    789    public static Mac updateHmac(final Mac mac, final String valueToDigest) {
    790        mac.reset();
    791        mac.update(StringUtils.getBytesUtf8(valueToDigest));
    792        return mac;
    793    }
    794}