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.factories; 019 020 021import java.security.Key; 022import java.security.interfaces.ECPrivateKey; 023import java.security.interfaces.RSAPrivateKey; 024import java.util.Collections; 025import java.util.LinkedHashSet; 026import java.util.Set; 027import javax.crypto.SecretKey; 028 029import com.nimbusds.jose.*; 030import com.nimbusds.jose.crypto.*; 031import com.nimbusds.jose.jca.JWEJCAContext; 032import com.nimbusds.jose.proc.JWEDecrypterFactory; 033import net.jcip.annotations.ThreadSafe; 034 035 036/** 037 * Default JSON Web Encryption (JWE) decrypter factory. 038 * 039 * <p>Supports all standard JWE algorithms implemented in the 040 * {@link com.nimbusds.jose.crypto} package. 041 * 042 * @author Vladimir Dzhuvinov 043 * @version 2015-11-16 044 */ 045@ThreadSafe 046public class DefaultJWEDecrypterFactory implements JWEDecrypterFactory { 047 048 049 /** 050 * The supported JWE algorithms. 051 */ 052 public static final Set<JWEAlgorithm> SUPPORTED_ALGORITHMS; 053 054 055 /** 056 * The supported encryption methods. 057 */ 058 public static final Set<EncryptionMethod> SUPPORTED_ENCRYPTION_METHODS; 059 060 061 static { 062 Set<JWEAlgorithm> algs = new LinkedHashSet<>(); 063 algs.addAll(RSADecrypter.SUPPORTED_ALGORITHMS); 064 algs.addAll(ECDHDecrypter.SUPPORTED_ALGORITHMS); 065 algs.addAll(DirectDecrypter.SUPPORTED_ALGORITHMS); 066 algs.addAll(AESDecrypter.SUPPORTED_ALGORITHMS); 067 algs.addAll(PasswordBasedDecrypter.SUPPORTED_ALGORITHMS); 068 SUPPORTED_ALGORITHMS = Collections.unmodifiableSet(algs); 069 070 Set<EncryptionMethod> encs = new LinkedHashSet<>(); 071 encs.addAll(RSADecrypter.SUPPORTED_ENCRYPTION_METHODS); 072 encs.addAll(ECDHDecrypter.SUPPORTED_ENCRYPTION_METHODS); 073 encs.addAll(DirectDecrypter.SUPPORTED_ENCRYPTION_METHODS); 074 encs.addAll(AESDecrypter.SUPPORTED_ENCRYPTION_METHODS); 075 encs.addAll(PasswordBasedDecrypter.SUPPORTED_ENCRYPTION_METHODS); 076 SUPPORTED_ENCRYPTION_METHODS = Collections.unmodifiableSet(encs); 077 } 078 079 080 /** 081 * The JWE JCA context. 082 */ 083 private final JWEJCAContext jcaContext = new JWEJCAContext(); 084 085 086 @Override 087 public Set<JWEAlgorithm> supportedJWEAlgorithms() { 088 089 return SUPPORTED_ALGORITHMS; 090 } 091 092 093 @Override 094 public Set<EncryptionMethod> supportedEncryptionMethods() { 095 096 return SUPPORTED_ENCRYPTION_METHODS; 097 } 098 099 100 @Override 101 public JWEJCAContext getJCAContext() { 102 103 return jcaContext; 104 } 105 106 107 @Override 108 public JWEDecrypter createJWEDecrypter(final JWEHeader header, final Key key) 109 throws JOSEException { 110 111 final JWEDecrypter decrypter; 112 113 if (RSADecrypter.SUPPORTED_ALGORITHMS.contains(header.getAlgorithm()) && 114 RSADecrypter.SUPPORTED_ENCRYPTION_METHODS.contains(header.getEncryptionMethod())) { 115 116 if (!(key instanceof RSAPrivateKey)) { 117 throw new KeyTypeException(RSAPrivateKey.class); 118 } 119 120 RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)key; 121 122 decrypter = new RSADecrypter(rsaPrivateKey); 123 124 } else if (ECDHDecrypter.SUPPORTED_ALGORITHMS.contains(header.getAlgorithm()) && 125 ECDHDecrypter.SUPPORTED_ENCRYPTION_METHODS.contains(header.getEncryptionMethod())) { 126 127 if (!(key instanceof ECPrivateKey)) { 128 throw new KeyTypeException(ECPrivateKey.class); 129 } 130 131 ECPrivateKey ecPrivateKey = (ECPrivateKey)key; 132 decrypter = new ECDHDecrypter(ecPrivateKey); 133 134 } else if (DirectDecrypter.SUPPORTED_ALGORITHMS.contains(header.getAlgorithm()) && 135 DirectDecrypter.SUPPORTED_ENCRYPTION_METHODS.contains(header.getEncryptionMethod())) { 136 137 if (!(key instanceof SecretKey)) { 138 throw new KeyTypeException(SecretKey.class); 139 } 140 141 SecretKey aesKey = (SecretKey)key; 142 DirectDecrypter directDecrypter = new DirectDecrypter(aesKey); 143 144 if (! directDecrypter.supportedEncryptionMethods().contains(header.getEncryptionMethod())) { 145 throw new KeyLengthException(header.getEncryptionMethod().cekBitLength(), header.getEncryptionMethod()); 146 } 147 148 decrypter = directDecrypter; 149 150 } else if (AESDecrypter.SUPPORTED_ALGORITHMS.contains(header.getAlgorithm()) && 151 AESDecrypter.SUPPORTED_ENCRYPTION_METHODS.contains(header.getEncryptionMethod())) { 152 153 if (!(key instanceof SecretKey)) { 154 throw new KeyTypeException(SecretKey.class); 155 } 156 157 SecretKey aesKey = (SecretKey)key; 158 AESDecrypter aesDecrypter = new AESDecrypter(aesKey); 159 160 if (! aesDecrypter.supportedJWEAlgorithms().contains(header.getAlgorithm())) { 161 throw new KeyLengthException(header.getAlgorithm()); 162 } 163 164 decrypter = aesDecrypter; 165 166 } else if (PasswordBasedDecrypter.SUPPORTED_ALGORITHMS.contains(header.getAlgorithm()) && 167 PasswordBasedDecrypter.SUPPORTED_ENCRYPTION_METHODS.contains(header.getEncryptionMethod())) { 168 169 if (!(key instanceof SecretKey)) { 170 throw new KeyTypeException(SecretKey.class); 171 } 172 173 byte[] password = key.getEncoded(); 174 decrypter = new PasswordBasedDecrypter(password); 175 176 } else { 177 178 throw new JOSEException("Unsupported JWE algorithm or encryption method"); 179 } 180 181 // Apply JCA context 182 decrypter.getJCAContext().setSecureRandom(jcaContext.getSecureRandom()); 183 decrypter.getJCAContext().setProvider(jcaContext.getProvider()); 184 decrypter.getJCAContext().setKeyEncryptionProvider(jcaContext.getKeyEncryptionProvider()); 185 decrypter.getJCAContext().setMACProvider(jcaContext.getMACProvider()); 186 decrypter.getJCAContext().setContentEncryptionProvider(jcaContext.getContentEncryptionProvider()); 187 188 return decrypter; 189 } 190}