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