001package com.nimbusds.jose.crypto;
002
003
004import net.jcip.annotations.ThreadSafe;
005
006import com.nimbusds.jose.JOSEException;
007import com.nimbusds.jose.JWSAlgorithm;
008import com.nimbusds.jose.JWSSigner;
009import com.nimbusds.jose.JWSHeader;
010import com.nimbusds.jose.util.Base64URL;
011
012
013
014/**
015 * Message Authentication Code (MAC) signer of 
016 * {@link com.nimbusds.jose.JWSObject JWS objects}. This class is thread-safe.
017 *
018 * <p>Supports the following JSON Web Algorithms (JWAs):
019 *
020 * <ul>
021 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256}
022 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384}
023 *     <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512}
024 * </ul>
025 * 
026 * @author Vladimir Dzhuvinov
027 * @version $version$ (2015-02-02)
028 */
029@ThreadSafe
030public class MACSigner extends MACProvider implements JWSSigner {
031
032
033        /**
034         * Returns the minimal required secret size for the specified
035         * HMAC JWS algorithm.
036         *
037         * @param hmacAlg The HMAC JWS algorithm. Must be
038         *                {@link #SUPPORTED_ALGORITHMS supported} and not
039         *                {@code null}.
040         *
041         * @return The minimal required secret size, in bits.
042         *
043         * @throws JOSEException If the algorithm is not supported.
044         */
045        public static int getMinRequiredSecretSize(final JWSAlgorithm hmacAlg)
046                throws JOSEException {
047
048                if (JWSAlgorithm.HS256.equals(hmacAlg)) {
049                        return 256;
050                } else if (JWSAlgorithm.HS384.equals(hmacAlg)) {
051                        return 384;
052                } else if (JWSAlgorithm.HS512.equals(hmacAlg)) {
053                        return 512;
054                } else {
055                        throw new JOSEException("Unsupported HMAC algorithm, must be HS256, HS384 or HS512");
056                }
057        }
058
059
060        /**
061         * Creates a new Message Authentication (MAC) signer.
062         *
063         * @param sharedSecret The shared secret. Must be at least 256 bits
064         *                     long and not {@code null}.
065         */
066        public MACSigner(final byte[] sharedSecret) {
067
068                super(sharedSecret);
069        }
070
071
072        /**
073         * Creates a new Message Authentication (MAC) signer.
074         *
075         * @param sharedSecretString The shared secret as a UTF-8 encoded
076         *                           string. Must not be {@code null}.
077         */
078        public MACSigner(final String sharedSecretString) {
079
080                super(sharedSecretString);
081        }
082
083
084        @Override
085        public Base64URL sign(final JWSHeader header, final byte[] signingInput)
086                throws JOSEException {
087
088                int minRequiredKeyLength = getMinRequiredSecretSize(header.getAlgorithm());
089
090                if (getSharedSecret().length < minRequiredKeyLength / 8) {
091                        throw new JOSEException("The shared secret size must be at least " + minRequiredKeyLength + " bits for " + header.getAlgorithm());
092                }
093
094                String jcaAlg = getJCAAlgorithmName(header.getAlgorithm());
095                byte[] hmac = HMAC.compute(jcaAlg, getSharedSecret(), signingInput, provider);
096                return Base64URL.encode(hmac);
097        }
098}