1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
46
47 public abstract class JcaSignature
48 extends GordianCoreSignature {
49
50
51
52 private static final String SIG_ERROR = "Signature error";
53
54
55
56
57 private static final String RSA_PSSMGF1_ALGOBASE = "withRSAandMGF1";
58
59
60
61
62 private static final String RSA_PSS128_ALGOBASE = "withRSAandSHAKE128";
63
64
65
66
67 private static final String RSA_PSS256_ALGOBASE = "withRSAandSHAKE256";
68
69
70
71
72 private static final String RSA_PSSSHAKE_ALGOBASE = "withRSA/PSS";
73
74
75
76
77 private static final String RSA_X931_ALGOBASE = "withRSA/X9.31";
78
79
80
81
82 private static final String RSA_ISO9796D2_ALGOBASE = "withRSA/ISO9796-2";
83
84
85
86
87 private static final String RSA_PREHASH_ALGOBASE = "withRSAEncryption";
88
89
90
91
92 private static final String EC_DSA_ALGOBASE = "withECDSA";
93
94
95
96
97 private static final String EC_DDSA_ALGOBASE = "withECDDSA";
98
99
100
101
102 private static final String DSA_ALGOBASE = "withDSA";
103
104
105
106
107 private static final String DDSA_ALGOBASE = "withDDSA";
108
109
110
111
112 private static final String EC_NR_ALGOBASE = "withECNR";
113
114
115
116
117 private static final String EC_SM2_ALGOBASE = "WITHSM2";
118
119
120
121
122 private static final String DSTU_SIGN = "DSTU4145";
123
124
125
126
127 private static final String PQC_HASH_PFX = "HASH-";
128
129
130
131
132 private Signature theSigner;
133
134
135
136
137
138
139
140 JcaSignature(final GordianBaseFactory pFactory,
141 final GordianSignatureSpec pSpec) {
142 super(pFactory, pSpec);
143 }
144
145
146
147
148
149
150 protected void setSigner(final Signature pSigner) {
151 theSigner = pSigner;
152 }
153
154
155
156
157
158
159 protected Signature getSigner() {
160 return theSigner;
161 }
162
163 @Override
164 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
165
166 super.initForSigning(pParams);
167 final JcaKeyPair myPair = getKeyPair();
168 final byte[] myContext = getContext();
169 JcaKeyPair.checkKeyPair(myPair);
170
171
172 try {
173
174 final GordianCoreKeyPairType myType = GordianCoreKeyPairType.mapCoreType(getSignatureSpec().getKeyPairType());
175 final boolean useRandom = myType.useRandomForSignatures();
176
177
178 if (useRandom) {
179 getSigner().initSign(myPair.getPrivateKey().getPrivateKey(), getRandom());
180 } else {
181 getSigner().initSign(myPair.getPrivateKey().getPrivateKey());
182 }
183
184
185 if (getSignatureSpec().supportsContext()) {
186
187 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
188 getSigner().setParameter(mySpec);
189 }
190
191
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
201 super.initForVerify(pParams);
202 final JcaKeyPair myPair = getKeyPair();
203 final byte[] myContext = getContext();
204 JcaKeyPair.checkKeyPair(myPair);
205
206
207 try {
208
209 getSigner().initVerify(myPair.getPublicKey().getPublicKey());
210
211
212 if (getSignatureSpec().supportsContext()) {
213
214 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
215 getSigner().setParameter(mySpec);
216 }
217
218
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
248 checkMode(GordianSignatureMode.SIGN);
249
250
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
262 checkMode(GordianSignatureMode.VERIFY);
263
264
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
275 }
276
277 @Override
278 protected JcaKeyPair getKeyPair() {
279 return (JcaKeyPair) super.getKeyPair();
280 }
281
282
283
284
285 static class JcaRSASignature
286 extends JcaSignature {
287
288
289
290
291
292
293
294 JcaRSASignature(final GordianBaseFactory pFactory,
295 final GordianSignatureSpec pSignatureSpec) throws GordianException {
296
297 super(pFactory, pSignatureSpec);
298
299
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
308
309
310
311
312 static String getSignatureBase(final GordianSignatureSpec pSignatureSpec) {
313
314 if (GordianKeyPairType.SM2.equals(pSignatureSpec.getKeyPairType())) {
315 return EC_SM2_ALGOBASE;
316 }
317
318
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
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
344
345 static class JcaDSASignature
346 extends JcaSignature {
347
348
349
350
351
352
353
354 JcaDSASignature(final GordianBaseFactory pFactory,
355 final GordianSignatureSpec pSignatureSpec) throws GordianException {
356
357 super(pFactory, pSignatureSpec);
358
359
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
368
369 static class JcaGOSTSignature
370 extends JcaSignature {
371
372
373
374
375
376
377
378 JcaGOSTSignature(final GordianBaseFactory pFactory,
379 final GordianSignatureSpec pSignatureSpec) throws GordianException {
380
381 super(pFactory, pSignatureSpec);
382
383
384 setSigner(getJavaSignature(getSignature(pSignatureSpec), false));
385 }
386
387
388
389
390
391
392
393 private static String getSignature(final GordianSignatureSpec pSignatureSpec) {
394
395 if (GordianKeyPairType.DSTU.equals(pSignatureSpec.getKeyPairType())) {
396 return DSTU_SIGN;
397 }
398
399
400 final GordianCoreSignatureSpec mySpec = (GordianCoreSignatureSpec) pSignatureSpec;
401 final GordianLength myLength = mySpec.getDigestSpec().getDigestLength();
402
403
404 return "GOST3411-2012-"
405 + myLength.getLength()
406 + "withECGOST3410-2012-"
407 + myLength.getLength();
408 }
409 }
410
411
412
413
414 static class JcaSLHDSASignature
415 extends JcaSignature {
416
417
418
419 private static final String BASE_NAME = "SLH-DSA";
420
421
422
423
424
425
426
427 JcaSLHDSASignature(final GordianBaseFactory pFactory,
428 final GordianSignatureSpec pSignatureSpec) {
429
430 super(pFactory, pSignatureSpec);
431 }
432
433 @Override
434 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
435
436 final GordianKeyPair myPair = pParams.getKeyPair();
437 JcaKeyPair.checkKeyPair(myPair);
438 final String mySignName = getAlgorithmForKeyPair(myPair);
439 setSigner(getJavaSignature(mySignName, false));
440
441
442 super.initForSigning(pParams);
443 }
444
445 @Override
446 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
447
448 final GordianKeyPair myPair = pParams.getKeyPair();
449 JcaKeyPair.checkKeyPair(myPair);
450 final String mySignName = getAlgorithmForKeyPair(myPair);
451 setSigner(getJavaSignature(mySignName, false));
452
453
454 super.initForVerify(pParams);
455 }
456
457
458
459
460
461
462
463 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
464
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
473
474 static class JcaMLDSASignature
475 extends JcaSignature {
476
477
478
479 private static final String BASE_NAME = "ML-DSA";
480
481
482
483
484
485
486
487 JcaMLDSASignature(final GordianBaseFactory pFactory,
488 final GordianSignatureSpec pSignatureSpec) {
489
490 super(pFactory, pSignatureSpec);
491 }
492
493 @Override
494 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
495
496 final GordianKeyPair myPair = pParams.getKeyPair();
497 JcaKeyPair.checkKeyPair(myPair);
498 final String mySignName = getAlgorithmForKeyPair(myPair);
499 setSigner(getJavaSignature(mySignName, false));
500
501
502 super.initForSigning(pParams);
503 }
504
505 @Override
506 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
507
508 final GordianKeyPair myPair = pParams.getKeyPair();
509 JcaKeyPair.checkKeyPair(myPair);
510 final String mySignName = getAlgorithmForKeyPair(myPair);
511 setSigner(getJavaSignature(mySignName, false));
512
513
514 super.initForVerify(pParams);
515 }
516
517
518
519
520
521
522
523 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
524
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
533
534 static class JcaFalconSignature
535 extends JcaSignature {
536
537
538
539
540
541
542
543 JcaFalconSignature(final GordianBaseFactory pFactory,
544 final GordianSignatureSpec pSignatureSpec) throws GordianException {
545
546 super(pFactory, pSignatureSpec);
547
548
549 setSigner(getJavaSignature("FALCON", true));
550 }
551 }
552
553
554
555
556 static class JcaMayoSignature
557 extends JcaSignature {
558
559
560
561
562
563
564
565 JcaMayoSignature(final GordianBaseFactory pFactory,
566 final GordianSignatureSpec pSignatureSpec) throws GordianException {
567
568 super(pFactory, pSignatureSpec);
569
570
571 setSigner(getJavaSignature("MAYO", true));
572 }
573 }
574
575
576
577
578 static class JcaSnovaSignature
579 extends JcaSignature {
580
581
582
583
584
585
586
587 JcaSnovaSignature(final GordianBaseFactory pFactory,
588 final GordianSignatureSpec pSignatureSpec) throws GordianException {
589
590 super(pFactory, pSignatureSpec);
591
592
593 setSigner(getJavaSignature("SNOVA", true));
594 }
595 }
596
597
598
599
600 static class JcaPicnicSignature
601 extends JcaSignature {
602
603
604
605 private static final String BASE_NAME = "PICNIC";
606
607
608
609
610
611
612
613
614 JcaPicnicSignature(final GordianBaseFactory pFactory,
615 final GordianSignatureSpec pSignatureSpec) throws GordianException {
616
617 super(pFactory, pSignatureSpec);
618
619
620 final String myName = determineSignatureName(pSignatureSpec);
621 setSigner(getJavaSignature(myName, true));
622 }
623
624
625
626
627
628
629
630 private static String determineSignatureName(final GordianSignatureSpec pSignatureSpec) {
631
632 if (pSignatureSpec.getSignatureSpec() == null) {
633 return BASE_NAME;
634 }
635
636
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
650
651 static class JcaXMSSSignature
652 extends JcaSignature {
653
654
655
656 private final boolean preHash;
657
658
659
660
661
662
663
664 JcaXMSSSignature(final GordianBaseFactory pFactory,
665 final GordianSignatureSpec pSignatureSpec) {
666
667 super(pFactory, pSignatureSpec);
668
669
670 preHash = GordianSignatureType.PREHASH.equals(pSignatureSpec.getSignatureType());
671 }
672
673 @Override
674 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
675
676 final GordianKeyPair myPair = pParams.getKeyPair();
677 JcaKeyPair.checkKeyPair(myPair);
678 final String mySignName = getAlgorithmForKeyPair(myPair);
679 setSigner(getJavaSignature(mySignName, true));
680
681
682 super.initForSigning(pParams);
683 }
684
685 @Override
686 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
687
688 final GordianKeyPair myPair = pParams.getKeyPair();
689 JcaKeyPair.checkKeyPair(myPair);
690 final String mySignName = getAlgorithmForKeyPair(myPair);
691 setSigner(getJavaSignature(mySignName, true));
692
693
694 super.initForVerify(pParams);
695 }
696
697
698
699
700
701
702
703
704 private String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) throws GordianException {
705
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
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
722 return myBuilder.toString();
723 }
724 }
725
726
727
728
729 static class JcaEdDSASignature
730 extends JcaSignature {
731
732
733
734
735
736
737 JcaEdDSASignature(final GordianBaseFactory pFactory,
738 final GordianSignatureSpec pSignatureSpec) {
739
740 super(pFactory, pSignatureSpec);
741 }
742
743 @Override
744 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
745
746 final GordianKeyPair myPair = pParams.getKeyPair();
747 JcaKeyPair.checkKeyPair(myPair);
748 final String mySignName = getAlgorithmForKeyPair(myPair);
749 setSigner(getJavaSignature(mySignName, false));
750
751
752 super.initForSigning(pParams);
753 }
754
755 @Override
756 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
757
758 final GordianKeyPair myPair = pParams.getKeyPair();
759 JcaKeyPair.checkKeyPair(myPair);
760 final String mySignName = getAlgorithmForKeyPair(myPair);
761 setSigner(getJavaSignature(mySignName, false));
762
763
764 super.initForVerify(pParams);
765 }
766
767
768
769
770
771
772
773 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
774
775 final GordianCoreKeyPairSpec mySpec = (GordianCoreKeyPairSpec) pKeyPair.getKeyPairSpec();
776 final GordianCoreEdwardsSpec myEdwards = mySpec.getEdwardsSpec();
777 final boolean is25519 = myEdwards.is25519();
778
779
780 return is25519 ? "Ed25519" : "Ed448";
781 }
782 }
783
784
785
786
787 static class JcaLMSSignature
788 extends JcaSignature {
789
790
791
792
793
794
795
796 JcaLMSSignature(final GordianBaseFactory pFactory,
797 final GordianSignatureSpec pSignatureSpec) throws GordianException {
798
799 super(pFactory, pSignatureSpec);
800
801
802 setSigner(getJavaSignature("LMS", true));
803 }
804 }
805
806
807
808
809
810
811
812
813
814 private static Signature getJavaSignature(final String pAlgorithm,
815 final boolean postQuantum) throws GordianException {
816
817 try {
818
819 return Signature.getInstance(pAlgorithm, postQuantum
820 ? JcaProvider.BCPQPROV
821 : JcaProvider.BCPROV);
822
823
824 } catch (NoSuchAlgorithmException e) {
825
826 throw new GordianCryptoException("Failed to create Signature", e);
827 }
828 }
829 }