View Javadoc
1   /*
2    * GordianKnot: Security Suite
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.gordianknot.impl.jca;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
21  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
22  import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
23  import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianXMSSSpec.GordianXMSSDigestType;
24  import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
25  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
26  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianLogicException;
27  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianCoreKeyPairGenerator;
28  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
29  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreDHSpec;
30  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreDSASpec;
31  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
32  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreLMSSpec;
33  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreXMSSSpec;
34  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaDHPrivateKey;
35  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaDHPublicKey;
36  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaPrivateKey;
37  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaPublicKey;
38  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaStateAwareKeyPair;
39  import io.github.tonywasher.joceanus.gordianknot.impl.jca.JcaKeyPair.JcaStateAwarePrivateKey;
40  import org.bouncycastle.crypto.params.DHParameters;
41  import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPrivateKey;
42  import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey;
43  import org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
44  import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
45  import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
46  import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
47  import org.bouncycastle.jcajce.spec.SLHDSAParameterSpec;
48  import org.bouncycastle.jcajce.spec.XDHParameterSpec;
49  import org.bouncycastle.jce.spec.ElGamalParameterSpec;
50  import org.bouncycastle.pqc.crypto.lms.LMSParameters;
51  import org.bouncycastle.pqc.jcajce.spec.BIKEParameterSpec;
52  import org.bouncycastle.pqc.jcajce.spec.CMCEParameterSpec;
53  import org.bouncycastle.pqc.jcajce.spec.FalconParameterSpec;
54  import org.bouncycastle.pqc.jcajce.spec.FrodoParameterSpec;
55  import org.bouncycastle.pqc.jcajce.spec.HQCParameterSpec;
56  import org.bouncycastle.pqc.jcajce.spec.LMSHSSKeyGenParameterSpec;
57  import org.bouncycastle.pqc.jcajce.spec.LMSKeyGenParameterSpec;
58  import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec;
59  import org.bouncycastle.pqc.jcajce.spec.NTRULPRimeParameterSpec;
60  import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec;
61  import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec;
62  import org.bouncycastle.pqc.jcajce.spec.PicnicParameterSpec;
63  import org.bouncycastle.pqc.jcajce.spec.SABERParameterSpec;
64  import org.bouncycastle.pqc.jcajce.spec.SNTRUPrimeParameterSpec;
65  import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec;
66  import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec;
67  import org.bouncycastle.pqc.jcajce.spec.XMSSParameterSpec;
68  
69  import java.security.InvalidAlgorithmParameterException;
70  import java.security.KeyFactory;
71  import java.security.KeyPair;
72  import java.security.KeyPairGenerator;
73  import java.security.NoSuchAlgorithmException;
74  import java.security.PrivateKey;
75  import java.security.PublicKey;
76  import java.security.spec.AlgorithmParameterSpec;
77  import java.security.spec.ECGenParameterSpec;
78  import java.security.spec.InvalidKeySpecException;
79  import java.security.spec.PKCS8EncodedKeySpec;
80  import java.security.spec.X509EncodedKeySpec;
81  import java.util.Arrays;
82  
83  /**
84   * Jca KeyPair generator.
85   */
86  public abstract class JcaKeyPairGenerator
87          extends GordianCoreKeyPairGenerator {
88      /**
89       * Parse error.
90       */
91      private static final String PARSE_ERROR = "Failed to parse encoding";
92  
93      /**
94       * Factory.
95       */
96      private KeyFactory theFactory;
97  
98      /**
99       * Constructor.
100      *
101      * @param pFactory the Security Factory
102      * @param pKeySpec the keySpec
103      */
104     JcaKeyPairGenerator(final GordianBaseFactory pFactory,
105                         final GordianKeyPairSpec pKeySpec) {
106         super(pFactory, pKeySpec);
107     }
108 
109     /**
110      * Obtain Set the key factory.
111      *
112      * @return the keyFactory
113      */
114     KeyFactory getKeyFactory() {
115         return theFactory;
116     }
117 
118     /**
119      * Set the key factory.
120      *
121      * @param pFactory the keyFactory
122      */
123     void setKeyFactory(final KeyFactory pFactory) {
124         theFactory = pFactory;
125     }
126 
127     @Override
128     public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
129         /* Check the keyPair */
130         JcaKeyPair.checkKeyPair(pKeyPair);
131 
132         /* derive the encoding */
133         final JcaPrivateKey myPrivateKey = (JcaPrivateKey) getPrivateKey(pKeyPair);
134         return new PKCS8EncodedKeySpec(myPrivateKey.getPrivateKey().getEncoded());
135     }
136 
137     @Override
138     public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
139         /* Check the keyPair */
140         JcaKeyPair.checkKeyPair(pKeyPair);
141 
142         /* derive the encoding */
143         final JcaPublicKey myPublicKey = (JcaPublicKey) getPublicKey(pKeyPair);
144         return new X509EncodedKeySpec(myPublicKey.getPublicKey().getEncoded());
145     }
146 
147     @Override
148     public JcaKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
149                                     final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
150         /* Protect against exceptions */
151         try {
152             /* Check the keySpec */
153             checkKeySpec(pPrivateKey);
154 
155             /* derive the keyPair */
156             final JcaPublicKey myPublic = derivePublicKey(pPublicKey);
157             final JcaPrivateKey myPrivate = createPrivate(theFactory.generatePrivate(pPrivateKey));
158             final JcaKeyPair myPair = new JcaKeyPair(myPublic, myPrivate);
159 
160             /* Check that we have a matching pair */
161             GordianKeyPairValidity.checkValidity(getFactory(), myPair);
162 
163             /* Return the keyPair */
164             return myPair;
165 
166         } catch (InvalidKeySpecException e) {
167             throw new GordianCryptoException(PARSE_ERROR, e);
168         }
169     }
170 
171     /**
172      * Create private key.
173      *
174      * @param pPrivateKey the private key
175      * @return the private key
176      */
177     protected JcaPrivateKey createPrivate(final PrivateKey pPrivateKey) {
178         return new JcaPrivateKey(getKeySpec(), pPrivateKey);
179     }
180 
181     /**
182      * Create public key.
183      *
184      * @param pPublicKey the public key
185      * @return the public key
186      */
187     protected JcaPublicKey createPublic(final PublicKey pPublicKey) {
188         return new JcaPublicKey(getKeySpec(), pPublicKey);
189     }
190 
191     @Override
192     public JcaKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pPublicKey) throws GordianException {
193         final JcaPublicKey myPublic = derivePublicKey(pPublicKey);
194         return new JcaKeyPair(myPublic);
195     }
196 
197     /**
198      * Derive the public key.
199      *
200      * @param pEncodedKey the encoded public key
201      * @return the public key
202      * @throws GordianException on error
203      */
204     protected JcaPublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
205         /* Protect against exceptions */
206         try {
207             /* Check the keySpec */
208             checkKeySpec(pEncodedKey);
209 
210             /* derive the key */
211             return createPublic(theFactory.generatePublic(pEncodedKey));
212 
213         } catch (InvalidKeySpecException e) {
214             throw new GordianCryptoException(PARSE_ERROR, e);
215         }
216     }
217 
218     /**
219      * Jca RSA KeyPair generator.
220      */
221     public static class JcaRSAKeyPairGenerator
222             extends JcaKeyPairGenerator {
223         /**
224          * RSA algorithm.
225          */
226         private static final String RSA_ALGO = "RSA";
227 
228         /**
229          * Generator.
230          */
231         private final KeyPairGenerator theGenerator;
232 
233         /**
234          * Constructor.
235          *
236          * @param pFactory the Security Factory
237          * @param pKeySpec the keySpec
238          * @throws GordianException on error
239          */
240         JcaRSAKeyPairGenerator(final GordianBaseFactory pFactory,
241                                final GordianKeyPairSpec pKeySpec) throws GordianException {
242             /* initialize underlying class */
243             super(pFactory, pKeySpec);
244 
245             /* Create and initialize the generator */
246             theGenerator = getJavaKeyPairGenerator(RSA_ALGO, false);
247             final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
248             theGenerator.initialize(myKeySpec.getRSASpec().getLength(), getRandom());
249 
250             /* Create the factory */
251             setKeyFactory(getJavaKeyFactory(RSA_ALGO, false));
252         }
253 
254         @Override
255         public JcaKeyPair generateKeyPair() {
256             /* Generate and return the keyPair */
257             final KeyPair myPair = theGenerator.generateKeyPair();
258             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
259             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
260             return new JcaKeyPair(myPublic, myPrivate);
261         }
262     }
263 
264     /**
265      * Jca ElGamal KeyPair generator.
266      */
267     public static class JcaElGamalKeyPairGenerator
268             extends JcaKeyPairGenerator {
269         /**
270          * RSA algorithm.
271          */
272         private static final String ELGAMAL_ALGO = "ELGAMAL";
273 
274         /**
275          * Generator.
276          */
277         private final KeyPairGenerator theGenerator;
278 
279         /**
280          * Constructor.
281          *
282          * @param pFactory the Security Factory
283          * @param pKeySpec the keySpec
284          * @throws GordianException on error
285          */
286         JcaElGamalKeyPairGenerator(final GordianBaseFactory pFactory,
287                                    final GordianKeyPairSpec pKeySpec) throws GordianException {
288             /* initialize underlying class */
289             super(pFactory, pKeySpec);
290 
291             /* Protect against exceptions */
292             try {
293                 /* Create the parameter generator */
294                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
295                 final GordianCoreDHSpec myGroup = myKeySpec.getDHSpec();
296                 final DHParameters myParms = myGroup.getParameters();
297                 final ElGamalParameterSpec mySpec = new ElGamalParameterSpec(myParms.getP(), myParms.getQ());
298 
299                 /* Create and initialize the generator */
300                 theGenerator = getJavaKeyPairGenerator(ELGAMAL_ALGO, false);
301                 theGenerator.initialize(mySpec, getRandom());
302 
303                 /* Create the factory */
304                 setKeyFactory(getJavaKeyFactory(ELGAMAL_ALGO, false));
305 
306             } catch (InvalidAlgorithmParameterException e) {
307                 throw new GordianCryptoException("Failed to create ElGamalGenerator", e);
308             }
309         }
310 
311         @Override
312         public JcaKeyPair generateKeyPair() {
313             /* Generate and return the keyPair */
314             final KeyPair myPair = theGenerator.generateKeyPair();
315             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
316             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
317             return new JcaKeyPair(myPublic, myPrivate);
318         }
319     }
320 
321     /**
322      * Jca Elliptic KeyPair generator.
323      */
324     public static class JcaECKeyPairGenerator
325             extends JcaKeyPairGenerator {
326         /**
327          * Generator.
328          */
329         private final KeyPairGenerator theGenerator;
330 
331         /**
332          * Constructor.
333          *
334          * @param pFactory the Security Factory
335          * @param pKeySpec the keySpec
336          * @throws GordianException on error
337          */
338         JcaECKeyPairGenerator(final GordianBaseFactory pFactory,
339                               final GordianKeyPairSpec pKeySpec) throws GordianException {
340             /* initialize underlying class */
341             super(pFactory, pKeySpec);
342 
343             /* Protect against exceptions */
344             try {
345                 /* Create and initialize the generator */
346                 final String myAlgo = getAlgorithm();
347                 theGenerator = getJavaKeyPairGenerator(myAlgo, false);
348                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
349                 final ECGenParameterSpec myParms = new ECGenParameterSpec(myKeySpec.getElliptic().getCurveName());
350                 theGenerator.initialize(myParms, getRandom());
351 
352                 /* Create the factory */
353                 setKeyFactory(getJavaKeyFactory(myAlgo, false));
354 
355             } catch (InvalidAlgorithmParameterException e) {
356                 throw new GordianCryptoException("Failed to create ECgenerator for:  " + pKeySpec, e);
357             }
358         }
359 
360         @Override
361         public JcaKeyPair generateKeyPair() {
362             /* Generate and return the keyPair */
363             final KeyPair myPair = theGenerator.generateKeyPair();
364             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
365             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
366             return new JcaKeyPair(myPublic, myPrivate);
367         }
368 
369         /**
370          * Obtain algorithm for keySpec.
371          *
372          * @return the algorithm
373          */
374         private String getAlgorithm() {
375             return switch (this.getKeySpec().getKeyPairType()) {
376                 case DSTU -> "DSTU4145";
377                 case GOST -> "ECGOST3410-2012";
378                 default -> "EC";
379             };
380         }
381     }
382 
383     /**
384      * Jca DSA KeyPair generator.
385      */
386     public static class JcaDSAKeyPairGenerator
387             extends JcaKeyPairGenerator {
388         /**
389          * DSA algorithm.
390          */
391         private static final String DSA_ALGO = "DSA";
392 
393         /**
394          * Generator.
395          */
396         private final KeyPairGenerator theGenerator;
397 
398         /**
399          * Constructor.
400          *
401          * @param pFactory the Security Factory
402          * @param pKeySpec the keySpec
403          * @throws GordianException on error
404          */
405         JcaDSAKeyPairGenerator(final GordianBaseFactory pFactory,
406                                final GordianKeyPairSpec pKeySpec) throws GordianException {
407             /* initialize underlying class */
408             super(pFactory, pKeySpec);
409 
410             /* Create and initialize the generator */
411             final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
412             final GordianCoreDSASpec myKeyType = myKeySpec.getDSASpec();
413             theGenerator = getJavaKeyPairGenerator(DSA_ALGO, false);
414             theGenerator.initialize(myKeyType.getKeySize(), getRandom());
415 
416             /* Create the factory */
417             setKeyFactory(getJavaKeyFactory(DSA_ALGO, false));
418         }
419 
420         @Override
421         public JcaKeyPair generateKeyPair() {
422             /* Generate and return the keyPair */
423             final KeyPair myPair = theGenerator.generateKeyPair();
424             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
425             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
426             return new JcaKeyPair(myPublic, myPrivate);
427         }
428     }
429 
430     /**
431      * Jca DiffieHellman KeyPair generator.
432      */
433     public static class JcaDHKeyPairGenerator
434             extends JcaKeyPairGenerator {
435         /**
436          * DH algorithm.
437          */
438         private static final String DH_ALGO = "DH";
439 
440         /**
441          * Generator.
442          */
443         private final KeyPairGenerator theGenerator;
444 
445         /**
446          * Constructor.
447          *
448          * @param pFactory the Security Factory
449          * @param pKeySpec the keySpec
450          * @throws GordianException on error
451          */
452         JcaDHKeyPairGenerator(final GordianBaseFactory pFactory,
453                               final GordianKeyPairSpec pKeySpec) throws GordianException {
454             /* initialize underlying class */
455             super(pFactory, pKeySpec);
456 
457             /* Protect against exceptions */
458             try {
459                 /* Create the parameter generator */
460                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
461                 final GordianCoreDHSpec myGroup = myKeySpec.getDHSpec();
462                 final DHParameters myParms = myGroup.getParameters();
463                 final DHDomainParameterSpec mySpec = new DHDomainParameterSpec(myParms);
464 
465                 /* Create and initialize the generator */
466                 theGenerator = getJavaKeyPairGenerator(DH_ALGO, false);
467                 theGenerator.initialize(mySpec, getRandom());
468 
469                 /* Create the factory */
470                 setKeyFactory(getJavaKeyFactory(DH_ALGO, false));
471 
472             } catch (InvalidAlgorithmParameterException e) {
473                 throw new GordianCryptoException("Failed to create DHgenerator", e);
474             }
475         }
476 
477         @Override
478         public JcaKeyPair generateKeyPair() {
479             /* Generate and return the keyPair */
480             final KeyPair myPair = theGenerator.generateKeyPair();
481             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
482             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
483             return new JcaKeyPair(myPublic, myPrivate);
484         }
485 
486         @Override
487         protected JcaPrivateKey createPrivate(final PrivateKey pPrivateKey) {
488             return new JcaDHPrivateKey(getKeySpec(), (BCDHPrivateKey) pPrivateKey);
489         }
490 
491         @Override
492         protected JcaPublicKey createPublic(final PublicKey pPublicKey) {
493             return new JcaDHPublicKey(getKeySpec(), (BCDHPublicKey) pPublicKey);
494         }
495     }
496 
497     /**
498      * Jca SLHDSA KeyPair generator.
499      */
500     public static class JcaSLHDSAKeyPairGenerator
501             extends JcaKeyPairGenerator {
502         /**
503          * SLHDSA algorithm.
504          */
505         private static final String SLHDSA_ALGO = "SLH-DSA";
506 
507         /**
508          * HASH indication.
509          */
510         private static final String SLHDSA_HASH = "HASH-" + SLHDSA_ALGO;
511 
512         /**
513          * Generator.
514          */
515         private final KeyPairGenerator theGenerator;
516 
517         /**
518          * Constructor.
519          *
520          * @param pFactory the Security Factory
521          * @param pKeySpec the keySpec
522          * @throws GordianException on error
523          */
524         JcaSLHDSAKeyPairGenerator(final GordianBaseFactory pFactory,
525                                   final GordianKeyPairSpec pKeySpec) throws GordianException {
526             /* initialize underlying class */
527             super(pFactory, pKeySpec);
528 
529             /* Protect against exceptions */
530             try {
531                 /* Determine algorithm */
532                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
533                 final String myAlgo = myKeySpec.getSLHDSASpec().isHash() ? SLHDSA_HASH : SLHDSA_ALGO;
534 
535                 /* Create and initialize the generator */
536                 theGenerator = getJavaKeyPairGenerator(myAlgo, false);
537                 final SLHDSAParameterSpec myParms = myKeySpec.getSLHDSASpec().getParameterSpec();
538                 theGenerator.initialize(myParms, getRandom());
539 
540                 /* Create the factory */
541                 setKeyFactory(getJavaKeyFactory(myAlgo, false));
542 
543             } catch (InvalidAlgorithmParameterException e) {
544                 throw new GordianCryptoException("Failed to create SLHDSAgenerator", e);
545             }
546         }
547 
548         @Override
549         public JcaKeyPair generateKeyPair() {
550             /* Generate and return the keyPair */
551             final KeyPair myPair = theGenerator.generateKeyPair();
552             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
553             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
554             return new JcaKeyPair(myPublic, myPrivate);
555         }
556     }
557 
558     /**
559      * Jca CMCE KeyPair generator.
560      */
561     public static class JcaCMCEKeyPairGenerator
562             extends JcaKeyPairGenerator {
563         /**
564          * FRODO algorithm.
565          */
566         private static final String CMCE_ALGO = "CMCE";
567 
568         /**
569          * Generator.
570          */
571         private final KeyPairGenerator theGenerator;
572 
573         /**
574          * Constructor.
575          *
576          * @param pFactory the Security Factory
577          * @param pKeySpec the keySpec
578          * @throws GordianException on error
579          */
580         JcaCMCEKeyPairGenerator(final GordianBaseFactory pFactory,
581                                 final GordianKeyPairSpec pKeySpec) throws GordianException {
582             /* initialize underlying class */
583             super(pFactory, pKeySpec);
584 
585             /* Protect against exceptions */
586             try {
587                 /* Create and initialize the generator */
588                 theGenerator = getJavaKeyPairGenerator(CMCE_ALGO, true);
589                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
590                 final CMCEParameterSpec myParms = myKeySpec.getCMCESpec().getParameterSpec();
591                 theGenerator.initialize(myParms, getRandom());
592 
593                 /* Create the factory */
594                 setKeyFactory(getJavaKeyFactory(CMCE_ALGO, true));
595 
596             } catch (InvalidAlgorithmParameterException e) {
597                 throw new GordianCryptoException("Failed to create CMCEgenerator", e);
598             }
599         }
600 
601         @Override
602         public JcaKeyPair generateKeyPair() {
603             /* Generate and return the keyPair */
604             final KeyPair myPair = theGenerator.generateKeyPair();
605             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
606             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
607             return new JcaKeyPair(myPublic, myPrivate);
608         }
609     }
610 
611     /**
612      * Jca Frodo KeyPair generator.
613      */
614     public static class JcaFrodoKeyPairGenerator
615             extends JcaKeyPairGenerator {
616         /**
617          * FRODO algorithm.
618          */
619         private static final String FRODO_ALGO = "FRODO";
620 
621         /**
622          * Generator.
623          */
624         private final KeyPairGenerator theGenerator;
625 
626         /**
627          * Constructor.
628          *
629          * @param pFactory the Security Factory
630          * @param pKeySpec the keySpec
631          * @throws GordianException on error
632          */
633         JcaFrodoKeyPairGenerator(final GordianBaseFactory pFactory,
634                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
635             /* initialize underlying class */
636             super(pFactory, pKeySpec);
637 
638             /* Protect against exceptions */
639             try {
640                 /* Create and initialize the generator */
641                 theGenerator = getJavaKeyPairGenerator(FRODO_ALGO, true);
642                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
643                 final FrodoParameterSpec myParms = myKeySpec.getFRODOSpec().getParameterSpec();
644                 theGenerator.initialize(myParms, getRandom());
645 
646                 /* Create the factory */
647                 setKeyFactory(getJavaKeyFactory(FRODO_ALGO, true));
648 
649             } catch (InvalidAlgorithmParameterException e) {
650                 throw new GordianCryptoException("Failed to create FRODOgenerator", e);
651             }
652         }
653 
654         @Override
655         public JcaKeyPair generateKeyPair() {
656             /* Generate and return the keyPair */
657             final KeyPair myPair = theGenerator.generateKeyPair();
658             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
659             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
660             return new JcaKeyPair(myPublic, myPrivate);
661         }
662     }
663 
664     /**
665      * Jca SABER KeyPair generator.
666      */
667     public static class JcaSABERKeyPairGenerator
668             extends JcaKeyPairGenerator {
669         /**
670          * SABER algorithm.
671          */
672         private static final String SABER_ALGO = "SABER";
673 
674         /**
675          * Generator.
676          */
677         private final KeyPairGenerator theGenerator;
678 
679         /**
680          * Constructor.
681          *
682          * @param pFactory the Security Factory
683          * @param pKeySpec the keySpec
684          * @throws GordianException on error
685          */
686         JcaSABERKeyPairGenerator(final GordianBaseFactory pFactory,
687                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
688             /* initialize underlying class */
689             super(pFactory, pKeySpec);
690 
691             /* Protect against exceptions */
692             try {
693                 /* Create and initialize the generator */
694                 theGenerator = getJavaKeyPairGenerator(SABER_ALGO, true);
695                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
696                 final SABERParameterSpec myParms = myKeySpec.getSABERSpec().getParameterSpec();
697                 theGenerator.initialize(myParms, getRandom());
698 
699                 /* Create the factory */
700                 setKeyFactory(getJavaKeyFactory(SABER_ALGO, true));
701 
702             } catch (InvalidAlgorithmParameterException e) {
703                 throw new GordianCryptoException("Failed to create SABERgenerator", e);
704             }
705         }
706 
707         @Override
708         public JcaKeyPair generateKeyPair() {
709             /* Generate and return the keyPair */
710             final KeyPair myPair = theGenerator.generateKeyPair();
711             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
712             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
713             return new JcaKeyPair(myPublic, myPrivate);
714         }
715     }
716 
717     /**
718      * Jca MLKEM KeyPair generator.
719      */
720     public static class JcaMLKEMKeyPairGenerator
721             extends JcaKeyPairGenerator {
722         /**
723          * MLKEM algorithm.
724          */
725         private static final String MLKEM_ALGO = "MLKEM";
726 
727         /**
728          * Generator.
729          */
730         private final KeyPairGenerator theGenerator;
731 
732         /**
733          * Constructor.
734          *
735          * @param pFactory the Security Factory
736          * @param pKeySpec the keySpec
737          * @throws GordianException on error
738          */
739         JcaMLKEMKeyPairGenerator(final GordianBaseFactory pFactory,
740                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
741             /* initialize underlying class */
742             super(pFactory, pKeySpec);
743 
744             /* Protect against exceptions */
745             try {
746                 /* Create and initialize the generator */
747                 theGenerator = getJavaKeyPairGenerator(MLKEM_ALGO, false);
748                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
749                 final MLKEMParameterSpec myParms = myKeySpec.getMLKEMSpec().getParameterSpec();
750                 theGenerator.initialize(myParms, getRandom());
751 
752                 /* Create the factory */
753                 setKeyFactory(getJavaKeyFactory(MLKEM_ALGO, false));
754 
755             } catch (InvalidAlgorithmParameterException e) {
756                 throw new GordianCryptoException("Failed to create MLKEMgenerator", e);
757             }
758         }
759 
760         @Override
761         public JcaKeyPair generateKeyPair() {
762             /* Generate and return the keyPair */
763             final KeyPair myPair = theGenerator.generateKeyPair();
764             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
765             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
766             return new JcaKeyPair(myPublic, myPrivate);
767         }
768     }
769 
770     /**
771      * Jca MLDSA KeyPair generator.
772      */
773     public static class JcaMLDSAKeyPairGenerator
774             extends JcaKeyPairGenerator {
775         /**
776          * MLDSA algorithm.
777          */
778         private static final String MLDSA_ALGO = "ML-DSA";
779 
780         /**
781          * HASH indication.
782          */
783         private static final String MLDSA_HASH = "HASH-" + MLDSA_ALGO;
784 
785         /**
786          * Generator.
787          */
788         private final KeyPairGenerator theGenerator;
789 
790         /**
791          * Constructor.
792          *
793          * @param pFactory the Security Factory
794          * @param pKeySpec the keySpec
795          * @throws GordianException on error
796          */
797         JcaMLDSAKeyPairGenerator(final GordianBaseFactory pFactory,
798                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
799             /* initialize underlying class */
800             super(pFactory, pKeySpec);
801 
802             /* Protect against exceptions */
803             try {
804                 /* Determine algorithm */
805                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
806                 final String myAlgo = myKeySpec.getMLDSASpec().isHash() ? MLDSA_HASH : MLDSA_ALGO;
807 
808                 /* Create and initialize the generator */
809                 theGenerator = getJavaKeyPairGenerator(myAlgo, false);
810                 final MLDSAParameterSpec myParms = myKeySpec.getMLDSASpec().getParameterSpec();
811                 theGenerator.initialize(myParms, getRandom());
812 
813                 /* Create the factory */
814                 setKeyFactory(getJavaKeyFactory(myAlgo, false));
815 
816             } catch (InvalidAlgorithmParameterException e) {
817                 throw new GordianCryptoException("Failed to create MLDSAGenerator", e);
818             }
819         }
820 
821         @Override
822         public JcaKeyPair generateKeyPair() {
823             /* Generate and return the keyPair */
824             final KeyPair myPair = theGenerator.generateKeyPair();
825             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
826             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
827             return new JcaKeyPair(myPublic, myPrivate);
828         }
829     }
830 
831     /**
832      * Jca HQC KeyPair generator.
833      */
834     public static class JcaHQCKeyPairGenerator
835             extends JcaKeyPairGenerator {
836         /**
837          * BIKE algorithm.
838          */
839         private static final String HQC_ALGO = "HQC";
840 
841         /**
842          * Generator.
843          */
844         private final KeyPairGenerator theGenerator;
845 
846         /**
847          * Constructor.
848          *
849          * @param pFactory the Security Factory
850          * @param pKeySpec the keySpec
851          * @throws GordianException on error
852          */
853         JcaHQCKeyPairGenerator(final GordianBaseFactory pFactory,
854                                final GordianKeyPairSpec pKeySpec) throws GordianException {
855             /* initialize underlying class */
856             super(pFactory, pKeySpec);
857 
858             /* Protect against exceptions */
859             try {
860                 /* Create and initialize the generator */
861                 theGenerator = getJavaKeyPairGenerator(HQC_ALGO, true);
862                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
863                 final HQCParameterSpec myParms = myKeySpec.getHQCSpec().getParameterSpec();
864                 theGenerator.initialize(myParms, getRandom());
865 
866                 /* Create the factory */
867                 setKeyFactory(getJavaKeyFactory(HQC_ALGO, true));
868 
869             } catch (InvalidAlgorithmParameterException e) {
870                 throw new GordianCryptoException("Failed to create HQCgenerator", e);
871             }
872         }
873 
874         @Override
875         public JcaKeyPair generateKeyPair() {
876             /* Generate and return the keyPair */
877             final KeyPair myPair = theGenerator.generateKeyPair();
878             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
879             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
880             return new JcaKeyPair(myPublic, myPrivate);
881         }
882     }
883 
884     /**
885      * Jca BIKE KeyPair generator.
886      */
887     public static class JcaBIKEKeyPairGenerator
888             extends JcaKeyPairGenerator {
889         /**
890          * BIKE algorithm.
891          */
892         private static final String BIKE_ALGO = "BIKE";
893 
894         /**
895          * Generator.
896          */
897         private final KeyPairGenerator theGenerator;
898 
899         /**
900          * Constructor.
901          *
902          * @param pFactory the Security Factory
903          * @param pKeySpec the keySpec
904          * @throws GordianException on error
905          */
906         JcaBIKEKeyPairGenerator(final GordianBaseFactory pFactory,
907                                 final GordianKeyPairSpec pKeySpec) throws GordianException {
908             /* initialize underlying class */
909             super(pFactory, pKeySpec);
910 
911             /* Protect against exceptions */
912             try {
913                 /* Create and initialize the generator */
914                 theGenerator = getJavaKeyPairGenerator(BIKE_ALGO, true);
915                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
916                 final BIKEParameterSpec myParms = myKeySpec.getBIKESpec().getParameterSpec();
917                 theGenerator.initialize(myParms, getRandom());
918 
919                 /* Create the factory */
920                 setKeyFactory(getJavaKeyFactory(BIKE_ALGO, true));
921 
922             } catch (InvalidAlgorithmParameterException e) {
923                 throw new GordianCryptoException("Failed to create BIKEgenerator", e);
924             }
925         }
926 
927         @Override
928         public JcaKeyPair generateKeyPair() {
929             /* Generate and return the keyPair */
930             final KeyPair myPair = theGenerator.generateKeyPair();
931             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
932             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
933             return new JcaKeyPair(myPublic, myPrivate);
934         }
935     }
936 
937     /**
938      * Jca NTRU KeyPair generator.
939      */
940     public static class JcaNTRUKeyPairGenerator
941             extends JcaKeyPairGenerator {
942         /**
943          * NTRU algorithm.
944          */
945         private static final String NTRU_ALGO = "NTRU";
946 
947         /**
948          * Generator.
949          */
950         private final KeyPairGenerator theGenerator;
951 
952         /**
953          * Constructor.
954          *
955          * @param pFactory the Security Factory
956          * @param pKeySpec the keySpec
957          * @throws GordianException on error
958          */
959         JcaNTRUKeyPairGenerator(final GordianBaseFactory pFactory,
960                                 final GordianKeyPairSpec pKeySpec) throws GordianException {
961             /* initialize underlying class */
962             super(pFactory, pKeySpec);
963 
964             /* Protect against exceptions */
965             try {
966                 /* Create and initialize the generator */
967                 theGenerator = getJavaKeyPairGenerator(NTRU_ALGO, true);
968                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
969                 final NTRUParameterSpec myParms = myKeySpec.getNTRUSpec().getParameterSpec();
970                 theGenerator.initialize(myParms, getRandom());
971 
972                 /* Create the factory */
973                 setKeyFactory(getJavaKeyFactory(NTRU_ALGO, true));
974 
975             } catch (InvalidAlgorithmParameterException e) {
976                 throw new GordianCryptoException("Failed to create NTRUgenerator", e);
977             }
978         }
979 
980         @Override
981         public JcaKeyPair generateKeyPair() {
982             /* Generate and return the keyPair */
983             final KeyPair myPair = theGenerator.generateKeyPair();
984             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
985             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
986             return new JcaKeyPair(myPublic, myPrivate);
987         }
988     }
989 
990     /**
991      * Jca NTRUPlus KeyPair generator.
992      */
993     public static class JcaNTRUPlusKeyPairGenerator
994             extends JcaKeyPairGenerator {
995         /**
996          * NTRU algorithm.
997          */
998         private static final String NTRUPLUS_ALGO = "NTRUPLUS";
999 
1000         /**
1001          * Generator.
1002          */
1003         private final KeyPairGenerator theGenerator;
1004 
1005         /**
1006          * Constructor.
1007          *
1008          * @param pFactory the Security Factory
1009          * @param pKeySpec the keySpec
1010          * @throws GordianException on error
1011          */
1012         JcaNTRUPlusKeyPairGenerator(final GordianBaseFactory pFactory,
1013                                     final GordianKeyPairSpec pKeySpec) throws GordianException {
1014             /* initialize underlying class */
1015             super(pFactory, pKeySpec);
1016 
1017             /* Protect against exceptions */
1018             try {
1019                 /* Create and initialize the generator */
1020                 theGenerator = getJavaKeyPairGenerator(NTRUPLUS_ALGO, true);
1021                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1022                 final NTRUPlusParameterSpec myParms = myKeySpec.getNTRUPlusSpec().getParameterSpec();
1023                 theGenerator.initialize(myParms, getRandom());
1024 
1025                 /* Create the factory */
1026                 setKeyFactory(getJavaKeyFactory(NTRUPLUS_ALGO, true));
1027 
1028             } catch (InvalidAlgorithmParameterException e) {
1029                 throw new GordianCryptoException("Failed to create NTRUPlusGenerator", e);
1030             }
1031         }
1032 
1033         @Override
1034         public JcaKeyPair generateKeyPair() {
1035             /* Generate and return the keyPair */
1036             final KeyPair myPair = theGenerator.generateKeyPair();
1037             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1038             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1039             return new JcaKeyPair(myPublic, myPrivate);
1040         }
1041     }
1042 
1043     /**
1044      * Jca Falcon KeyPair generator.
1045      */
1046     public static class JcaFalconKeyPairGenerator
1047             extends JcaKeyPairGenerator {
1048         /**
1049          * FALCON algorithm.
1050          */
1051         private static final String FALCON_ALGO = "FALCON";
1052 
1053         /**
1054          * Generator.
1055          */
1056         private final KeyPairGenerator theGenerator;
1057 
1058         /**
1059          * Constructor.
1060          *
1061          * @param pFactory the Security Factory
1062          * @param pKeySpec the keySpec
1063          * @throws GordianException on error
1064          */
1065         JcaFalconKeyPairGenerator(final GordianBaseFactory pFactory,
1066                                   final GordianKeyPairSpec pKeySpec) throws GordianException {
1067             /* initialize underlying class */
1068             super(pFactory, pKeySpec);
1069 
1070             /* Protect against exceptions */
1071             try {
1072                 /* Create and initialize the generator */
1073                 theGenerator = getJavaKeyPairGenerator(FALCON_ALGO, true);
1074                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1075                 final FalconParameterSpec myParms = myKeySpec.getFalconSpec().getParameterSpec();
1076                 theGenerator.initialize(myParms, getRandom());
1077 
1078                 /* Create the factory */
1079                 setKeyFactory(getJavaKeyFactory(FALCON_ALGO, true));
1080 
1081             } catch (InvalidAlgorithmParameterException e) {
1082                 throw new GordianCryptoException("Failed to create FALCONgenerator", e);
1083             }
1084         }
1085 
1086         @Override
1087         public JcaKeyPair generateKeyPair() {
1088             /* Generate and return the keyPair */
1089             final KeyPair myPair = theGenerator.generateKeyPair();
1090             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1091             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1092             return new JcaKeyPair(myPublic, myPrivate);
1093         }
1094     }
1095 
1096     /**
1097      * Jca Mayo KeyPair generator.
1098      */
1099     public static class JcaMayoKeyPairGenerator
1100             extends JcaKeyPairGenerator {
1101         /**
1102          * Mayo algorithm.
1103          */
1104         private static final String MAYO_ALGO = "MAYO";
1105 
1106         /**
1107          * Generator.
1108          */
1109         private final KeyPairGenerator theGenerator;
1110 
1111         /**
1112          * Constructor.
1113          *
1114          * @param pFactory the Security Factory
1115          * @param pKeySpec the keySpec
1116          * @throws GordianException on error
1117          */
1118         JcaMayoKeyPairGenerator(final GordianBaseFactory pFactory,
1119                                 final GordianKeyPairSpec pKeySpec) throws GordianException {
1120             /* initialize underlying class */
1121             super(pFactory, pKeySpec);
1122 
1123             /* Protect against exceptions */
1124             try {
1125                 /* Create and initialize the generator */
1126                 theGenerator = getJavaKeyPairGenerator(MAYO_ALGO, true);
1127                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1128                 final MayoParameterSpec myParms = myKeySpec.getMayoSpec().getParameterSpec();
1129                 theGenerator.initialize(myParms, getRandom());
1130 
1131                 /* Create the factory */
1132                 setKeyFactory(getJavaKeyFactory(MAYO_ALGO, true));
1133 
1134             } catch (InvalidAlgorithmParameterException e) {
1135                 throw new GordianCryptoException("Failed to create MayoGenerator", e);
1136             }
1137         }
1138 
1139         @Override
1140         public JcaKeyPair generateKeyPair() {
1141             /* Generate and return the keyPair */
1142             final KeyPair myPair = theGenerator.generateKeyPair();
1143             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1144             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1145             return new JcaKeyPair(myPublic, myPrivate);
1146         }
1147     }
1148 
1149     /**
1150      * Jca Snova KeyPair generator.
1151      */
1152     public static class JcaSnovaKeyPairGenerator
1153             extends JcaKeyPairGenerator {
1154         /**
1155          * Snova algorithm.
1156          */
1157         private static final String SNOVA_ALGO = "SNOVA";
1158 
1159         /**
1160          * Generator.
1161          */
1162         private final KeyPairGenerator theGenerator;
1163 
1164         /**
1165          * Constructor.
1166          *
1167          * @param pFactory the Security Factory
1168          * @param pKeySpec the keySpec
1169          * @throws GordianException on error
1170          */
1171         JcaSnovaKeyPairGenerator(final GordianBaseFactory pFactory,
1172                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
1173             /* initialize underlying class */
1174             super(pFactory, pKeySpec);
1175 
1176             /* Protect against exceptions */
1177             try {
1178                 /* Create and initialize the generator */
1179                 theGenerator = getJavaKeyPairGenerator(SNOVA_ALGO, true);
1180                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1181                 final SnovaParameterSpec myParms = myKeySpec.getSnovaSpec().getParameterSpec();
1182                 theGenerator.initialize(myParms, getRandom());
1183 
1184                 /* Create the factory */
1185                 setKeyFactory(getJavaKeyFactory(SNOVA_ALGO, true));
1186 
1187             } catch (InvalidAlgorithmParameterException e) {
1188                 throw new GordianCryptoException("Failed to create SnovaGenerator", e);
1189             }
1190         }
1191 
1192         @Override
1193         public JcaKeyPair generateKeyPair() {
1194             /* Generate and return the keyPair */
1195             final KeyPair myPair = theGenerator.generateKeyPair();
1196             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1197             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1198             return new JcaKeyPair(myPublic, myPrivate);
1199         }
1200     }
1201 
1202     /**
1203      * Jca NTRULPrime KeyPair generator.
1204      */
1205     public static class JcaNTRULPrimeKeyPairGenerator
1206             extends JcaKeyPairGenerator {
1207         /**
1208          * NTRULPrime algorithm.
1209          */
1210         private static final String NTRU_ALGO = "NTRULPRIME";
1211 
1212         /**
1213          * Generator.
1214          */
1215         private final KeyPairGenerator theGenerator;
1216 
1217         /**
1218          * Constructor.
1219          *
1220          * @param pFactory the Security Factory
1221          * @param pKeySpec the keySpec
1222          * @throws GordianException on error
1223          */
1224         JcaNTRULPrimeKeyPairGenerator(final GordianBaseFactory pFactory,
1225                                       final GordianKeyPairSpec pKeySpec) throws GordianException {
1226             /* initialize underlying class */
1227             super(pFactory, pKeySpec);
1228 
1229             /* Protect against exceptions */
1230             try {
1231                 /* Create and initialize the generator */
1232                 theGenerator = getJavaKeyPairGenerator(NTRU_ALGO, true);
1233                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1234                 final NTRULPRimeParameterSpec myParms = myKeySpec.getNTRUPrimeSpec().getCoreParams().getNTRULParameterSpec();
1235                 theGenerator.initialize(myParms, getRandom());
1236 
1237                 /* Create the factory */
1238                 setKeyFactory(getJavaKeyFactory(NTRU_ALGO, true));
1239 
1240             } catch (InvalidAlgorithmParameterException e) {
1241                 throw new GordianCryptoException("Failed to create NTRULPrimeGenerator", e);
1242             }
1243         }
1244 
1245         @Override
1246         public JcaKeyPair generateKeyPair() {
1247             /* Generate and return the keyPair */
1248             final KeyPair myPair = theGenerator.generateKeyPair();
1249             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1250             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1251             return new JcaKeyPair(myPublic, myPrivate);
1252         }
1253     }
1254 
1255     /**
1256      * Jca SNTRUPrime KeyPair generator.
1257      */
1258     public static class JcaSNTRUPrimeKeyPairGenerator
1259             extends JcaKeyPairGenerator {
1260         /**
1261          * NTRULPrime algorithm.
1262          */
1263         private static final String NTRU_ALGO = "SNTRUPRIME";
1264 
1265         /**
1266          * Generator.
1267          */
1268         private final KeyPairGenerator theGenerator;
1269 
1270         /**
1271          * Constructor.
1272          *
1273          * @param pFactory the Security Factory
1274          * @param pKeySpec the keySpec
1275          * @throws GordianException on error
1276          */
1277         JcaSNTRUPrimeKeyPairGenerator(final GordianBaseFactory pFactory,
1278                                       final GordianKeyPairSpec pKeySpec) throws GordianException {
1279             /* initialize underlying class */
1280             super(pFactory, pKeySpec);
1281 
1282             /* Protect against exceptions */
1283             try {
1284                 /* Create and initialize the generator */
1285                 theGenerator = getJavaKeyPairGenerator(NTRU_ALGO, true);
1286                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1287                 final SNTRUPrimeParameterSpec myParms = myKeySpec.getNTRUPrimeSpec().getCoreParams().getSNTRUParameterSpec();
1288                 theGenerator.initialize(myParms, getRandom());
1289 
1290                 /* Create the factory */
1291                 setKeyFactory(getJavaKeyFactory(NTRU_ALGO, true));
1292 
1293             } catch (InvalidAlgorithmParameterException e) {
1294                 throw new GordianCryptoException("Failed to create SNTRUPrimeGenerator", e);
1295             }
1296         }
1297 
1298         @Override
1299         public JcaKeyPair generateKeyPair() {
1300             /* Generate and return the keyPair */
1301             final KeyPair myPair = theGenerator.generateKeyPair();
1302             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1303             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1304             return new JcaKeyPair(myPublic, myPrivate);
1305         }
1306     }
1307 
1308     /**
1309      * Jca Picnic KeyPair generator.
1310      */
1311     public static class JcaPicnicKeyPairGenerator
1312             extends JcaKeyPairGenerator {
1313         /**
1314          * Picnic algorithm.
1315          */
1316         private static final String PICNIC_ALGO = "PICNIC";
1317 
1318         /**
1319          * Generator.
1320          */
1321         private final KeyPairGenerator theGenerator;
1322 
1323         /**
1324          * Constructor.
1325          *
1326          * @param pFactory the Security Factory
1327          * @param pKeySpec the keySpec
1328          * @throws GordianException on error
1329          */
1330         JcaPicnicKeyPairGenerator(final GordianBaseFactory pFactory,
1331                                   final GordianKeyPairSpec pKeySpec) throws GordianException {
1332             /* initialize underlying class */
1333             super(pFactory, pKeySpec);
1334 
1335             /* Protect against exceptions */
1336             try {
1337                 /* Create and initialize the generator */
1338                 theGenerator = getJavaKeyPairGenerator(PICNIC_ALGO, true);
1339                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1340                 final PicnicParameterSpec myParms = myKeySpec.getPicnicSpec().getParameterSpec();
1341                 theGenerator.initialize(myParms, getRandom());
1342 
1343                 /* Create the factory */
1344                 setKeyFactory(getJavaKeyFactory(PICNIC_ALGO, true));
1345 
1346             } catch (InvalidAlgorithmParameterException e) {
1347                 throw new GordianCryptoException("Failed to create PICNICgenerator", e);
1348             }
1349         }
1350 
1351         @Override
1352         public JcaKeyPair generateKeyPair() {
1353             /* Generate and return the keyPair */
1354             final KeyPair myPair = theGenerator.generateKeyPair();
1355             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1356             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1357             return new JcaKeyPair(myPublic, myPrivate);
1358         }
1359     }
1360 
1361     /**
1362      * Jca XMSS KeyPair generator.
1363      */
1364     public static class JcaXMSSKeyPairGenerator
1365             extends JcaKeyPairGenerator {
1366         /**
1367          * Generator.
1368          */
1369         private final KeyPairGenerator theGenerator;
1370 
1371         /**
1372          * Constructor.
1373          *
1374          * @param pFactory the Security Factory
1375          * @param pKeySpec the keySpec
1376          * @throws GordianException on error
1377          */
1378         JcaXMSSKeyPairGenerator(final GordianBaseFactory pFactory,
1379                                 final GordianKeyPairSpec pKeySpec) throws GordianException {
1380             /* initialize underlying class */
1381             super(pFactory, pKeySpec);
1382 
1383             /* Protect against exceptions */
1384             try {
1385                 /* Access the algorithm */
1386                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1387                 final GordianCoreXMSSSpec myXMSSKeySpec = myKeySpec.getXMSSSpec();
1388                 final boolean isXMSSMT = myXMSSKeySpec.isMT();
1389                 final GordianXMSSDigestType myType = myXMSSKeySpec.getDigestType();
1390 
1391                 /* Create the parameters */
1392                 final AlgorithmParameterSpec myAlgo = isXMSSMT
1393                         ? new XMSSMTParameterSpec(myXMSSKeySpec.getHeight().getHeight(),
1394                         myXMSSKeySpec.getLayers().getLayers(), myType.name())
1395                         : new XMSSParameterSpec(myXMSSKeySpec.getHeight().getHeight(), myType.name());
1396 
1397                 /* Create and initialize the generator */
1398                 final String myJavaType = myXMSSKeySpec.getKeyType().name();
1399                 theGenerator = getJavaKeyPairGenerator(myJavaType, true);
1400                 theGenerator.initialize(myAlgo, getRandom());
1401 
1402                 /* Create the factory */
1403                 setKeyFactory(getJavaKeyFactory(myJavaType, true));
1404 
1405             } catch (InvalidAlgorithmParameterException e) {
1406                 throw new GordianCryptoException("Failed to create XMSSgenerator", e);
1407             }
1408         }
1409 
1410         @Override
1411         public JcaKeyPair generateKeyPair() {
1412             /* Generate and return the keyPair */
1413             final KeyPair myPair = theGenerator.generateKeyPair();
1414             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1415             final JcaStateAwarePrivateKey myPrivate = createPrivate(myPair.getPrivate());
1416             return new JcaStateAwareKeyPair(myPublic, myPrivate);
1417         }
1418 
1419         @Override
1420         protected JcaStateAwarePrivateKey createPrivate(final PrivateKey pPrivateKey) {
1421             return new JcaStateAwarePrivateKey(getKeySpec(), pPrivateKey);
1422         }
1423 
1424         @Override
1425         public JcaKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
1426                                         final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
1427             /* Protect against exceptions */
1428             try {
1429                 /* Check the keySpecs */
1430                 checkKeySpec(pPrivateKey);
1431 
1432                 /* derive keyPair */
1433                 final JcaPublicKey myPublic = derivePublicKey(pPublicKey);
1434                 JcaStateAwarePrivateKey myPrivate = createPrivate(getKeyFactory().generatePrivate(pPrivateKey));
1435                 final JcaKeyPair myPair = new JcaStateAwareKeyPair(myPublic, myPrivate);
1436 
1437                 /* Check that we have a matching pair */
1438                 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
1439 
1440                 /* Rebuild and return the keyPair to avoid incrementing usage count */
1441                 myPrivate = createPrivate(getKeyFactory().generatePrivate(pPrivateKey));
1442                 return new JcaStateAwareKeyPair(myPublic, myPrivate);
1443 
1444             } catch (InvalidKeySpecException e) {
1445                 throw new GordianCryptoException(PARSE_ERROR, e);
1446             }
1447         }
1448     }
1449 
1450     /**
1451      * Jca Edwards KeyPair generator.
1452      */
1453     public static class JcaEdKeyPairGenerator
1454             extends JcaKeyPairGenerator {
1455         /**
1456          * Generator.
1457          */
1458         private final KeyPairGenerator theGenerator;
1459 
1460         /**
1461          * Constructor.
1462          *
1463          * @param pFactory the Security Factory
1464          * @param pKeySpec the keySpec
1465          * @throws GordianException on error
1466          */
1467         protected JcaEdKeyPairGenerator(final GordianBaseFactory pFactory,
1468                                         final GordianKeyPairSpec pKeySpec) throws GordianException {
1469             /* initialize underlying class */
1470             super(pFactory, pKeySpec);
1471 
1472             /* Protect against exceptions */
1473             try {
1474                 /* Create the parameters */
1475                 final AlgorithmParameterSpec myAlgo;
1476                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1477                 final boolean is25519 = myKeySpec.getEdwardsSpec().is25519();
1478                 myAlgo = switch (pKeySpec.getKeyPairType()) {
1479                     case XDH -> is25519
1480                             ? new XDHParameterSpec(XDHParameterSpec.X25519)
1481                             : new XDHParameterSpec(XDHParameterSpec.X448);
1482                     case EDDSA -> is25519
1483                             ? new EdDSAParameterSpec(EdDSAParameterSpec.Ed25519)
1484                             : new EdDSAParameterSpec(EdDSAParameterSpec.Ed448);
1485                     default -> throw new GordianLogicException("Invalid KeySpec" + pKeySpec);
1486                 };
1487 
1488                 /* Create and initialize the generator */
1489                 final String myJavaType = pKeySpec.toString();
1490                 theGenerator = getJavaKeyPairGenerator(myJavaType, false);
1491                 theGenerator.initialize(myAlgo, getRandom());
1492 
1493                 /* Create the factory */
1494                 setKeyFactory(getJavaKeyFactory(myJavaType, false));
1495 
1496             } catch (InvalidAlgorithmParameterException e) {
1497                 throw new GordianCryptoException("Failed to create EdwardsGenerator", e);
1498             }
1499         }
1500 
1501         @Override
1502         public JcaKeyPair generateKeyPair() {
1503             /* Generate and return the keyPair */
1504             final KeyPair myPair = theGenerator.generateKeyPair();
1505             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1506             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1507             return new JcaKeyPair(myPublic, myPrivate);
1508         }
1509     }
1510 
1511     /**
1512      * Jca NewHope KeyPair generator.
1513      */
1514     public static class JcaNewHopeKeyPairGenerator
1515             extends JcaKeyPairGenerator {
1516         /**
1517          * NewHope algorithm.
1518          */
1519         private static final String NEWHOPE_ALGO = "NH";
1520 
1521         /**
1522          * Generator.
1523          */
1524         private final KeyPairGenerator theGenerator;
1525 
1526         /**
1527          * Constructor.
1528          *
1529          * @param pFactory the Security Factory
1530          * @param pKeySpec the keySpec
1531          * @throws GordianException on error
1532          */
1533         JcaNewHopeKeyPairGenerator(final GordianBaseFactory pFactory,
1534                                    final GordianKeyPairSpec pKeySpec) throws GordianException {
1535             /* initialize underlying class */
1536             super(pFactory, pKeySpec);
1537 
1538             /* Create and initialize the generator */
1539             theGenerator = getJavaKeyPairGenerator(NEWHOPE_ALGO, true);
1540             theGenerator.initialize(GordianLength.LEN_1024.getLength(), getRandom());
1541 
1542             /* Create the factory */
1543             setKeyFactory(getJavaKeyFactory(NEWHOPE_ALGO, true));
1544         }
1545 
1546         @Override
1547         public JcaKeyPair generateKeyPair() {
1548             /* Generate and return the keyPair */
1549             final KeyPair myPair = theGenerator.generateKeyPair();
1550             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1551             final JcaPrivateKey myPrivate = createPrivate(myPair.getPrivate());
1552             return new JcaKeyPair(myPublic, myPrivate);
1553         }
1554     }
1555 
1556     /**
1557      * Jca LMS KeyPair generator.
1558      */
1559     public static class JcaLMSKeyPairGenerator
1560             extends JcaKeyPairGenerator {
1561         /**
1562          * Generator.
1563          */
1564         private final KeyPairGenerator theGenerator;
1565 
1566         /**
1567          * Constructor.
1568          *
1569          * @param pFactory the Security Factory
1570          * @param pKeySpec the keySpec
1571          * @throws GordianException on error
1572          */
1573         JcaLMSKeyPairGenerator(final GordianBaseFactory pFactory,
1574                                final GordianKeyPairSpec pKeySpec) throws GordianException {
1575             /* initialize underlying class */
1576             super(pFactory, pKeySpec);
1577 
1578             /* Create and initialize the generator */
1579             final String myJavaType = pKeySpec.getKeyPairType().toString();
1580             theGenerator = getJavaKeyPairGenerator(myJavaType, true);
1581 
1582             /* Protect against exceptions */
1583             try {
1584                 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
1585                 final AlgorithmParameterSpec myParms = deriveParameters(myKeySpec.getLMSSpec());
1586                 theGenerator.initialize(myParms, getRandom());
1587 
1588             } catch (InvalidAlgorithmParameterException e) {
1589                 throw new GordianCryptoException("Failed to initialize generator", e);
1590             }
1591 
1592             /* Create the factory */
1593             setKeyFactory(getJavaKeyFactory(myJavaType, true));
1594         }
1595 
1596         /**
1597          * Derive the parameters.
1598          *
1599          * @param pKeySpec the keySPec
1600          * @return the parameters.
1601          */
1602         private static LMSHSSKeyGenParameterSpec deriveParameters(final GordianCoreLMSSpec pKeySpec) {
1603             /* Generate and return the keyPair */
1604             final LMSKeyGenParameterSpec[] myParams = new LMSKeyGenParameterSpec[pKeySpec.getTreeDepth()];
1605             final LMSParameters myParms = pKeySpec.getParameters();
1606             final LMSKeyGenParameterSpec myKeyGen = new LMSKeyGenParameterSpec(myParms.getLMSigParam(), myParms.getLMOTSParam());
1607             Arrays.fill(myParams, myKeyGen);
1608             return new LMSHSSKeyGenParameterSpec(myParams);
1609         }
1610 
1611         @Override
1612         public JcaKeyPair generateKeyPair() {
1613             /* Generate and return the keyPair */
1614             final KeyPair myPair = theGenerator.generateKeyPair();
1615             final JcaPublicKey myPublic = createPublic(myPair.getPublic());
1616             final JcaStateAwarePrivateKey myPrivate = createPrivate(myPair.getPrivate());
1617             return new JcaStateAwareKeyPair(myPublic, myPrivate);
1618         }
1619 
1620         @Override
1621         protected JcaStateAwarePrivateKey createPrivate(final PrivateKey pPrivateKey) {
1622             return new JcaStateAwarePrivateKey(getKeySpec(), pPrivateKey);
1623         }
1624 
1625         @Override
1626         public JcaKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
1627                                         final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
1628             /* Protect against exceptions */
1629             try {
1630                 /* Check the keySpecs */
1631                 checkKeySpec(pPrivateKey);
1632 
1633                 /* derive keyPair */
1634                 final JcaPublicKey myPublic = derivePublicKey(pPublicKey);
1635                 JcaStateAwarePrivateKey myPrivate = createPrivate(getKeyFactory().generatePrivate(pPrivateKey));
1636                 final JcaKeyPair myPair = new JcaStateAwareKeyPair(myPublic, myPrivate);
1637 
1638                 /* Check that we have a matching pair */
1639                 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
1640 
1641                 /* Rebuild and return the keyPair to avoid incrementing usage count */
1642                 myPrivate = createPrivate(getKeyFactory().generatePrivate(pPrivateKey));
1643                 return new JcaStateAwareKeyPair(myPublic, myPrivate);
1644 
1645             } catch (InvalidKeySpecException e) {
1646                 throw new GordianCryptoException(PARSE_ERROR, e);
1647             }
1648         }
1649     }
1650 
1651     /**
1652      * Create the BouncyCastle KeyFactory via JCA.
1653      *
1654      * @param pAlgorithm  the Algorithm
1655      * @param postQuantum is this a postQuantum algorithm?
1656      * @return the KeyFactory
1657      * @throws GordianException on error
1658      */
1659     static KeyFactory getJavaKeyFactory(final String pAlgorithm,
1660                                         final boolean postQuantum) throws GordianException {
1661         /* Protect against exceptions */
1662         try {
1663             /* Return a KeyFactory for the algorithm */
1664             return KeyFactory.getInstance(pAlgorithm, postQuantum
1665                     ? JcaProvider.BCPQPROV
1666                     : JcaProvider.BCPROV);
1667 
1668             /* Catch exceptions */
1669         } catch (NoSuchAlgorithmException e) {
1670             /* Throw the exception */
1671             throw new GordianCryptoException("Failed to create KeyFactory", e);
1672         }
1673     }
1674 
1675     /**
1676      * Create the BouncyCastle KeyPairGenerator via JCA.
1677      *
1678      * @param pAlgorithm  the Algorithm
1679      * @param postQuantum is this a postQuantum algorithm?
1680      * @return the KeyPairGenerator
1681      * @throws GordianException on error
1682      */
1683     static KeyPairGenerator getJavaKeyPairGenerator(final String pAlgorithm,
1684                                                     final boolean postQuantum) throws GordianException {
1685         /* Protect against exceptions */
1686         try {
1687             /* Return a KeyPairGenerator for the algorithm */
1688             return KeyPairGenerator.getInstance(pAlgorithm, postQuantum
1689                     ? JcaProvider.BCPQPROV
1690                     : JcaProvider.BCPROV);
1691 
1692             /* Catch exceptions */
1693         } catch (NoSuchAlgorithmException e) {
1694             /* Throw the exception */
1695             throw new GordianCryptoException("Failed to create KeyPairGenerator", e);
1696         }
1697     }
1698 }