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