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