001package com.nimbusds.jose.crypto; 002 003 004import java.util.Set; 005import javax.crypto.SecretKey; 006 007import com.nimbusds.jose.CriticalHeaderParamsAware; 008import com.nimbusds.jose.JOSEException; 009import com.nimbusds.jose.JWSHeader; 010import com.nimbusds.jose.JWSVerifier; 011import com.nimbusds.jose.jwk.OctetSequenceKey; 012import com.nimbusds.jose.util.Base64URL; 013import com.nimbusds.jose.util.StandardCharset; 014import net.jcip.annotations.ThreadSafe; 015 016 017/** 018 * Message Authentication Code (MAC) verifier of 019 * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a secret key. 020 * 021 * <p>See RFC 7518 022 * <a href="https://tools.ietf.org/html/rfc7518#section-3.2">section 3.2</a> 023 * for more information. 024 * 025 * <p>This class is thread-safe. 026 * 027 * <p>Supports the following algorithms: 028 * 029 * <ul> 030 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS256} 031 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS384} 032 * <li>{@link com.nimbusds.jose.JWSAlgorithm#HS512} 033 * </ul> 034 * 035 * @author Vladimir Dzhuvinov 036 * @version 2016-06-26 037 */ 038@ThreadSafe 039public class MACVerifier extends MACProvider implements JWSVerifier, CriticalHeaderParamsAware { 040 041 042 /** 043 * The critical header policy. 044 */ 045 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 046 047 048 /** 049 * Creates a new Message Authentication (MAC) verifier. 050 * 051 * @param secret The secret. Must be at least 256 bits long and not 052 * {@code null}. 053 * 054 * @throws JOSEException If the secret length is shorter than the 055 * minimum 256-bit requirement. 056 */ 057 public MACVerifier(final byte[] secret) 058 throws JOSEException { 059 060 this(secret, null); 061 } 062 063 064 /** 065 * Creates a new Message Authentication (MAC) verifier. 066 * 067 * @param secretString The secret as a UTF-8 encoded string. Must be at 068 * least 256 bits long and not {@code null}. 069 * 070 * @throws JOSEException If the secret length is shorter than the 071 * minimum 256-bit requirement. 072 */ 073 public MACVerifier(final String secretString) 074 throws JOSEException { 075 076 this(secretString.getBytes(StandardCharset.UTF_8)); 077 } 078 079 080 /** 081 * Creates a new Message Authentication (MAC) verifier. 082 * 083 * @param secretKey The secret key. Must be at least 256 bits long and 084 * not {@code null}. 085 * 086 * @throws JOSEException If the secret length is shorter than the 087 * minimum 256-bit requirement. 088 */ 089 public MACVerifier(final SecretKey secretKey) 090 throws JOSEException { 091 092 this(secretKey.getEncoded()); 093 } 094 095 096 /** 097 * Creates a new Message Authentication (MAC) verifier. 098 * 099 * @param jwk The secret as a JWK. Must be at least 256 bits long and 100 * not {@code null}. 101 * 102 * @throws JOSEException If the secret length is shorter than the 103 * minimum 256-bit requirement. 104 */ 105 public MACVerifier(final OctetSequenceKey jwk) 106 throws JOSEException { 107 108 this(jwk.toByteArray()); 109 } 110 111 112 /** 113 * Creates a new Message Authentication (MAC) verifier. 114 * 115 * @param secret The secret. Must be at least 256 bits long 116 * and not {@code null}. 117 * @param defCritHeaders The names of the critical header parameters 118 * that are deferred to the application for 119 * processing, empty set or {@code null} if none. 120 * 121 * @throws JOSEException If the secret length is shorter than the 122 * minimum 256-bit requirement. 123 */ 124 public MACVerifier(final byte[] secret, 125 final Set<String> defCritHeaders) 126 throws JOSEException { 127 128 super(secret, SUPPORTED_ALGORITHMS); 129 130 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 131 } 132 133 134 @Override 135 public Set<String> getProcessedCriticalHeaderParams() { 136 137 return critPolicy.getProcessedCriticalHeaderParams(); 138 } 139 140 141 @Override 142 public Set<String> getDeferredCriticalHeaderParams() { 143 144 return critPolicy.getProcessedCriticalHeaderParams(); 145 } 146 147 148 @Override 149 public boolean verify(final JWSHeader header, 150 final byte[] signedContent, 151 final Base64URL signature) 152 throws JOSEException { 153 154 if (! critPolicy.headerPasses(header)) { 155 return false; 156 } 157 158 String jcaAlg = getJCAAlgorithmName(header.getAlgorithm()); 159 byte[] expectedHMAC = HMAC.compute(jcaAlg, getSecret(), signedContent, getJCAContext().getProvider()); 160 return ConstantTimeUtils.areEqual(expectedHMAC, signature.decode()); 161 } 162}