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, {@code null} to use the default.
052         *
053         * @return The MAC service instance.
054         *
055         * @throws JOSEException If the algorithm is not supported or the
056         *                       MAC secret key is invalid.
057         */
058        public static Mac getInitMac(final SecretKey secretKey, final Provider provider)
059                throws JOSEException {
060
061                return getInitMac(secretKey.getAlgorithm(), secretKey, provider);
062        }
063
064
065        /**
066         * Gets an initialised Message Authentication Code (MAC) service
067         * instance.
068         *
069         * @param alg       The Java Cryptography Architecture (JCA) HMAC
070         *                  algorithm name. Must not be {@code null}.
071         * @param secretKey The secret key. Its algorithm name is ignored.
072         *                  Must not be {@code null}.
073         * @param provider  The JCA provider, {@code null} to use the default.
074         *
075         * @return The MAC service instance.
076         *
077         * @throws JOSEException If the algorithm is not supported or the
078         *                       MAC secret key is invalid.
079         */
080        public static Mac getInitMac(final String alg,
081                                     final SecretKey secretKey,
082                                     final Provider provider)
083                throws JOSEException {
084
085                Mac mac;
086                try {
087                        if (provider != null) {
088                                mac = Mac.getInstance(alg, provider);
089                        } else {
090                                mac = Mac.getInstance(alg);
091                        }
092
093                        mac.init(secretKey);
094
095                } catch (NoSuchAlgorithmException e) {
096                        throw new JOSEException("Unsupported HMAC algorithm: " + e.getMessage(), e);
097                } catch (InvalidKeyException e) {
098                        throw new JOSEException("Invalid HMAC key: " + e.getMessage(), e);
099                }
100
101                return mac;
102        }
103
104
105        /**
106         * Computes a Hash-based Message Authentication Code (HMAC) for the
107         * specified secret and message.
108         *
109         * @param alg      The Java Cryptography Architecture (JCA) HMAC
110         *                 algorithm name. Must not be {@code null}.
111         * @param secret   The secret. Must not be {@code null}.
112         * @param message  The message. Must not be {@code null}.
113         * @param provider The JCA provider, {@code null} to use the default.
114         *
115         * @return The computed HMAC.
116         *
117         * @throws JOSEException If the algorithm is not supported or the
118         *                       MAC secret key is invalid.
119         */
120        @Deprecated
121        public static byte[] compute(final String alg,
122                                     final byte[] secret,
123                                     final byte[] message,
124                                     final Provider provider)
125                throws JOSEException {
126
127                return compute(alg, new SecretKeySpec(secret, alg), message, provider);
128        }
129
130
131        /**
132         * Computes a Hash-based Message Authentication Code (HMAC) for the
133         * specified secret key and message.
134         *
135         * @param alg       The Java Cryptography Architecture (JCA) HMAC
136         *                  algorithm name. Must not be {@code null}.
137         * @param secretKey The secret key. Its algorithm name is ignored.
138         *                  Must not be {@code null}.
139         * @param message   The message. Must not be {@code null}.
140         * @param provider  The JCA provider, {@code null} to use the default.
141         *
142         * @return The computed HMAC.
143         *
144         * @throws JOSEException If the algorithm is not supported or the MAC
145         *                       secret key is invalid.
146         */
147        public static byte[] compute(final String alg,
148                                     final SecretKey secretKey,
149                                     final byte[] message,
150                                     final Provider provider)
151                        throws JOSEException {
152
153                Mac mac = getInitMac(alg, secretKey, provider);
154                mac.update(message);
155                return mac.doFinal();
156        }
157
158        /**
159         * Computes a Hash-based Message Authentication Code (HMAC) for the
160         * specified secret key and message.
161         *
162         * @param secretKey The secret key, with the appropriate HMAC
163         *                  algorithm. Must not be {@code null}.
164         * @param message   The message. Must not be {@code null}.
165         * @param provider  The JCA provider, or {@code null} to use the
166         *                  default one.
167         *
168         * @return A MAC service instance.
169         *
170         * @throws JOSEException If the algorithm is not supported or the MAC
171         *                       secret key is invalid.
172         */
173        public static byte[] compute(final SecretKey secretKey,
174                                     final byte[] message,
175                                     final Provider provider)
176                        throws JOSEException {
177
178                return compute(secretKey.getAlgorithm(), secretKey, message, provider);
179        }
180}