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}