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