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