BouncyCastleProvider.java revision 5db505e1f6a68c8d5dfdb0fed0b8607dea7bed96
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.50";
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", "ChaCha", "DES", "DESede",
76        // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5",
77        // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish",
78        // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20"
79        // END android-removed
80        // BEGIN android-added
81        "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish",
82        // END android-added
83    };
84
85     /*
86     * Configurable asymmetric ciphers
87     */
88    private static final String ASYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric.";
89
90    // this one is required for GNU class path - it needs to be loaded first as the
91    // later ones configure it.
92    private static final String[] ASYMMETRIC_GENERIC =
93    {
94        // BEGIN android-removed
95        // "X509", "IES"
96        // END android-removed
97        // BEGIN android-added
98        "X509"
99        // END android-added
100    };
101
102    private static final String[] ASYMMETRIC_CIPHERS =
103    {
104        // BEGIN android-removed
105        // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145"
106        // END android-removed
107        // BEGIN android-added
108        "DSA", "DH", "EC", "RSA",
109        // END android-added
110    };
111
112    /*
113     * Configurable digests
114     */
115    private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
116    private static final String[] DIGESTS =
117    {
118        // BEGIN android-removed
119        // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool"
120        // END android-removed
121        // BEGIN android-added
122        "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512",
123        // END android-added
124    };
125
126    /*
127     * Configurable keystores
128     */
129    private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore.";
130    private static final String[] KEYSTORES =
131    {
132        "BC", "PKCS12"
133    };
134
135    /**
136     * Construct a new provider.  This should only be required when
137     * using runtime registration of the provider using the
138     * <code>Security.addProvider()</code> mechanism.
139     */
140    public BouncyCastleProvider()
141    {
142        super(PROVIDER_NAME, 1.50, info);
143
144        AccessController.doPrivileged(new PrivilegedAction()
145        {
146            public Object run()
147            {
148                setup();
149                return null;
150            }
151        });
152    }
153
154    private void setup()
155    {
156        loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
157
158        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC);
159
160        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS);
161
162        loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS);
163
164        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC);
165
166        loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS);
167
168        loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES);
169
170        // BEGIN android-removed
171        // //
172        // // X509Store
173        // //
174        // put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection");
175        // put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection");
176        // put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection");
177        // put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection");
178        //
179        // put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts");
180        // put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs");
181        // put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts");
182        // put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs");
183        //
184        // //
185        // // X509StreamParser
186        // //
187        // put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser");
188        // put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser");
189        // put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser");
190        // put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser");
191        //
192        // //
193        // // cipher engines
194        // //
195        // put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
196        //
197        // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
198        //
199        //
200        // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
201        //
202        // // Certification Path API
203        // put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
204        // put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
205        // put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
206        // put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
207        // END android-removed
208        put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
209        put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
210        put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi");
211        // BEGIN android-removed
212        // put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi");
213        // put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi");
214        // put("Alg.Alias.CertStore.X509LDAP", "LDAP");
215        // END android-removed
216    }
217
218    private void loadAlgorithms(String packageName, String[] names)
219    {
220        for (int i = 0; i != names.length; i++)
221        {
222            Class clazz = null;
223            try
224            {
225                ClassLoader loader = this.getClass().getClassLoader();
226
227                if (loader != null)
228                {
229                    clazz = loader.loadClass(packageName + names[i] + "$Mappings");
230                }
231                else
232                {
233                    clazz = Class.forName(packageName + names[i] + "$Mappings");
234                }
235            }
236            catch (ClassNotFoundException e)
237            {
238                // ignore
239            }
240
241            if (clazz != null)
242            {
243                try
244                {
245                    ((AlgorithmProvider)clazz.newInstance()).configure(this);
246                }
247                catch (Exception e)
248                {   // this should never ever happen!!
249                    throw new InternalError("cannot create instance of "
250                        + packageName + names[i] + "$Mappings : " + e);
251                }
252            }
253        }
254    }
255
256    public void setParameter(String parameterName, Object parameter)
257    {
258        synchronized (CONFIGURATION)
259        {
260            ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
261        }
262    }
263
264    public boolean hasAlgorithm(String type, String name)
265    {
266        return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
267    }
268
269    public void addAlgorithm(String key, String value)
270    {
271        if (containsKey(key))
272        {
273            throw new IllegalStateException("duplicate provider key (" + key + ") found");
274        }
275
276        put(key, value);
277    }
278
279    public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
280    {
281        keyInfoConverters.put(oid, keyInfoConverter);
282    }
283
284    public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
285        throws IOException
286    {
287        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
288
289        if (converter == null)
290        {
291            return null;
292        }
293
294        return converter.generatePublic(publicKeyInfo);
295    }
296
297    public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
298        throws IOException
299    {
300        AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
301
302        if (converter == null)
303        {
304            return null;
305        }
306
307        return converter.generatePrivate(privateKeyInfo);
308    }
309}
310