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.digest.GordianDigestSpec;
22  import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestType;
23  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianEdwardsElliptic;
24  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
25  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPairType;
26  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianXMSSKeySpec;
27  import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianSignParams;
28  import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianSignatureSpec;
29  import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianSignatureType;
30  import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
31  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
32  import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
33  import org.bouncycastle.jcajce.spec.ContextParameterSpec;
34  
35  import java.security.InvalidAlgorithmParameterException;
36  import java.security.InvalidKeyException;
37  import java.security.NoSuchAlgorithmException;
38  import java.security.Signature;
39  import java.security.SignatureException;
40  
41  /**
42   * Jca implementation of signature.
43   */
44  public abstract class JcaSignature
45          extends GordianCoreSignature {
46      /**
47       * The Signature error.
48       */
49      private static final String SIG_ERROR = "Signature error";
50  
51      /**
52       * The RSA PSS MGF1 Algorithm.
53       */
54      private static final String RSA_PSSMGF1_ALGOBASE = "withRSAandMGF1";
55  
56      /**
57       * The RSA PSS SHAKE128 Algorithm.
58       */
59      private static final String RSA_PSS128_ALGOBASE = "withRSAandSHAKE128";
60  
61      /**
62       * The RSA PSS SHAKE256 Algorithm.
63       */
64      private static final String RSA_PSS256_ALGOBASE = "withRSAandSHAKE256";
65  
66      /**
67       * The RSA PSS PureSHAKE Algorithm.
68       */
69      private static final String RSA_PSSSHAKE_ALGOBASE = "withRSA/PSS";
70  
71      /**
72       * The RSA X9.31 Algorithm.
73       */
74      private static final String RSA_X931_ALGOBASE = "withRSA/X9.31";
75  
76      /**
77       * The RSA ISO9796d2 Algorithm.
78       */
79      private static final String RSA_ISO9796D2_ALGOBASE = "withRSA/ISO9796-2";
80  
81      /**
82       * The RSA preHash Algorithm.
83       */
84      private static final String RSA_PREHASH_ALGOBASE = "withRSAEncryption";
85  
86      /**
87       * The ECDSA Signature.
88       */
89      private static final String EC_DSA_ALGOBASE = "withECDSA";
90  
91      /**
92       * The ECDDSA Signature.
93       */
94      private static final String EC_DDSA_ALGOBASE = "withECDDSA";
95  
96      /**
97       * The DSA Signature.
98       */
99      private static final String DSA_ALGOBASE = "withDSA";
100 
101     /**
102      * The DDSA Signature.
103      */
104     private static final String DDSA_ALGOBASE = "withDDSA";
105 
106     /**
107      * The ECNR Signature.
108      */
109     private static final String EC_NR_ALGOBASE = "withECNR";
110 
111     /**
112      * The SM2 Signature.
113      */
114     private static final String EC_SM2_ALGOBASE = "WITHSM2";
115 
116     /**
117      * The DSTU Signature.
118      */
119     private static final String DSTU_SIGN = "DSTU4145";
120 
121     /**
122      * The PQC Hash prefix.
123      */
124     private static final String PQC_HASH_PFX = "HASH-";
125 
126     /**
127      * The RSA Signer.
128      */
129     private Signature theSigner;
130 
131     /**
132      * Constructor.
133      *
134      * @param pFactory the factory
135      * @param pSpec    the signature Spec
136      */
137     JcaSignature(final GordianBaseFactory pFactory,
138                  final GordianSignatureSpec pSpec) {
139         super(pFactory, pSpec);
140     }
141 
142     /**
143      * Set the signer.
144      *
145      * @param pSigner the signer.
146      */
147     protected void setSigner(final Signature pSigner) {
148         theSigner = pSigner;
149     }
150 
151     /**
152      * Obtain the signer.
153      *
154      * @return the signer.
155      */
156     protected Signature getSigner() {
157         return theSigner;
158     }
159 
160     @Override
161     public void initForSigning(final GordianSignParams pParams) throws GordianException {
162         /* Initialise detail */
163         super.initForSigning(pParams);
164         final JcaKeyPair myPair = getKeyPair();
165         final byte[] myContext = getContext();
166         JcaKeyPair.checkKeyPair(myPair);
167 
168         /* Initialise for signing */
169         try {
170             /* Determine whether we should use random for signatures */
171             final boolean useRandom = getSignatureSpec().getKeyPairType().useRandomForSignatures();
172 
173             /* Initialise the signing */
174             if (useRandom) {
175                 getSigner().initSign(myPair.getPrivateKey().getPrivateKey(), getRandom());
176             } else {
177                 getSigner().initSign(myPair.getPrivateKey().getPrivateKey());
178             }
179 
180             /* If we support context */
181             if (getSignatureSpec().supportsContext()) {
182                 /* Declare the context to the signer */
183                 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
184                 getSigner().setParameter(mySpec);
185             }
186 
187             /* Catch exceptions */
188         } catch (InvalidKeyException
189                  | InvalidAlgorithmParameterException e) {
190             throw new GordianCryptoException(SIG_ERROR, e);
191         }
192     }
193 
194     @Override
195     public void initForVerify(final GordianSignParams pParams) throws GordianException {
196         /* Initialise detail */
197         super.initForVerify(pParams);
198         final JcaKeyPair myPair = getKeyPair();
199         final byte[] myContext = getContext();
200         JcaKeyPair.checkKeyPair(myPair);
201 
202         /* Initialise for signing */
203         try {
204             /* Initialise for verification */
205             getSigner().initVerify(myPair.getPublicKey().getPublicKey());
206 
207             /* If we support context */
208             if (getSignatureSpec().supportsContext()) {
209                 /* Declare the context to the signer */
210                 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
211                 getSigner().setParameter(mySpec);
212             }
213 
214             /* Catch exceptions */
215         } catch (InvalidKeyException
216                  | InvalidAlgorithmParameterException e) {
217             throw new GordianCryptoException(SIG_ERROR, e);
218         }
219     }
220 
221     @Override
222     public void update(final byte[] pBytes,
223                        final int pOffset,
224                        final int pLength) {
225         try {
226             theSigner.update(pBytes, pOffset, pLength);
227         } catch (SignatureException e) {
228             throw new IllegalArgumentException(e);
229         }
230     }
231 
232     @Override
233     public void update(final byte pByte) {
234         try {
235             theSigner.update(pByte);
236         } catch (SignatureException e) {
237             throw new IllegalArgumentException(e);
238         }
239     }
240 
241     @Override
242     public byte[] sign() throws GordianException {
243         /* Check that we are in signing mode */
244         checkMode(GordianSignatureMode.SIGN);
245 
246         /* Protect against exception */
247         try {
248             return getSigner().sign();
249 
250         } catch (SignatureException e) {
251             throw new GordianCryptoException(SIG_ERROR, e);
252         }
253     }
254 
255     @Override
256     public boolean verify(final byte[] pSignature) throws GordianException {
257         /* Check that we are in verify mode */
258         checkMode(GordianSignatureMode.VERIFY);
259 
260         /* Protect against exception */
261         try {
262             return getSigner().verify(pSignature);
263         } catch (SignatureException e) {
264             throw new GordianCryptoException(SIG_ERROR, e);
265         }
266     }
267 
268     @Override
269     public void reset() {
270         /* NoOp */
271     }
272 
273     @Override
274     protected JcaKeyPair getKeyPair() {
275         return (JcaKeyPair) super.getKeyPair();
276     }
277 
278     /**
279      * RSA signature.
280      */
281     static class JcaRSASignature
282             extends JcaSignature {
283         /**
284          * Constructor.
285          *
286          * @param pFactory       the factory
287          * @param pSignatureSpec the signatureSpec
288          * @throws GordianException on error
289          */
290         JcaRSASignature(final GordianBaseFactory pFactory,
291                         final GordianSignatureSpec pSignatureSpec) throws GordianException {
292             /* Initialise class */
293             super(pFactory, pSignatureSpec);
294 
295             /* Create the signature class */
296             final String myDigest = JcaDigest.getSignAlgorithm(pSignatureSpec.getDigestSpec());
297             setSigner(getJavaSignature(myDigest + getSignatureBase(pSignatureSpec), false));
298         }
299     }
300 
301     /**
302      * Obtain Signer base.
303      *
304      * @param pSignatureSpec the signatureSpec
305      * @return the base
306      */
307     static String getSignatureBase(final GordianSignatureSpec pSignatureSpec) {
308         /* Handle SM2 explicitly */
309         if (GordianKeyPairType.SM2.equals(pSignatureSpec.getKeyPairType())) {
310             return EC_SM2_ALGOBASE;
311         }
312 
313         /* Note if we are DSA */
314         final boolean isDSA = GordianKeyPairType.DSA.equals(pSignatureSpec.getKeyPairType());
315         final boolean isSHAKE = GordianDigestType.SHAKE.equals(pSignatureSpec.getDigestSpec().getDigestType());
316 
317         /* Switch on signature type */
318         switch (pSignatureSpec.getSignatureType()) {
319             case PSSMGF1:
320                 return RSA_PSSMGF1_ALGOBASE;
321             case PSS128:
322                 return isSHAKE ? RSA_PSSSHAKE_ALGOBASE : RSA_PSS128_ALGOBASE;
323             case PSS256:
324                 return isSHAKE ? RSA_PSSSHAKE_ALGOBASE : RSA_PSS256_ALGOBASE;
325             case X931:
326                 return RSA_X931_ALGOBASE;
327             case ISO9796D2:
328                 return RSA_ISO9796D2_ALGOBASE;
329             case PREHASH:
330                 return RSA_PREHASH_ALGOBASE;
331             case DSA:
332                 return isDSA
333                         ? DSA_ALGOBASE
334                         : EC_DSA_ALGOBASE;
335             case DDSA:
336                 return isDSA
337                         ? DDSA_ALGOBASE
338                         : EC_DDSA_ALGOBASE;
339             case NR:
340                 return EC_NR_ALGOBASE;
341             default:
342                 return null;
343         }
344     }
345 
346     /**
347      * DSA signer.
348      */
349     static class JcaDSASignature
350             extends JcaSignature {
351         /**
352          * Constructor.
353          *
354          * @param pFactory       the factory
355          * @param pSignatureSpec the signatureSpec
356          * @throws GordianException on error
357          */
358         JcaDSASignature(final GordianBaseFactory pFactory,
359                         final GordianSignatureSpec pSignatureSpec) throws GordianException {
360             /* Initialise class */
361             super(pFactory, pSignatureSpec);
362 
363             /* Create the signature class */
364             final String myDigest = JcaDigest.getSignAlgorithm(pSignatureSpec.getDigestSpec());
365             setSigner(getJavaSignature(myDigest + getSignatureBase(pSignatureSpec), false));
366         }
367     }
368 
369     /**
370      * GOST signature.
371      */
372     static class JcaGOSTSignature
373             extends JcaSignature {
374         /**
375          * Constructor.
376          *
377          * @param pFactory       the factory
378          * @param pSignatureSpec the signatureSpec
379          * @throws GordianException on error
380          */
381         JcaGOSTSignature(final GordianBaseFactory pFactory,
382                          final GordianSignatureSpec pSignatureSpec) throws GordianException {
383             /* Initialise class */
384             super(pFactory, pSignatureSpec);
385 
386             /* Create the signature class */
387             setSigner(getJavaSignature(getSignature(pSignatureSpec), false));
388         }
389 
390         /**
391          * Obtain Signer base.
392          *
393          * @param pSignatureSpec the signatureSpec
394          * @return the base
395          */
396         private static String getSignature(final GordianSignatureSpec pSignatureSpec) {
397             /* Handle DSTU explicitly */
398             if (GordianKeyPairType.DSTU4145.equals(pSignatureSpec.getKeyPairType())) {
399                 return DSTU_SIGN;
400             }
401 
402             /* Obtain the digest length */
403             final GordianLength myLength = pSignatureSpec.getDigestSpec().getDigestLength();
404 
405             /* Build the algorithm */
406             return "GOST3411-2012-"
407                     + myLength.getLength()
408                     + "withECGOST3410-2012-"
409                     + myLength.getLength();
410         }
411     }
412 
413     /**
414      * SLHDSA signature.
415      */
416     static class JcaSLHDSASignature
417             extends JcaSignature {
418         /**
419          * Base name.
420          */
421         private static final String BASE_NAME = "SLH-DSA";
422 
423         /**
424          * Constructor.
425          *
426          * @param pFactory       the factory
427          * @param pSignatureSpec the signatureSpec
428          */
429         JcaSLHDSASignature(final GordianBaseFactory pFactory,
430                            final GordianSignatureSpec pSignatureSpec) {
431             /* Initialise class */
432             super(pFactory, pSignatureSpec);
433         }
434 
435         @Override
436         public void initForSigning(final GordianSignParams pParams) throws GordianException {
437             /* Determine the required signer */
438             final GordianKeyPair myPair = pParams.getKeyPair();
439             JcaKeyPair.checkKeyPair(myPair);
440             final String mySignName = getAlgorithmForKeyPair(myPair);
441             setSigner(getJavaSignature(mySignName, false));
442 
443             /* pass on call */
444             super.initForSigning(pParams);
445         }
446 
447         @Override
448         public void initForVerify(final GordianSignParams pParams) throws GordianException {
449             /* Determine the required signer */
450             final GordianKeyPair myPair = pParams.getKeyPair();
451             JcaKeyPair.checkKeyPair(myPair);
452             final String mySignName = getAlgorithmForKeyPair(myPair);
453             setSigner(getJavaSignature(mySignName, false));
454 
455             /* pass on call */
456             super.initForVerify(pParams);
457         }
458 
459         /**
460          * Obtain algorithmName for keyPair.
461          *
462          * @param pKeyPair the keyPair
463          * @return the name
464          */
465         private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
466             /* Build the algorithm */
467             final boolean isHash = pKeyPair.getKeyPairSpec().getSLHDSAKeySpec().isHash();
468             return isHash ? PQC_HASH_PFX + BASE_NAME : BASE_NAME;
469         }
470     }
471 
472     /**
473      * MLDSA signature.
474      */
475     static class JcaMLDSASignature
476             extends JcaSignature {
477         /**
478          * Base name.
479          */
480         private static final String BASE_NAME = "ML-DSA";
481 
482         /**
483          * Constructor.
484          *
485          * @param pFactory       the factory
486          * @param pSignatureSpec the signatureSpec
487          */
488         JcaMLDSASignature(final GordianBaseFactory pFactory,
489                           final GordianSignatureSpec pSignatureSpec) {
490             /* Initialise class */
491             super(pFactory, pSignatureSpec);
492         }
493 
494         @Override
495         public void initForSigning(final GordianSignParams pParams) throws GordianException {
496             /* Determine the required signer */
497             final GordianKeyPair myPair = pParams.getKeyPair();
498             JcaKeyPair.checkKeyPair(myPair);
499             final String mySignName = getAlgorithmForKeyPair(myPair);
500             setSigner(getJavaSignature(mySignName, false));
501 
502             /* pass on call */
503             super.initForSigning(pParams);
504         }
505 
506         @Override
507         public void initForVerify(final GordianSignParams pParams) throws GordianException {
508             /* Determine the required signer */
509             final GordianKeyPair myPair = pParams.getKeyPair();
510             JcaKeyPair.checkKeyPair(myPair);
511             final String mySignName = getAlgorithmForKeyPair(myPair);
512             setSigner(getJavaSignature(mySignName, false));
513 
514             /* pass on call */
515             super.initForVerify(pParams);
516         }
517 
518         /**
519          * Obtain algorithmName for keyPair.
520          *
521          * @param pKeyPair the keyPair
522          * @return the name
523          */
524         private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
525             /* Build the algorithm */
526             final boolean isHash = pKeyPair.getKeyPairSpec().getMLDSAKeySpec().isHash();
527             return isHash ? PQC_HASH_PFX + BASE_NAME : BASE_NAME;
528         }
529     }
530 
531     /**
532      * Falcon signature.
533      */
534     static class JcaFalconSignature
535             extends JcaSignature {
536         /**
537          * Constructor.
538          *
539          * @param pFactory       the factory
540          * @param pSignatureSpec the signatureSpec
541          * @throws GordianException on error
542          */
543         JcaFalconSignature(final GordianBaseFactory pFactory,
544                            final GordianSignatureSpec pSignatureSpec) throws GordianException {
545             /* Initialise class */
546             super(pFactory, pSignatureSpec);
547 
548             /* Create the signature class */
549             setSigner(getJavaSignature("FALCON", true));
550         }
551     }
552 
553     /**
554      * Mayo signature.
555      */
556     static class JcaMayoSignature
557             extends JcaSignature {
558         /**
559          * Constructor.
560          *
561          * @param pFactory       the factory
562          * @param pSignatureSpec the signatureSpec
563          * @throws GordianException on error
564          */
565         JcaMayoSignature(final GordianBaseFactory pFactory,
566                          final GordianSignatureSpec pSignatureSpec) throws GordianException {
567             /* Initialise class */
568             super(pFactory, pSignatureSpec);
569 
570             /* Create the signature class */
571             setSigner(getJavaSignature("MAYO", true));
572         }
573     }
574 
575     /**
576      * Snova signature.
577      */
578     static class JcaSnovaSignature
579             extends JcaSignature {
580         /**
581          * Constructor.
582          *
583          * @param pFactory       the factory
584          * @param pSignatureSpec the signatureSpec
585          * @throws GordianException on error
586          */
587         JcaSnovaSignature(final GordianBaseFactory pFactory,
588                           final GordianSignatureSpec pSignatureSpec) throws GordianException {
589             /* Initialise class */
590             super(pFactory, pSignatureSpec);
591 
592             /* Create the signature class */
593             setSigner(getJavaSignature("SNOVA", true));
594         }
595     }
596 
597     /**
598      * Picnic signature.
599      */
600     static class JcaPicnicSignature
601             extends JcaSignature {
602         /**
603          * SIgnature base.
604          */
605         private static final String BASE_NAME = "PICNIC";
606 
607         /**
608          * Constructor.
609          *
610          * @param pFactory       the factory
611          * @param pSignatureSpec the signatureSpec
612          * @throws GordianException on error
613          */
614         JcaPicnicSignature(final GordianBaseFactory pFactory,
615                            final GordianSignatureSpec pSignatureSpec) throws GordianException {
616             /* Initialise class */
617             super(pFactory, pSignatureSpec);
618 
619             /* Create the signature class */
620             final String myName = determineSignatureName(pSignatureSpec);
621             setSigner(getJavaSignature(myName, true));
622         }
623 
624         /**
625          * Determine signatureName.
626          *
627          * @param pSignatureSpec the signatureSpec
628          * @return the algorithm name
629          */
630         private static String determineSignatureName(final GordianSignatureSpec pSignatureSpec) {
631             /* If we do not have a digest */
632             if (pSignatureSpec.getSignatureSpec() == null) {
633                 return BASE_NAME;
634             }
635 
636             /* Switch on digest Type */
637             switch (pSignatureSpec.getDigestSpec().getDigestType()) {
638                 case SHA2:
639                     return "SHA512With" + BASE_NAME;
640                 case SHA3:
641                     return "SHA3-512With" + BASE_NAME;
642                 case SHAKE:
643                     return "SHAKE256With" + BASE_NAME;
644                 default:
645                     throw new IllegalArgumentException("Bad SignatureSpec");
646             }
647         }
648 
649     }
650 
651     /**
652      * XMSS signature.
653      */
654     static class JcaXMSSSignature
655             extends JcaSignature {
656         /**
657          * Is this a preHash signature?
658          */
659         private final boolean preHash;
660 
661         /**
662          * Constructor.
663          *
664          * @param pFactory       the factory
665          * @param pSignatureSpec the signatureSpec
666          */
667         JcaXMSSSignature(final GordianBaseFactory pFactory,
668                          final GordianSignatureSpec pSignatureSpec) {
669             /* Initialise class */
670             super(pFactory, pSignatureSpec);
671 
672             /* Determine preHash */
673             preHash = GordianSignatureType.PREHASH.equals(pSignatureSpec.getSignatureType());
674         }
675 
676         @Override
677         public void initForSigning(final GordianSignParams pParams) throws GordianException {
678             /* Determine the required signer */
679             final GordianKeyPair myPair = pParams.getKeyPair();
680             JcaKeyPair.checkKeyPair(myPair);
681             final String mySignName = getAlgorithmForKeyPair(myPair);
682             setSigner(getJavaSignature(mySignName, true));
683 
684             /* pass on call */
685             super.initForSigning(pParams);
686         }
687 
688         @Override
689         public void initForVerify(final GordianSignParams pParams) throws GordianException {
690             /* Determine the required signer */
691             final GordianKeyPair myPair = pParams.getKeyPair();
692             JcaKeyPair.checkKeyPair(myPair);
693             final String mySignName = getAlgorithmForKeyPair(myPair);
694             setSigner(getJavaSignature(mySignName, true));
695 
696             /* pass on call */
697             super.initForVerify(pParams);
698         }
699 
700         /**
701          * Obtain algorithmName for keyPair.
702          *
703          * @param pKeyPair the keyPair
704          * @return the name
705          * @throws GordianException on error
706          */
707         private String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) throws GordianException {
708             /* Determine the required signer */
709             final GordianXMSSKeySpec myXMSSKeySpec = pKeyPair.getKeyPairSpec().getXMSSKeySpec();
710             final GordianDigestSpec myDigestSpec = myXMSSKeySpec.getDigestType().getDigestSpec();
711             final String myDigest = JcaDigest.getAlgorithm(myDigestSpec);
712 
713             /* Create builder */
714             final StringBuilder myBuilder = new StringBuilder();
715             myBuilder.append(myXMSSKeySpec.getKeyType().name())
716                     .append('-')
717                     .append(myDigest);
718             if (preHash) {
719                 myBuilder.insert(0, "with")
720                         .insert(0, myDigest);
721             }
722 
723             /* Build the algorithm */
724             return myBuilder.toString();
725         }
726     }
727 
728     /**
729      * EdDSA signature.
730      */
731     static class JcaEdDSASignature
732             extends JcaSignature {
733         /**
734          * Constructor.
735          *
736          * @param pFactory       the factory
737          * @param pSignatureSpec the signatureSpec
738          */
739         JcaEdDSASignature(final GordianBaseFactory pFactory,
740                           final GordianSignatureSpec pSignatureSpec) {
741             /* Initialise class */
742             super(pFactory, pSignatureSpec);
743         }
744 
745         @Override
746         public void initForSigning(final GordianSignParams pParams) throws GordianException {
747             /* Determine the required signer */
748             final GordianKeyPair myPair = pParams.getKeyPair();
749             JcaKeyPair.checkKeyPair(myPair);
750             final String mySignName = getAlgorithmForKeyPair(myPair);
751             setSigner(getJavaSignature(mySignName, false));
752 
753             /* pass on call */
754             super.initForSigning(pParams);
755         }
756 
757         @Override
758         public void initForVerify(final GordianSignParams pParams) throws GordianException {
759             /* Determine the required signer */
760             final GordianKeyPair myPair = pParams.getKeyPair();
761             JcaKeyPair.checkKeyPair(myPair);
762             final String mySignName = getAlgorithmForKeyPair(myPair);
763             setSigner(getJavaSignature(mySignName, false));
764 
765             /* pass on call */
766             super.initForVerify(pParams);
767         }
768 
769         /**
770          * Obtain algorithmName for keyPair.
771          *
772          * @param pKeyPair the keyPair
773          * @return the name
774          */
775         private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
776             /* Determine the required signer */
777             final GordianEdwardsElliptic myEdwards = pKeyPair.getKeyPairSpec().getEdwardsElliptic();
778             final boolean is25519 = myEdwards.is25519();
779 
780             /* Build the algorithm */
781             return is25519 ? "Ed25519" : "Ed448";
782         }
783     }
784 
785     /**
786      * LMS signature.
787      */
788     static class JcaLMSSignature
789             extends JcaSignature {
790         /**
791          * Constructor.
792          *
793          * @param pFactory       the factory
794          * @param pSignatureSpec the signatureSpec
795          * @throws GordianException on error
796          */
797         JcaLMSSignature(final GordianBaseFactory pFactory,
798                         final GordianSignatureSpec pSignatureSpec) throws GordianException {
799             /* Initialise class */
800             super(pFactory, pSignatureSpec);
801 
802             /* Create the signature class */
803             setSigner(getJavaSignature("LMS", true));
804         }
805     }
806 
807     /**
808      * Create the BouncyCastle Signature via JCA.
809      *
810      * @param pAlgorithm  the Algorithm
811      * @param postQuantum is this a postQuantum algorithm?
812      * @return the KeyPairGenerator
813      * @throws GordianException on error
814      */
815     private static Signature getJavaSignature(final String pAlgorithm,
816                                               final boolean postQuantum) throws GordianException {
817         /* Protect against exceptions */
818         try {
819             /* Return a Signature for the algorithm */
820             return Signature.getInstance(pAlgorithm, postQuantum
821                     ? JcaProvider.BCPQPROV
822                     : JcaProvider.BCPROV);
823 
824             /* Catch exceptions */
825         } catch (NoSuchAlgorithmException e) {
826             /* Throw the exception */
827             throw new GordianCryptoException("Failed to create Signature", e);
828         }
829     }
830 }