001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2016, Connect2id Ltd. 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; 019 020 021import java.util.Set; 022import javax.crypto.SecretKey; 023import javax.crypto.spec.SecretKeySpec; 024 025import com.nimbusds.jose.*; 026import com.nimbusds.jose.jwk.OctetSequenceKey; 027import com.nimbusds.jose.util.Base64URL; 028import net.jcip.annotations.ThreadSafe; 029 030 031/** 032 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a 033 * shared symmetric key. 034 * 035 * <p>See RFC 7518 036 * <a href="https://tools.ietf.org/html/rfc7518#section-4.5">section 4.5</a> 037 * for more information.</p> 038 * 039 * <p>This class is thread-safe. 040 * 041 * <p>Supports the following key management algorithms: 042 * 043 * <ul> 044 * <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR} 045 * </ul> 046 * 047 * <p>Supports the following content encryption algorithms: 048 * 049 * <ul> 050 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} (requires 256 bit key) 051 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} (requires 384 bit key) 052 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} (requires 512 bit key) 053 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} (requires 128 bit key) 054 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} (requires 192 bit key) 055 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} (requires 256 bit key) 056 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} (requires 256 bit key) 057 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} (requires 512 bit key) 058 * </ul> 059 * 060 * <p>Also supports a promiscuous mode to decrypt any JWE by passing the 061 * content encryption key (CEK) directly. The that mode the JWE algorithm 062 * checks for ("alg":"dir") and encrypted key not being present will be 063 * skipped. 064 * 065 * @author Vladimir Dzhuvinov 066 * @version 2018-07-16 067 */ 068@ThreadSafe 069public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 070 071 072 /** 073 * If set skips the checks for alg "dir" and encrypted key not present. 074 */ 075 private final boolean promiscuousMode; 076 077 078 /** 079 * The critical header policy. 080 */ 081 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 082 083 084 /** 085 * Creates a new direct decrypter. 086 * 087 * @param key The symmetric key. Its algorithm should be "AES". Must be 088 * 128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32 089 * bytes), 384 bits (48 bytes) or 512 bits (64 bytes) long. 090 * Must not be {@code null}. 091 * 092 * @throws KeyLengthException If the symmetric key length is not 093 * compatible. 094 */ 095 public DirectDecrypter(final SecretKey key) 096 throws KeyLengthException { 097 098 this(key, false); 099 } 100 101 102 /** 103 * Creates a new direct decrypter with the option to set it in 104 * promiscuous mode. 105 * 106 * @param key The symmetric key. Its algorithm should be 107 * "AES". Must be 128 bits (16 bytes), 192 bits 108 * (24 bytes), 256 bits (32 bytes), 384 bits (48 109 * bytes) or 512 bits (64 bytes) long. Must not 110 * be {@code null}. 111 * @param promiscuousMode If {@code true} set the decrypter in 112 * promiscuous mode to permit decryption of any 113 * JWE with the supplied symmetric key. The that 114 * mode the JWE algorithm checks for 115 * ("alg":"dir") and encrypted key not being 116 * present will be skipped. 117 * 118 * @throws KeyLengthException If the symmetric key length is not 119 * compatible. 120 */ 121 public DirectDecrypter(final SecretKey key, final boolean promiscuousMode) 122 throws KeyLengthException { 123 124 super(key); 125 126 this.promiscuousMode = promiscuousMode; 127 } 128 129 130 /** 131 * Creates a new direct decrypter. 132 * 133 * @param keyBytes The symmetric key, as a byte array. Must be 128 bits 134 * (16 bytes), 192 bits (24 bytes), 256 bits (32 135 * bytes), 384 bits (48 bytes) or 512 bits (64 bytes) 136 * long. Must not be {@code null}. 137 * 138 * @throws KeyLengthException If the symmetric key length is not 139 * compatible. 140 */ 141 public DirectDecrypter(final byte[] keyBytes) 142 throws KeyLengthException { 143 144 this(new SecretKeySpec(keyBytes, "AES"), false); 145 } 146 147 148 /** 149 * Creates a new direct decrypter. 150 * 151 * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16 152 * bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384 153 * bits (48 bytes) or 512 bits (64 bytes) long. Must not 154 * be {@code null}. 155 * 156 * @throws KeyLengthException If the symmetric key length is not 157 * compatible. 158 */ 159 public DirectDecrypter(final OctetSequenceKey octJWK) 160 throws KeyLengthException { 161 162 this(octJWK.toSecretKey("AES")); 163 } 164 165 166 /** 167 * Creates a new direct decrypter with the option to set it in 168 * promiscuous mode. 169 * 170 * @param key The symmetric key. Its algorithm should be 171 * "AES". Must be 128 bits (16 bytes), 192 bits 172 * (24 bytes), 256 bits (32 bytes), 384 bits (48 173 * bytes) or 512 bits (64 bytes) long. Must not 174 * be {@code null}. 175 * @param defCritHeaders The names of the critical header parameters 176 * that are deferred to the application for 177 * processing, empty set or {@code null} if none. 178 * 179 * @throws KeyLengthException If the symmetric key length is not 180 * compatible. 181 */ 182 public DirectDecrypter(final SecretKey key, final Set<String> defCritHeaders) 183 throws KeyLengthException { 184 185 this(key, defCritHeaders, false); 186 } 187 188 189 /** 190 * Creates a new direct decrypter. 191 * 192 * @param key The symmetric key. Its algorithm should be 193 * "AES". Must be 128 bits (16 bytes), 192 bits 194 * (24 bytes), 256 bits (32 bytes), 384 bits (48 195 * bytes) or 512 bits (64 bytes) long. Must not 196 * be {@code null}. 197 * @param defCritHeaders The names of the critical header parameters 198 * that are deferred to the application for 199 * processing, empty set or {@code null} if none. 200 *@param promiscuousMode If {@code true} set the decrypter in 201 * promiscuous mode to permit decryption of any 202 * JWE with the supplied symmetric key. The that 203 * mode the JWE algorithm checks for 204 * ("alg":"dir") and encrypted key not being 205 * present will be skipped. 206 * 207 * @throws KeyLengthException If the symmetric key length is not 208 * compatible. 209 */ 210 public DirectDecrypter(final SecretKey key, 211 final Set<String> defCritHeaders, 212 final boolean promiscuousMode) 213 throws KeyLengthException { 214 215 super(key); 216 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 217 this.promiscuousMode = promiscuousMode; 218 } 219 220 221 @Override 222 public Set<String> getProcessedCriticalHeaderParams() { 223 224 return critPolicy.getProcessedCriticalHeaderParams(); 225 } 226 227 228 @Override 229 public Set<String> getDeferredCriticalHeaderParams() { 230 231 return critPolicy.getProcessedCriticalHeaderParams(); 232 } 233 234 235 @Override 236 public byte[] decrypt(final JWEHeader header, 237 final Base64URL encryptedKey, 238 final Base64URL iv, 239 final Base64URL cipherText, 240 final Base64URL authTag) 241 throws JOSEException { 242 243 // Validate required JWE parts 244 if (! promiscuousMode) { 245 246 JWEAlgorithm alg = header.getAlgorithm(); 247 248 if (!alg.equals(JWEAlgorithm.DIR)) { 249 throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS)); 250 } 251 252 if (encryptedKey != null) { 253 throw new JOSEException("Unexpected present JWE encrypted key"); 254 } 255 } 256 257 if (iv == null) { 258 throw new JOSEException("Unexpected present JWE initialization vector (IV)"); 259 } 260 261 if (authTag == null) { 262 throw new JOSEException("Missing JWE authentication tag"); 263 } 264 265 critPolicy.ensureHeaderPasses(header); 266 267 return ContentCryptoProvider.decrypt(header, null, iv, cipherText, authTag, getKey(), getJCAContext()); 268 } 269}