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