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}