001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2023, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.crypto.impl;
019
020
021import com.nimbusds.jose.JOSEException;
022import net.jcip.annotations.ThreadSafe;
023
024import javax.crypto.Mac;
025import javax.crypto.SecretKey;
026import javax.crypto.spec.SecretKeySpec;
027import java.security.InvalidKeyException;
028import java.security.NoSuchAlgorithmException;
029import java.security.Provider;
030
031
032/**
033 * Static methods for Hash-based Message Authentication Codes (HMAC). This
034 * class is thread-safe.
035 *
036 * @author Axel Nennker
037 * @author Vladimir Dzhuvinov
038 * @author Ulrich Winter
039 * @version 2023-09-14
040 */
041@ThreadSafe
042public class HMAC {
043
044
045        /**
046         * Gets an initialised Message Authentication Code (MAC) service
047         * instance.
048         *
049         * @param secretKey The secret key, with the appropriate HMAC
050         *                  algorithm. Must not be {@code null}.
051         * @param provider  The JCA provider, or {@code null} to use the
052         *                  default one.
053         *
054         * @return The MAC service instance.
055         *
056         * @throws JOSEException If the algorithm is not supported or the
057         *                       MAC secret key is invalid.
058         */
059        public static Mac getInitMac(final SecretKey secretKey, final Provider provider)
060                throws JOSEException {
061
062                return getInitMac(secretKey.getAlgorithm(), secretKey, provider);
063        }
064
065
066        /**
067         * Gets an initialised Message Authentication Code (MAC) service
068         * instance.
069         *
070         * @param alg       The Java Cryptography Architecture (JCA) HMAC
071         *                  algorithm name. Must not be {@code null}.
072         * @param secretKey The secret key. Its algorithm name is ignored.
073         *                  Must not be {@code null}.
074         * @param provider  The JCA provider, or {@code null} to use the
075         *                  default one.
076         *
077         * @return The MAC service instance.
078         *
079         * @throws JOSEException If the algorithm is not supported or the
080         *                       MAC secret key is invalid.
081         */
082        public static Mac getInitMac(final String alg,
083                                     final SecretKey secretKey,
084                                     final Provider provider)
085                throws JOSEException {
086
087                Mac mac;
088                try {
089                        if (provider != null) {
090                                mac = Mac.getInstance(alg, provider);
091                        } else {
092                                mac = Mac.getInstance(alg);
093                        }
094
095                        mac.init(secretKey);
096
097                } catch (NoSuchAlgorithmException e) {
098                        throw new JOSEException("Unsupported HMAC algorithm: " + e.getMessage(), e);
099                } catch (InvalidKeyException e) {
100                        throw new JOSEException("Invalid HMAC key: " + e.getMessage(), e);
101                }
102
103                return mac;
104        }
105
106
107        /**
108         * Computes a Hash-based Message Authentication Code (HMAC) for the
109         * specified secret and message.
110         *
111         * @param alg      The Java Cryptography Architecture (JCA) HMAC
112         *                 algorithm name. Must not be {@code null}.
113         * @param secret   The secret. Must not be {@code null}.
114         * @param message  The message. Must not be {@code null}.
115         * @param provider The JCA provider, or {@code null} to use the default
116         *                 one.
117         *
118         * @return The computed HMAC.
119         *
120         * @throws JOSEException If the algorithm is not supported or the
121         *                       MAC secret key is invalid.
122         */
123        @Deprecated
124        public static byte[] compute(final String alg,
125                                     final byte[] secret,
126                                     final byte[] message,
127                                     final Provider provider)
128                throws JOSEException {
129
130                return compute(alg, new SecretKeySpec(secret, alg), message, provider);
131        }
132
133
134        /**
135         * Computes a Hash-based Message Authentication Code (HMAC) for the
136         * specified secret key and message.
137         *
138         * @param alg       The Java Cryptography Architecture (JCA) HMAC
139         *                  algorithm name. Must not be {@code null}.
140         * @param secretKey The secret key. Its algorithm name is ignored.
141         *                  Must not be {@code null}.
142         * @param message   The message. Must not be {@code null}.
143         * @param provider  The JCA provider, or {@code null} to use the
144         *                  default one.
145         *
146         * @return The computed HMAC.
147         *
148         * @throws JOSEException If the algorithm is not supported or the MAC
149         *                       secret key is invalid.
150         */
151        public static byte[] compute(final String alg,
152                                     final SecretKey secretKey,
153                                     final byte[] message,
154                                     final Provider provider)
155                        throws JOSEException {
156
157                Mac mac = getInitMac(alg, secretKey, provider);
158                mac.update(message);
159                return mac.doFinal();
160        }
161
162        /**
163         * Computes a Hash-based Message Authentication Code (HMAC) for the
164         * specified secret key and message.
165         *
166         * @param secretKey The secret key, with the appropriate HMAC
167         *                  algorithm. Must not be {@code null}.
168         * @param message   The message. Must not be {@code null}.
169         * @param provider  The JCA provider, or {@code null} to use the
170         *                  default one.
171         *
172         * @return A MAC service instance.
173         *
174         * @throws JOSEException If the algorithm is not supported or the MAC
175         *                       secret key is invalid.
176         */
177        public static byte[] compute(final SecretKey secretKey,
178                                     final byte[] message,
179                                     final Provider provider)
180                        throws JOSEException {
181
182                return compute(secretKey.getAlgorithm(), secretKey, message, provider);
183        }
184}