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.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
43
44 public abstract class JcaSignature
45 extends GordianCoreSignature {
46
47
48
49 private static final String SIG_ERROR = "Signature error";
50
51
52
53
54 private static final String RSA_PSSMGF1_ALGOBASE = "withRSAandMGF1";
55
56
57
58
59 private static final String RSA_PSS128_ALGOBASE = "withRSAandSHAKE128";
60
61
62
63
64 private static final String RSA_PSS256_ALGOBASE = "withRSAandSHAKE256";
65
66
67
68
69 private static final String RSA_PSSSHAKE_ALGOBASE = "withRSA/PSS";
70
71
72
73
74 private static final String RSA_X931_ALGOBASE = "withRSA/X9.31";
75
76
77
78
79 private static final String RSA_ISO9796D2_ALGOBASE = "withRSA/ISO9796-2";
80
81
82
83
84 private static final String RSA_PREHASH_ALGOBASE = "withRSAEncryption";
85
86
87
88
89 private static final String EC_DSA_ALGOBASE = "withECDSA";
90
91
92
93
94 private static final String EC_DDSA_ALGOBASE = "withECDDSA";
95
96
97
98
99 private static final String DSA_ALGOBASE = "withDSA";
100
101
102
103
104 private static final String DDSA_ALGOBASE = "withDDSA";
105
106
107
108
109 private static final String EC_NR_ALGOBASE = "withECNR";
110
111
112
113
114 private static final String EC_SM2_ALGOBASE = "WITHSM2";
115
116
117
118
119 private static final String DSTU_SIGN = "DSTU4145";
120
121
122
123
124 private static final String PQC_HASH_PFX = "HASH-";
125
126
127
128
129 private Signature theSigner;
130
131
132
133
134
135
136
137 JcaSignature(final GordianBaseFactory pFactory,
138 final GordianSignatureSpec pSpec) {
139 super(pFactory, pSpec);
140 }
141
142
143
144
145
146
147 protected void setSigner(final Signature pSigner) {
148 theSigner = pSigner;
149 }
150
151
152
153
154
155
156 protected Signature getSigner() {
157 return theSigner;
158 }
159
160 @Override
161 public void initForSigning(final GordianSignParams pParams) throws GordianException {
162
163 super.initForSigning(pParams);
164 final JcaKeyPair myPair = getKeyPair();
165 final byte[] myContext = getContext();
166 JcaKeyPair.checkKeyPair(myPair);
167
168
169 try {
170
171 final boolean useRandom = getSignatureSpec().getKeyPairType().useRandomForSignatures();
172
173
174 if (useRandom) {
175 getSigner().initSign(myPair.getPrivateKey().getPrivateKey(), getRandom());
176 } else {
177 getSigner().initSign(myPair.getPrivateKey().getPrivateKey());
178 }
179
180
181 if (getSignatureSpec().supportsContext()) {
182
183 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
184 getSigner().setParameter(mySpec);
185 }
186
187
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
197 super.initForVerify(pParams);
198 final JcaKeyPair myPair = getKeyPair();
199 final byte[] myContext = getContext();
200 JcaKeyPair.checkKeyPair(myPair);
201
202
203 try {
204
205 getSigner().initVerify(myPair.getPublicKey().getPublicKey());
206
207
208 if (getSignatureSpec().supportsContext()) {
209
210 final ContextParameterSpec mySpec = myContext == null ? null : new ContextParameterSpec(myContext);
211 getSigner().setParameter(mySpec);
212 }
213
214
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
244 checkMode(GordianSignatureMode.SIGN);
245
246
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
258 checkMode(GordianSignatureMode.VERIFY);
259
260
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
271 }
272
273 @Override
274 protected JcaKeyPair getKeyPair() {
275 return (JcaKeyPair) super.getKeyPair();
276 }
277
278
279
280
281 static class JcaRSASignature
282 extends JcaSignature {
283
284
285
286
287
288
289
290 JcaRSASignature(final GordianBaseFactory pFactory,
291 final GordianSignatureSpec pSignatureSpec) throws GordianException {
292
293 super(pFactory, pSignatureSpec);
294
295
296 final String myDigest = JcaDigest.getSignAlgorithm(pSignatureSpec.getDigestSpec());
297 setSigner(getJavaSignature(myDigest + getSignatureBase(pSignatureSpec), false));
298 }
299 }
300
301
302
303
304
305
306
307 static String getSignatureBase(final GordianSignatureSpec pSignatureSpec) {
308
309 if (GordianKeyPairType.SM2.equals(pSignatureSpec.getKeyPairType())) {
310 return EC_SM2_ALGOBASE;
311 }
312
313
314 final boolean isDSA = GordianKeyPairType.DSA.equals(pSignatureSpec.getKeyPairType());
315 final boolean isSHAKE = GordianDigestType.SHAKE.equals(pSignatureSpec.getDigestSpec().getDigestType());
316
317
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
348
349 static class JcaDSASignature
350 extends JcaSignature {
351
352
353
354
355
356
357
358 JcaDSASignature(final GordianBaseFactory pFactory,
359 final GordianSignatureSpec pSignatureSpec) throws GordianException {
360
361 super(pFactory, pSignatureSpec);
362
363
364 final String myDigest = JcaDigest.getSignAlgorithm(pSignatureSpec.getDigestSpec());
365 setSigner(getJavaSignature(myDigest + getSignatureBase(pSignatureSpec), false));
366 }
367 }
368
369
370
371
372 static class JcaGOSTSignature
373 extends JcaSignature {
374
375
376
377
378
379
380
381 JcaGOSTSignature(final GordianBaseFactory pFactory,
382 final GordianSignatureSpec pSignatureSpec) throws GordianException {
383
384 super(pFactory, pSignatureSpec);
385
386
387 setSigner(getJavaSignature(getSignature(pSignatureSpec), false));
388 }
389
390
391
392
393
394
395
396 private static String getSignature(final GordianSignatureSpec pSignatureSpec) {
397
398 if (GordianKeyPairType.DSTU4145.equals(pSignatureSpec.getKeyPairType())) {
399 return DSTU_SIGN;
400 }
401
402
403 final GordianLength myLength = pSignatureSpec.getDigestSpec().getDigestLength();
404
405
406 return "GOST3411-2012-"
407 + myLength.getLength()
408 + "withECGOST3410-2012-"
409 + myLength.getLength();
410 }
411 }
412
413
414
415
416 static class JcaSLHDSASignature
417 extends JcaSignature {
418
419
420
421 private static final String BASE_NAME = "SLH-DSA";
422
423
424
425
426
427
428
429 JcaSLHDSASignature(final GordianBaseFactory pFactory,
430 final GordianSignatureSpec pSignatureSpec) {
431
432 super(pFactory, pSignatureSpec);
433 }
434
435 @Override
436 public void initForSigning(final GordianSignParams pParams) throws GordianException {
437
438 final GordianKeyPair myPair = pParams.getKeyPair();
439 JcaKeyPair.checkKeyPair(myPair);
440 final String mySignName = getAlgorithmForKeyPair(myPair);
441 setSigner(getJavaSignature(mySignName, false));
442
443
444 super.initForSigning(pParams);
445 }
446
447 @Override
448 public void initForVerify(final GordianSignParams pParams) throws GordianException {
449
450 final GordianKeyPair myPair = pParams.getKeyPair();
451 JcaKeyPair.checkKeyPair(myPair);
452 final String mySignName = getAlgorithmForKeyPair(myPair);
453 setSigner(getJavaSignature(mySignName, false));
454
455
456 super.initForVerify(pParams);
457 }
458
459
460
461
462
463
464
465 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
466
467 final boolean isHash = pKeyPair.getKeyPairSpec().getSLHDSAKeySpec().isHash();
468 return isHash ? PQC_HASH_PFX + BASE_NAME : BASE_NAME;
469 }
470 }
471
472
473
474
475 static class JcaMLDSASignature
476 extends JcaSignature {
477
478
479
480 private static final String BASE_NAME = "ML-DSA";
481
482
483
484
485
486
487
488 JcaMLDSASignature(final GordianBaseFactory pFactory,
489 final GordianSignatureSpec pSignatureSpec) {
490
491 super(pFactory, pSignatureSpec);
492 }
493
494 @Override
495 public void initForSigning(final GordianSignParams pParams) throws GordianException {
496
497 final GordianKeyPair myPair = pParams.getKeyPair();
498 JcaKeyPair.checkKeyPair(myPair);
499 final String mySignName = getAlgorithmForKeyPair(myPair);
500 setSigner(getJavaSignature(mySignName, false));
501
502
503 super.initForSigning(pParams);
504 }
505
506 @Override
507 public void initForVerify(final GordianSignParams pParams) throws GordianException {
508
509 final GordianKeyPair myPair = pParams.getKeyPair();
510 JcaKeyPair.checkKeyPair(myPair);
511 final String mySignName = getAlgorithmForKeyPair(myPair);
512 setSigner(getJavaSignature(mySignName, false));
513
514
515 super.initForVerify(pParams);
516 }
517
518
519
520
521
522
523
524 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
525
526 final boolean isHash = pKeyPair.getKeyPairSpec().getMLDSAKeySpec().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 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
653
654 static class JcaXMSSSignature
655 extends JcaSignature {
656
657
658
659 private final boolean preHash;
660
661
662
663
664
665
666
667 JcaXMSSSignature(final GordianBaseFactory pFactory,
668 final GordianSignatureSpec pSignatureSpec) {
669
670 super(pFactory, pSignatureSpec);
671
672
673 preHash = GordianSignatureType.PREHASH.equals(pSignatureSpec.getSignatureType());
674 }
675
676 @Override
677 public void initForSigning(final GordianSignParams pParams) throws GordianException {
678
679 final GordianKeyPair myPair = pParams.getKeyPair();
680 JcaKeyPair.checkKeyPair(myPair);
681 final String mySignName = getAlgorithmForKeyPair(myPair);
682 setSigner(getJavaSignature(mySignName, true));
683
684
685 super.initForSigning(pParams);
686 }
687
688 @Override
689 public void initForVerify(final GordianSignParams pParams) throws GordianException {
690
691 final GordianKeyPair myPair = pParams.getKeyPair();
692 JcaKeyPair.checkKeyPair(myPair);
693 final String mySignName = getAlgorithmForKeyPair(myPair);
694 setSigner(getJavaSignature(mySignName, true));
695
696
697 super.initForVerify(pParams);
698 }
699
700
701
702
703
704
705
706
707 private String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) throws GordianException {
708
709 final GordianXMSSKeySpec myXMSSKeySpec = pKeyPair.getKeyPairSpec().getXMSSKeySpec();
710 final GordianDigestSpec myDigestSpec = myXMSSKeySpec.getDigestType().getDigestSpec();
711 final String myDigest = JcaDigest.getAlgorithm(myDigestSpec);
712
713
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
724 return myBuilder.toString();
725 }
726 }
727
728
729
730
731 static class JcaEdDSASignature
732 extends JcaSignature {
733
734
735
736
737
738
739 JcaEdDSASignature(final GordianBaseFactory pFactory,
740 final GordianSignatureSpec pSignatureSpec) {
741
742 super(pFactory, pSignatureSpec);
743 }
744
745 @Override
746 public void initForSigning(final GordianSignParams pParams) throws GordianException {
747
748 final GordianKeyPair myPair = pParams.getKeyPair();
749 JcaKeyPair.checkKeyPair(myPair);
750 final String mySignName = getAlgorithmForKeyPair(myPair);
751 setSigner(getJavaSignature(mySignName, false));
752
753
754 super.initForSigning(pParams);
755 }
756
757 @Override
758 public void initForVerify(final GordianSignParams pParams) throws GordianException {
759
760 final GordianKeyPair myPair = pParams.getKeyPair();
761 JcaKeyPair.checkKeyPair(myPair);
762 final String mySignName = getAlgorithmForKeyPair(myPair);
763 setSigner(getJavaSignature(mySignName, false));
764
765
766 super.initForVerify(pParams);
767 }
768
769
770
771
772
773
774
775 private static String getAlgorithmForKeyPair(final GordianKeyPair pKeyPair) {
776
777 final GordianEdwardsElliptic myEdwards = pKeyPair.getKeyPairSpec().getEdwardsElliptic();
778 final boolean is25519 = myEdwards.is25519();
779
780
781 return is25519 ? "Ed25519" : "Ed448";
782 }
783 }
784
785
786
787
788 static class JcaLMSSignature
789 extends JcaSignature {
790
791
792
793
794
795
796
797 JcaLMSSignature(final GordianBaseFactory pFactory,
798 final GordianSignatureSpec pSignatureSpec) throws GordianException {
799
800 super(pFactory, pSignatureSpec);
801
802
803 setSigner(getJavaSignature("LMS", true));
804 }
805 }
806
807
808
809
810
811
812
813
814
815 private static Signature getJavaSignature(final String pAlgorithm,
816 final boolean postQuantum) throws GordianException {
817
818 try {
819
820 return Signature.getInstance(pAlgorithm, postQuantum
821 ? JcaProvider.BCPQPROV
822 : JcaProvider.BCPROV);
823
824
825 } catch (NoSuchAlgorithmException e) {
826
827 throw new GordianCryptoException("Failed to create Signature", e);
828 }
829 }
830 }