1 package org.bouncycastle.jce.provider; 2 3 import java.io.IOException; 4 import java.security.AccessController; 5 import java.security.PrivateKey; 6 import java.security.PrivilegedAction; 7 import java.security.Provider; 8 import java.security.PublicKey; 9 import java.util.HashMap; 10 import java.util.Map; 11 12 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 13 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 14 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 15 import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; 16 import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; 17 import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; 18 import 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 */ 44 public final class BouncyCastleProvider extends Provider 45 implements ConfigurableProvider 46 { 47 private static String info = "BouncyCastle Security Provider v1.54"; 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", "SM4", "TEA", "Twofish", "Threefish", 78 // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF" 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", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", 120 // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b" 121 // END android-removed 122 // BEGIN android-added 123 "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", 124 // END android-added 125 }; 126 127 /* 128 * Configurable keystores 129 */ 130 private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore."; 131 private static final String[] KEYSTORES = 132 { 133 "BC", "PKCS12" 134 }; 135 136 /** 137 * Construct a new provider. This should only be required when 138 * using runtime registration of the provider using the 139 * <code>Security.addProvider()</code> mechanism. 140 */ BouncyCastleProvider()141 public BouncyCastleProvider() 142 { 143 super(PROVIDER_NAME, 1.54, info); 144 145 AccessController.doPrivileged(new PrivilegedAction() 146 { 147 public Object run() 148 { 149 setup(); 150 return null; 151 } 152 }); 153 } 154 setup()155 private void setup() 156 { 157 loadAlgorithms(DIGEST_PACKAGE, DIGESTS); 158 159 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_GENERIC); 160 161 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_MACS); 162 163 loadAlgorithms(SYMMETRIC_PACKAGE, SYMMETRIC_CIPHERS); 164 165 loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_GENERIC); 166 167 loadAlgorithms(ASYMMETRIC_PACKAGE, ASYMMETRIC_CIPHERS); 168 169 loadAlgorithms(KEYSTORE_PACKAGE, KEYSTORES); 170 171 // BEGIN android-removed 172 // // 173 // // X509Store 174 // // 175 // put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection"); 176 // put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection"); 177 // put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection"); 178 // put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection"); 179 // 180 // put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts"); 181 // put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs"); 182 // put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts"); 183 // put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs"); 184 // 185 // // 186 // // X509StreamParser 187 // // 188 // put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser"); 189 // put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser"); 190 // put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser"); 191 // put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser"); 192 // 193 // // 194 // // cipher engines 195 // // 196 // put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES"); 197 // 198 // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES"); 199 // 200 // 201 // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish"); 202 // 203 // // Certification Path API 204 // put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi"); 205 // put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi"); 206 // put("CertPathValidator.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi"); 207 // put("CertPathBuilder.RFC3280", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi"); 208 // END android-removed 209 put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi"); 210 put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi"); 211 put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi"); 212 // BEGIN android-removed 213 // put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi"); 214 // put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi"); 215 // put("Alg.Alias.CertStore.X509LDAP", "LDAP"); 216 // END android-removed 217 } 218 loadAlgorithms(String packageName, String[] names)219 private void loadAlgorithms(String packageName, String[] names) 220 { 221 for (int i = 0; i != names.length; i++) 222 { 223 Class clazz = null; 224 try 225 { 226 ClassLoader loader = this.getClass().getClassLoader(); 227 228 if (loader != null) 229 { 230 clazz = loader.loadClass(packageName + names[i] + "$Mappings"); 231 } 232 else 233 { 234 clazz = Class.forName(packageName + names[i] + "$Mappings"); 235 } 236 } 237 catch (ClassNotFoundException e) 238 { 239 // ignore 240 } 241 242 if (clazz != null) 243 { 244 try 245 { 246 ((AlgorithmProvider)clazz.newInstance()).configure(this); 247 } 248 catch (Exception e) 249 { // this should never ever happen!! 250 throw new InternalError("cannot create instance of " 251 + packageName + names[i] + "$Mappings : " + e); 252 } 253 } 254 } 255 } 256 setParameter(String parameterName, Object parameter)257 public void setParameter(String parameterName, Object parameter) 258 { 259 synchronized (CONFIGURATION) 260 { 261 ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter); 262 } 263 } 264 hasAlgorithm(String type, String name)265 public boolean hasAlgorithm(String type, String name) 266 { 267 return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name); 268 } 269 addAlgorithm(String key, String value)270 public void addAlgorithm(String key, String value) 271 { 272 if (containsKey(key)) 273 { 274 throw new IllegalStateException("duplicate provider key (" + key + ") found"); 275 } 276 277 put(key, value); 278 } 279 addAlgorithm(String type, ASN1ObjectIdentifier oid, String className)280 public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) 281 { 282 addAlgorithm(type + "." + oid, className); 283 addAlgorithm(type + ".OID." + oid, className); 284 } 285 addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)286 public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter) 287 { 288 keyInfoConverters.put(oid, keyInfoConverter); 289 } 290 getPublicKey(SubjectPublicKeyInfo publicKeyInfo)291 public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo) 292 throws IOException 293 { 294 AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm()); 295 296 if (converter == null) 297 { 298 return null; 299 } 300 301 return converter.generatePublic(publicKeyInfo); 302 } 303 getPrivateKey(PrivateKeyInfo privateKeyInfo)304 public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo) 305 throws IOException 306 { 307 AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm()); 308 309 if (converter == null) 310 { 311 return null; 312 } 313 314 return converter.generatePrivate(privateKeyInfo); 315 } 316 } 317