001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2023, 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 com.nimbusds.jose.JOSEException; 022import com.nimbusds.jose.JWSAlgorithm; 023import com.nimbusds.jose.KeyLengthException; 024import com.nimbusds.jose.util.StandardCharset; 025 026import javax.crypto.SecretKey; 027import javax.crypto.spec.SecretKeySpec; 028import java.util.Collections; 029import java.util.LinkedHashSet; 030import java.util.Set; 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 * @author Ulrich Winter 047 * @version 2019-09-14 048 */ 049public abstract class MACProvider extends BaseJWSProvider { 050 051 052 /** 053 * The supported JWS algorithms by the MAC provider class. 054 */ 055 public static final Set<JWSAlgorithm> SUPPORTED_ALGORITHMS; 056 057 058 static { 059 Set<JWSAlgorithm> algs = new LinkedHashSet<>(); 060 algs.add(JWSAlgorithm.HS256); 061 algs.add(JWSAlgorithm.HS384); 062 algs.add(JWSAlgorithm.HS512); 063 SUPPORTED_ALGORITHMS = Collections.unmodifiableSet(algs); 064 } 065 066 067 /** 068 * Gets the matching Java Cryptography Architecture (JCA) algorithm 069 * name for the specified HMAC-based JSON Web Algorithm (JWA). 070 * 071 * @param alg The JSON Web Algorithm (JWA). Must be supported and not 072 * {@code null}. 073 * 074 * @return The matching JCA algorithm name. 075 * 076 * @throws JOSEException If the algorithm is not supported. 077 */ 078 protected static String getJCAAlgorithmName(final JWSAlgorithm alg) 079 throws JOSEException { 080 081 if (alg.equals(JWSAlgorithm.HS256)) { 082 return "HMACSHA256"; 083 } else if (alg.equals(JWSAlgorithm.HS384)) { 084 return "HMACSHA384"; 085 } else if (alg.equals(JWSAlgorithm.HS512)) { 086 return "HMACSHA512"; 087 } else { 088 throw new JOSEException(AlgorithmSupportMessage.unsupportedJWSAlgorithm( 089 alg, 090 SUPPORTED_ALGORITHMS)); 091 } 092 } 093 094 095 /** 096 * The secret, {@code null} if specified as {@link SecretKey}. 097 */ 098 private final byte[] secret; 099 100 101 /** 102 * The secret key, {@code null} if specified as byte array. 103 */ 104 private final SecretKey secretKey; 105 106 107 /** 108 * Creates a new Message Authentication (MAC) provider. 109 * 110 * @param secret The secret. Must be at least 256 bits long and 111 * not {@code null}. 112 * @param supportedAlgs The supported HMAC algorithms. Must not be 113 * {@code null}. 114 * 115 * @throws KeyLengthException If the secret length is shorter than the 116 * minimum 256-bit requirement. 117 */ 118 protected MACProvider(final byte[] secret, 119 final Set<JWSAlgorithm> supportedAlgs) 120 throws KeyLengthException { 121 122 super(supportedAlgs); 123 124 if (secret.length < 256 / 8) { 125 throw new KeyLengthException("The secret length must be at least 256 bits"); 126 } 127 128 this.secret = secret; 129 this.secretKey = null; 130 } 131 132 133 /** 134 * Creates a new Message Authentication (MAC) provider. 135 * 136 * @param secretKey The secret key. Must be at least 256 bits long 137 * and not {@code null}. 138 * @param supportedAlgs The supported HMAC algorithms. Must not be 139 * {@code null}. 140 * 141 * @throws KeyLengthException If the secret length is shorter than the 142 * minimum 256-bit requirement. 143 */ 144 protected MACProvider(final SecretKey secretKey, 145 final Set<JWSAlgorithm> supportedAlgs) 146 throws KeyLengthException { 147 148 super(supportedAlgs); 149 150 // An HSM based key will not expose its material and return null 151 if (secretKey.getEncoded() != null && secretKey.getEncoded().length < 256 / 8) { 152 throw new KeyLengthException("The secret length must be at least 256 bits"); 153 } 154 155 this.secretKey = secretKey; 156 this.secret = null; 157 } 158 159 160 /** 161 * Gets the secret key. 162 * 163 * @return The secret key. 164 */ 165 public SecretKey getSecretKey() { 166 if(this.secretKey != null) { 167 return secretKey; 168 } else if (secret != null){ 169 return new SecretKeySpec(secret, "MAC"); 170 } else { 171 throw new IllegalStateException("Unexpected state"); 172 } 173 } 174 175 176 /** 177 * Gets the secret bytes. 178 * 179 * @return The secret bytes, {@code null} if this provider was 180 * constructed with a {@link SecretKey} that doesn't expose the 181 * key material. 182 */ 183 public byte[] getSecret() { 184 if(this.secretKey != null) { 185 return secretKey.getEncoded(); 186 } else if (secret != null){ 187 return secret; 188 } else { 189 throw new IllegalStateException("Unexpected state"); 190 } 191 } 192 193 194 /** 195 * Gets the secret as a UTF-8 encoded string. 196 * 197 * @return The secret as a UTF-8 encoded string, {@code null} if this 198 * provider was constructed with a {@link SecretKey} that 199 * doesn't expose the key material. 200 */ 201 public String getSecretString() { 202 203 byte[] secret = getSecret(); 204 205 if (secret == null) { 206 return null; 207 } 208 209 return new String(secret, StandardCharset.UTF_8); 210 } 211}