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.<n>=org.bouncycastle.jce.provider.BouncyCastleProvider 37 * </code> 38 * </pre> 39 * Where <n> 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