BouncyCastleProvider.java revision a198e1ecc615e26a167d0f2dca9fa7e5fc62de10
1package org.bouncycastle.jce.provider;
2
3import java.io.IOException;
4import java.security.AccessController;
5import java.security.PrivateKey;
6import java.security.PrivilegedAction;
7import java.security.Provider;
8import java.security.PublicKey;
9import java.util.HashMap;
10import java.util.Map;
11
12import org.bouncycastle.asn1.ASN1ObjectIdentifier;
13import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
14import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
15import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
16import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
17import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
18import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
19
20/**
21 * To add the provider at runtime use:
22 * <pre>
23 * import java.security.Security;
24 * import org.bouncycastle.jce.provider.BouncyCastleProvider;
25 *
26 * Security.addProvider(new BouncyCastleProvider());
27 * </pre>
28 * The provider can also be configured as part of your environment via
29 * static registration by adding an entry to the java.security properties
30 * file (found in $JAVA_HOME/jre/lib/security/java.security, where
31 * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
32 * detailed instructions in the file but basically it comes down to adding
33 * a line:
34 * <pre>
35 * <code>
36 *    security.provider.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
37 * </code>
38 * </pre>
39 * Where &lt;n&gt; is the preference you want the provider at (1 being the
40 * most preferred).
41 * <p>Note: JCE algorithm names should be upper-case only so the case insensitive
42 * test for getInstance works.
43 */
44public final class BouncyCastleProvider extends Provider
45    implements ConfigurableProvider
46{
47    private static String info = "BouncyCastle Security Provider v1.49";
48
49    public static final String PROVIDER_NAME = "BC";
50
51    public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
52
53    private static final Map keyInfoConverters = new HashMap();
54
55    /*
56     * Configurable symmetric ciphers
57     */
58    private static final String SYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric.";
59
60    private static final String[] SYMMETRIC_GENERIC =
61    {
62        "PBEPBKDF2", "PBEPKCS12"
63    };
64
65    private static final String[] SYMMETRIC_MACS =
66    {
67        // BEGIN android-removed
68        // "SipHash"
69        // END android-removed
70    };
71
72    private static final String[] SYMMETRIC_CIPHERS =
73    {
74        // BEGIN android-removed
75        // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
76        // "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
77        // END android-removed
78        // BEGIN android-added
79        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish"
80        // END android-added
81    };
82
83     /*
84     * Configurable asymmetric ciphers
85     */
86    private static final String ASYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric.";
87
88    // this one is required for GNU class path - it needs to be loaded first as the
89    // later ones configure it.
90    private static final String[] ASYMMETRIC_GENERIC =
91    {
92        // BEGIN android-removed
93        // "X509", "IES"
94        // END android-removed
95        // BEGIN android-added
96        "X509"
97        // END android-added
98    };
99
100    private static final String[] ASYMMETRIC_CIPHERS =
101    {
102        // BEGIN android-removed
103        // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145"
104        // END android-removed
105        // BEGIN android-added
106        "DSA", "DH", "EC", "RSA",
107        // END android-added
108    };
109
110    /*
111     * Configurable digests
112     */
113    private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
114    private static final String[] DIGESTS =
115    {
116        // BEGIN android-removed
117        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Tiger", "Whirlpool"
118        // END android-removed
119        // BEGIN android-added
120        "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
121        // END android-added
122    };
123
124    /*
125     * Configurable digests
126     */
127    private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore.";
128    private static final String[] KEYSTORES =
129    {
130        "BC", "PKCS12"
131    };
132
133    /**
134     * Construct a new provider.  This should only be required when
135     * using runtime registration of the provider using the
136     * <code>Security.addProvider()</code> mechanism.
137     */
138    public BouncyCastleProvider()
139    {
140        super(PROVIDER_NAME, 1.49, info);
141
142        AccessController.doPrivileged(new PrivilegedAction()
143        {
144            public Object run()
145            {
146                setup();
147                return null;
148            }
149        });
150    }
151
152    private void setup()
153    {
154        loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
155
156        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC);
157
158        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS);
159
160        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS);
161
162        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC);
163
164        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS);
165
166        loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
167
168        // BEGIN android-removed
169        // //
170        // // X509Store
171        // //
172        // put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection");
173        // put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection");
174        // put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection");
175        // put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection");
176        //
177        // put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts");
178        // put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs");
179        // put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts");
180        // put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs");
181        //
182        // //
183        // // X509StreamParser
184        // //
185        // put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser");
186        // put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser");
187        // put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser");
188        // put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser");
189        //
190        // //
191        // // cipher engines
192        // //
193        // put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
194        //
195        // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
196        //
197        //
198        // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
199        //
200        // // Certification Path API
201        // put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
202        // put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
203        // put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
204        // put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
205        // END android-removed
206        put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
207        put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
208        put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi");
209        // BEGIN android-removed
210        // put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi");
211        // put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi");
212        // put("Alg.Alias.CertStore.X509LDAP", "LDAP");
213        // END android-removed
214    }
215
216    private void loadAlgorithms(String packageName, String[] names)
217    {
218        for (int i = 0; i != names.length; i++)
219        {
220            Class clazz = null;
221            try
222            {
223                ClassLoader loader = this.getClass().getClassLoader();
224
225                if (loader != null)
226                {
227                    clazz = loader.loadClass(packageName + names[i] + "$Mappings");
228                }
229                else
230                {
231                    clazz = Class.forName(packageName + names[i] + "$Mappings");
232                }
233            }
234            catch (ClassNotFoundException e)
235            {
236                // ignore
237            }
238
239            if (clazz != null)
240            {
241                try
242                {
243                    ((AlgorithmProvider)clazz.newInstance()).configure(this);
244                }
245                catch (Exception e)
246                {   // this should never ever happen!!
247                    throw new InternalError("cannot create instance of "
248                        + packageName + names[i] + "$Mappings : " + e);
249                }
250            }
251        }
252    }
253
254    public void setParameter(String parameterName, Object parameter)
255    {
256        synchronized (CONFIGURATION)
257        {
258            ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
259        }
260    }
261
262    public boolean hasAlgorithm(String type, String name)
263    {
264        return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
265    }
266
267    public void addAlgorithm(String key, String value)
268    {
269        if (containsKey(key))
270        {
271            throw new IllegalStateException("duplicate provider key (" + key + ") found");
272        }
273
274        put(key, value);
275    }
276
277    public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
278    {
279        keyInfoConverters.put(oid, keyInfoConverter);
280    }
281
282    public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
283        throws IOException
284    {
285        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
286
287        if (converter == null)
288        {
289            return null;
290        }
291
292        return converter.generatePublic(publicKeyInfo);
293    }
294
295    public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
296        throws IOException
297    {
298        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
299
300        if (converter == null)
301        {
302            return null;
303        }
304
305        return converter.generatePrivate(privateKeyInfo);
306    }
307}
308