1 package org.bouncycastle.pqc.jcajce.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.util.AlgorithmProvider; 19 import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; 20 21 public class BouncyCastlePQCProvider 22 extends Provider 23 implements ConfigurableProvider 24 { 25 private static String info = "BouncyCastle Post-Quantum Security Provider v1.69"; 26 27 public static String PROVIDER_NAME = "BCPQC"; 28 29 public static final ProviderConfiguration CONFIGURATION = null; 30 31 32 private static final Map keyInfoConverters = new HashMap(); 33 34 /* 35 * Configurable symmetric ciphers 36 */ 37 private static final String ALGORITHM_PACKAGE = "org.bouncycastle.pqc.jcajce.provider."; 38 private static final String[] ALGORITHMS = 39 { 40 "Rainbow", "McEliece", "SPHINCS", "LMS", "NH", "XMSS", "QTESLA" 41 }; 42 43 /** 44 * Construct a new provider. This should only be required when 45 * using runtime registration of the provider using the 46 * <code>Security.addProvider()</code> mechanism. 47 */ BouncyCastlePQCProvider()48 public BouncyCastlePQCProvider() 49 { 50 super(PROVIDER_NAME, 1.67, info); 51 52 AccessController.doPrivileged(new PrivilegedAction() 53 { 54 public Object run() 55 { 56 setup(); 57 return null; 58 } 59 }); 60 } 61 setup()62 private void setup() 63 { 64 loadAlgorithms(ALGORITHM_PACKAGE, ALGORITHMS); 65 } 66 loadAlgorithms(String packageName, String[] names)67 private void loadAlgorithms(String packageName, String[] names) 68 { 69 for (int i = 0; i != names.length; i++) 70 { 71 Class clazz = loadClass(BouncyCastlePQCProvider.class, packageName + names[i] + "$Mappings"); 72 73 if (clazz != null) 74 { 75 try 76 { 77 ((AlgorithmProvider)clazz.newInstance()).configure(this); 78 } 79 catch (Exception e) 80 { // this should never ever happen!! 81 throw new InternalError("cannot create instance of " 82 + packageName + names[i] + "$Mappings : " + e); 83 } 84 } 85 } 86 } 87 setParameter(String parameterName, Object parameter)88 public void setParameter(String parameterName, Object parameter) 89 { 90 synchronized (CONFIGURATION) 91 { 92 //((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter); 93 } 94 } 95 hasAlgorithm(String type, String name)96 public boolean hasAlgorithm(String type, String name) 97 { 98 return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name); 99 } 100 addAlgorithm(String key, String value)101 public void addAlgorithm(String key, String value) 102 { 103 if (containsKey(key)) 104 { 105 throw new IllegalStateException("duplicate provider key (" + key + ") found"); 106 } 107 108 put(key, value); 109 } 110 addAlgorithm(String type, ASN1ObjectIdentifier oid, String className)111 public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) 112 { 113 if (!containsKey(type + "." + className)) 114 { 115 throw new IllegalStateException("primary key (" + type + "." + className + ") not found"); 116 } 117 118 addAlgorithm(type + "." + oid, className); 119 addAlgorithm(type + ".OID." + oid, className); 120 } 121 addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)122 public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter) 123 { 124 synchronized (keyInfoConverters) 125 { 126 keyInfoConverters.put(oid, keyInfoConverter); 127 } 128 } 129 getKeyInfoConverter(ASN1ObjectIdentifier oid)130 public AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid) 131 { 132 return (AsymmetricKeyInfoConverter)keyInfoConverters.get(oid); 133 } 134 addAttributes(String key, Map<String, String> attributeMap)135 public void addAttributes(String key, Map<String, String> attributeMap) 136 { 137 for (Iterator it = attributeMap.keySet().iterator(); it.hasNext();) 138 { 139 String attributeName = (String)it.next(); 140 String attributeKey = key + " " + attributeName; 141 if (containsKey(attributeKey)) 142 { 143 throw new IllegalStateException("duplicate provider attribute key (" + attributeKey + ") found"); 144 } 145 146 put(attributeKey, attributeMap.get(attributeName)); 147 } 148 } 149 getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm)150 private static AsymmetricKeyInfoConverter getAsymmetricKeyInfoConverter(ASN1ObjectIdentifier algorithm) 151 { 152 synchronized (keyInfoConverters) 153 { 154 return (AsymmetricKeyInfoConverter)keyInfoConverters.get(algorithm); 155 } 156 } 157 getPublicKey(SubjectPublicKeyInfo publicKeyInfo)158 public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo) 159 throws IOException 160 { 161 AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(publicKeyInfo.getAlgorithm().getAlgorithm()); 162 163 if (converter == null) 164 { 165 return null; 166 } 167 168 return converter.generatePublic(publicKeyInfo); 169 } 170 getPrivateKey(PrivateKeyInfo privateKeyInfo)171 public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo) 172 throws IOException 173 { 174 AsymmetricKeyInfoConverter converter = getAsymmetricKeyInfoConverter(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm()); 175 176 if (converter == null) 177 { 178 return null; 179 } 180 181 return converter.generatePrivate(privateKeyInfo); 182 } 183 loadClass(Class sourceClass, final String className)184 static Class loadClass(Class sourceClass, final String className) 185 { 186 try 187 { 188 ClassLoader loader = sourceClass.getClassLoader(); 189 if (loader != null) 190 { 191 return loader.loadClass(className); 192 } 193 else 194 { 195 return (Class)AccessController.doPrivileged(new PrivilegedAction() 196 { 197 public Object run() 198 { 199 try 200 { 201 return Class.forName(className); 202 } 203 catch (Exception e) 204 { 205 // ignore - maybe log? 206 } 207 208 return null; 209 } 210 }); 211 } 212 } 213 catch (ClassNotFoundException e) 214 { 215 // ignore - maybe log? 216 } 217 218 return null; 219 } 220 } 221