001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, 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 java.util.Collections;
022import java.util.LinkedHashSet;
023import java.util.Set;
024import javax.crypto.SecretKey;
025import javax.crypto.spec.SecretKeySpec;
026
027import com.nimbusds.jose.JOSEException;
028import com.nimbusds.jose.JWSAlgorithm;
029import com.nimbusds.jose.KeyLengthException;
030import com.nimbusds.jose.util.StandardCharset;
031
032
033/**
034 * The base abstract class for Message Authentication Code (MAC) signers and
035 * verifiers of {@link com.nimbusds.jose.JWSObject JWS objects}.
036 *
037 * <p>Supports the following algorithms:
038 *
039 * <ul>
040 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256}
041 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384}
042 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512}
043 * </ul>
044 * 
045 * @author Vladimir Dzhuvinov
046 * @version 2016-07-27
047 */
048public abstract class MACProvider extends BaseJWSProvider {
049
050
051        /**
052         * The supported JWS algorithms by the MAC provider class.
053         */
054        public static final Set<JWSAlgorithm> SUPPORTED_ALGORITHMS;
055
056
057        static {
058                Set<JWSAlgorithm> algs = new LinkedHashSet<>();
059                algs.add(JWSAlgorithm.HS256);
060                algs.add(JWSAlgorithm.HS384);
061                algs.add(JWSAlgorithm.HS512);
062                SUPPORTED_ALGORITHMS = Collections.unmodifiableSet(algs);
063        }
064
065
066        /**
067         * Gets the matching Java Cryptography Architecture (JCA) algorithm 
068         * name for the specified HMAC-based JSON Web Algorithm (JWA).
069         *
070         * @param alg The JSON Web Algorithm (JWA). Must be supported and not
071         *            {@code null}.
072         *
073         * @return The matching JCA algorithm name.
074         *
075         * @throws JOSEException If the algorithm is not supported.
076         */
077        protected static String getJCAAlgorithmName(final JWSAlgorithm alg)
078                throws JOSEException {
079
080                if (alg.equals(JWSAlgorithm.HS256)) {
081                        return "HMACSHA256";
082                } else if (alg.equals(JWSAlgorithm.HS384)) {
083                        return "HMACSHA384";
084                } else if (alg.equals(JWSAlgorithm.HS512)) {
085                        return "HMACSHA512";
086                } else {
087                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWSAlgorithm(
088                                alg,
089                                SUPPORTED_ALGORITHMS));
090                }
091        }
092
093
094        /**
095         * The secret.
096         */
097        private final byte[] secret;
098
099
100        /**
101         * Creates a new Message Authentication (MAC) provider.
102         *
103         * @param secret        The secret. Must be at least 256 bits long and
104         *                      not {@code null}.
105         * @param supportedAlgs The supported HMAC algorithms. Must not be
106         *                      {@code null}.
107         *
108         * @throws KeyLengthException If the secret length is shorter than the
109         *                            minimum 256-bit requirement.
110         */
111        protected MACProvider(final byte[] secret,
112                              final Set<JWSAlgorithm> supportedAlgs)
113                throws KeyLengthException {
114
115                super(supportedAlgs);
116
117                if (secret.length < 256 / 8) {
118                        throw new KeyLengthException("The secret length must be at least 256 bits");
119                }
120
121                this.secret = secret;
122        }
123
124
125        /**
126         * Gets the secret key.
127         *
128         * @return The secret key.
129         */
130        public SecretKey getSecretKey() {
131
132                return new SecretKeySpec(secret, "MAC");
133        }
134
135
136        /**
137         * Gets the secret bytes.
138         *
139         * @return The secret bytes.
140         */
141        public byte[] getSecret() {
142
143                return secret;
144        }
145
146
147        /**
148         * Gets the secret as a UTF-8 encoded string.
149         *
150         * @return The secret as a UTF-8 encoded string.
151         */
152        public String getSecretString() {
153
154                return new String(secret, StandardCharset.UTF_8);
155        }
156}