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