1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.impl.bc;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20 import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestFactory;
21 import io.github.tonywasher.joceanus.gordianknot.api.digest.spec.GordianDigestSpec;
22 import io.github.tonywasher.joceanus.gordianknot.api.digest.spec.GordianDigestSpecBuilder;
23 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
24 import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
25 import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianNewSignParams;
26 import io.github.tonywasher.joceanus.gordianknot.api.sign.spec.GordianSignatureSpec;
27 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPrivateKey;
28 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPublicKey;
29 import io.github.tonywasher.joceanus.gordianknot.impl.core.agree.GordianCoreAgreementFactory;
30 import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
31 import io.github.tonywasher.joceanus.gordianknot.impl.core.encrypt.GordianCoreEncryptor;
32 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
33 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianIOException;
34 import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
35 import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
36 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.agree.GordianCoreAgreementSpec;
37 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.encrypt.GordianCoreEncryptorSpec;
38 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
39 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.sign.GordianCoreSignatureSpec;
40 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
41 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
42 import org.bouncycastle.crypto.AsymmetricBlockCipher;
43 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
44 import org.bouncycastle.crypto.CipherParameters;
45 import org.bouncycastle.crypto.CryptoException;
46 import org.bouncycastle.crypto.DataLengthException;
47 import org.bouncycastle.crypto.DerivationFunction;
48 import org.bouncycastle.crypto.InvalidCipherTextException;
49 import org.bouncycastle.crypto.SecretWithEncapsulation;
50 import org.bouncycastle.crypto.Signer;
51 import org.bouncycastle.crypto.encodings.OAEPEncoding;
52 import org.bouncycastle.crypto.engines.RSABlindedEngine;
53 import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
54 import org.bouncycastle.crypto.kems.RSAKEMExtractor;
55 import org.bouncycastle.crypto.kems.RSAKEMGenerator;
56 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
57 import org.bouncycastle.crypto.params.ParametersWithRandom;
58 import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
59 import org.bouncycastle.crypto.params.RSAKeyParameters;
60 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
61 import org.bouncycastle.crypto.signers.ISO9796d2Signer;
62 import org.bouncycastle.crypto.signers.ISOTrailers;
63 import org.bouncycastle.crypto.signers.PSSSigner;
64 import org.bouncycastle.crypto.signers.RSADigestSigner;
65 import org.bouncycastle.crypto.signers.X931Signer;
66 import org.bouncycastle.crypto.util.PrivateKeyFactory;
67 import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
68 import org.bouncycastle.crypto.util.PublicKeyFactory;
69 import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
70
71 import javax.crypto.spec.PSource;
72 import javax.security.auth.DestroyFailedException;
73 import java.io.IOException;
74 import java.math.BigInteger;
75 import java.security.spec.PKCS8EncodedKeySpec;
76 import java.security.spec.X509EncodedKeySpec;
77 import java.util.Arrays;
78
79
80
81
82 public final class BouncyRSAKeyPair {
83
84
85
86 private BouncyRSAKeyPair() {
87 }
88
89
90
91
92 public static class BouncyRSAPublicKey
93 extends BouncyPublicKey<RSAKeyParameters> {
94
95
96
97
98
99
100 BouncyRSAPublicKey(final GordianKeyPairSpec pKeySpec,
101 final RSAKeyParameters pPublicKey) {
102 super(pKeySpec, pPublicKey);
103 }
104
105 @Override
106 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
107
108 final RSAKeyParameters myThis = getPublicKey();
109 final RSAKeyParameters myThat = (RSAKeyParameters) pThat;
110
111
112 return compareKeys(myThis, myThat);
113 }
114
115
116
117
118
119
120
121
122 private static boolean compareKeys(final RSAKeyParameters pFirst,
123 final RSAKeyParameters pSecond) {
124 return pFirst.getExponent().equals(pSecond.getExponent())
125 && pFirst.getModulus().equals(pSecond.getModulus());
126 }
127
128
129
130
131
132
133
134 public boolean validPrivate(final BouncyRSAPrivateKey pPrivate) {
135 final RSAPrivateCrtKeyParameters myPrivate = pPrivate.getPrivateKey();
136 return getPublicKey().getExponent().equals(myPrivate.getExponent())
137 && getPublicKey().getModulus().equals(myPrivate.getModulus());
138 }
139 }
140
141
142
143
144 public static class BouncyRSAPrivateKey
145 extends BouncyPrivateKey<RSAPrivateCrtKeyParameters> {
146
147
148
149
150
151
152 BouncyRSAPrivateKey(final GordianKeyPairSpec pKeySpec,
153 final RSAPrivateCrtKeyParameters pPrivateKey) {
154 super(pKeySpec, pPrivateKey);
155 }
156
157 @Override
158 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
159
160 final RSAPrivateCrtKeyParameters myThis = getPrivateKey();
161 final RSAPrivateCrtKeyParameters myThat = (RSAPrivateCrtKeyParameters) pThat;
162
163
164 return compareKeys(myThis, myThat);
165 }
166
167
168
169
170
171
172
173
174 private static boolean compareKeys(final RSAPrivateCrtKeyParameters pFirst,
175 final RSAPrivateCrtKeyParameters pSecond) {
176 if (!pFirst.getExponent().equals(pSecond.getExponent())
177 || !pFirst.getModulus().equals(pSecond.getModulus())) {
178 return false;
179 }
180
181 if (!pFirst.getP().equals(pSecond.getP())
182 || !pFirst.getQ().equals(pSecond.getQ())) {
183 return false;
184 }
185
186 if (!pFirst.getDP().equals(pSecond.getDP())
187 || !pFirst.getDQ().equals(pSecond.getDQ())) {
188 return false;
189 }
190
191 return pFirst.getPublicExponent().equals(pSecond.getPublicExponent())
192 && pFirst.getQInv().equals(pSecond.getQInv());
193 }
194 }
195
196
197
198
199 public static class BouncyRSAKeyPairGenerator
200 extends BouncyKeyPairGenerator {
201
202
203
204 private static final BigInteger RSA_EXPONENT = new BigInteger("10001", 16);
205
206
207
208
209 private final RSAKeyPairGenerator theGenerator;
210
211
212
213
214
215
216
217 BouncyRSAKeyPairGenerator(final GordianBaseFactory pFactory,
218 final GordianKeyPairSpec pKeySpec) {
219
220 super(pFactory, pKeySpec);
221
222
223 theGenerator = new RSAKeyPairGenerator();
224 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
225 final RSAKeyGenerationParameters myParams
226 = new RSAKeyGenerationParameters(RSA_EXPONENT, getRandom(), myKeySpec.getRSASpec().getLength(), PRIME_CERTAINTY);
227 theGenerator.init(myParams);
228 }
229
230 @Override
231 public BouncyKeyPair generateKeyPair() {
232
233 final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
234 final BouncyRSAPublicKey myPublic = new BouncyRSAPublicKey(getKeySpec(), (RSAKeyParameters) myPair.getPublic());
235 final BouncyRSAPrivateKey myPrivate = new BouncyRSAPrivateKey(getKeySpec(), (RSAPrivateCrtKeyParameters) myPair.getPrivate());
236 return new BouncyKeyPair(myPublic, myPrivate);
237 }
238
239 @Override
240 public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
241
242 try {
243
244 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
245
246
247 final BouncyRSAPrivateKey myPrivateKey = (BouncyRSAPrivateKey) getPrivateKey(pKeyPair);
248 final RSAPrivateCrtKeyParameters myParms = myPrivateKey.getPrivateKey();
249 final PrivateKeyInfo myInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(myParms);
250 return new PKCS8EncodedKeySpec(myInfo.getEncoded());
251
252 } catch (IOException e) {
253 throw new GordianCryptoException(ERROR_PARSE, e);
254 }
255 }
256
257 @Override
258 public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
259 final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
260
261 try {
262
263 checkKeySpec(pPrivateKey);
264
265
266 final BouncyRSAPublicKey myPublic = derivePublicKey(pPublicKey);
267 final PrivateKeyInfo myInfo = PrivateKeyInfo.getInstance(pPrivateKey.getEncoded());
268 final RSAPrivateCrtKeyParameters myParms = (RSAPrivateCrtKeyParameters) PrivateKeyFactory.createKey(myInfo);
269 final BouncyRSAPrivateKey myPrivate = new BouncyRSAPrivateKey(getKeySpec(), myParms);
270 final BouncyKeyPair myPair = new BouncyKeyPair(myPublic, myPrivate);
271
272
273 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
274
275
276 return myPair;
277
278 } catch (IOException e) {
279 throw new GordianCryptoException(ERROR_PARSE, e);
280 }
281 }
282
283 @Override
284 public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
285
286 try {
287
288 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
289
290
291 final BouncyRSAPublicKey myPublicKey = (BouncyRSAPublicKey) getPublicKey(pKeyPair);
292 final RSAKeyParameters myParms = myPublicKey.getPublicKey();
293 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(myParms);
294 return new X509EncodedKeySpec(myInfo.getEncoded());
295
296 } catch (IOException e) {
297 throw new GordianCryptoException(ERROR_PARSE, e);
298 }
299 }
300
301 @Override
302 public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
303 final BouncyRSAPublicKey myPublic = derivePublicKey(pEncodedKey);
304 return new BouncyKeyPair(myPublic);
305 }
306
307
308
309
310
311
312
313
314 private BouncyRSAPublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
315
316 try {
317
318 checkKeySpec(pEncodedKey);
319
320
321 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfo.getInstance(pEncodedKey.getEncoded());
322 final RSAKeyParameters myParms = (RSAKeyParameters) PublicKeyFactory.createKey(myInfo);
323 return new BouncyRSAPublicKey(getKeySpec(), myParms);
324
325 } catch (IOException e) {
326 throw new GordianCryptoException(ERROR_PARSE, e);
327 }
328 }
329 }
330
331
332
333
334 private abstract static class BouncyPSSSignature
335 extends GordianCoreSignature {
336
337
338
339 private final Signer theSigner;
340
341
342
343
344
345
346
347
348 BouncyPSSSignature(final GordianBaseFactory pFactory,
349 final GordianSignatureSpec pSpec) throws GordianException {
350 super(pFactory, pSpec);
351 theSigner = getRSASigner(pFactory, (GordianCoreSignatureSpec) pSpec);
352 }
353
354
355
356
357
358
359 protected Signer getSigner() {
360 return theSigner;
361 }
362
363 @Override
364 public void update(final byte[] pBytes,
365 final int pOffset,
366 final int pLength) {
367 theSigner.update(pBytes, pOffset, pLength);
368 }
369
370 @Override
371 public void update(final byte pByte) {
372 theSigner.update(pByte);
373 }
374
375 @Override
376 public void update(final byte[] pBytes) {
377 theSigner.update(pBytes, 0, pBytes.length);
378 }
379
380 @Override
381 public void reset() {
382 theSigner.reset();
383 }
384
385
386
387
388
389
390
391
392
393 private static Signer getRSASigner(final GordianBaseFactory pFactory,
394 final GordianCoreSignatureSpec pSpec) throws GordianException {
395
396 final GordianDigestSpec myDigestSpec = pSpec.getDigestSpec();
397 final GordianDigestFactory myFactory = pFactory.getDigestFactory();
398 final BouncyDigest myDigest = (BouncyDigest) myFactory.createDigest(myDigestSpec);
399 final GordianDigestSpecBuilder myBuilder = myFactory.newDigestSpecBuilder();
400 final int mySaltLength = myDigestSpec.getDigestLength().getByteLength();
401
402
403 return switch (pSpec.getSignatureType()) {
404 case ISO9796D2 ->
405 new ISO9796d2Signer(new RSABlindedEngine(), myDigest.getDigest(), ISOTrailers.noTrailerAvailable(myDigest.getDigest()));
406 case X931 ->
407 new X931Signer(new RSABlindedEngine(), myDigest.getDigest(), ISOTrailers.noTrailerAvailable(myDigest.getDigest()));
408 case PREHASH -> new RSADigestSigner(myDigest.getDigest());
409 case PSS128 -> new PSSSigner(new RSABlindedEngine(), myDigest.getDigest(),
410 ((BouncyDigest) pFactory.getDigestFactory().createDigest(myBuilder.shake128())).getDigest(), mySaltLength);
411 case PSS256 -> new PSSSigner(new RSABlindedEngine(), myDigest.getDigest(),
412 ((BouncyDigest) pFactory.getDigestFactory().createDigest(myBuilder.shake256())).getDigest(), mySaltLength);
413 default -> new PSSSigner(new RSABlindedEngine(), myDigest.getDigest(), mySaltLength);
414 };
415 }
416 }
417
418
419
420
421 public static class BouncyRSASignature
422 extends BouncyPSSSignature {
423
424
425
426
427
428
429
430 BouncyRSASignature(final GordianBaseFactory pFactory,
431 final GordianSignatureSpec pSpec) throws GordianException {
432
433 super(pFactory, pSpec);
434 }
435
436 @Override
437 protected BouncyKeyPair getKeyPair() {
438 return (BouncyKeyPair) super.getKeyPair();
439 }
440
441 @Override
442 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
443
444 super.initForSigning(pParams);
445 final BouncyKeyPair myPair = getKeyPair();
446 BouncyKeyPair.checkKeyPair(myPair);
447
448
449 final BouncyRSAPrivateKey myPrivate = (BouncyRSAPrivateKey) myPair.getPrivateKey();
450 final CipherParameters myParms = getSignatureSpec().getCoreType().isPSS()
451 ? new ParametersWithRandom(myPrivate.getPrivateKey(), getRandom())
452 : myPrivate.getPrivateKey();
453 getSigner().init(true, myParms);
454 }
455
456 @Override
457 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
458
459 super.initForVerify(pParams);
460 final BouncyKeyPair myPair = getKeyPair();
461 BouncyKeyPair.checkKeyPair(myPair);
462
463
464 final BouncyRSAPublicKey myPublic = (BouncyRSAPublicKey) myPair.getPublicKey();
465 getSigner().init(false, myPublic.getPublicKey());
466 }
467
468 @Override
469 public byte[] sign() throws GordianException {
470
471 checkMode(GordianSignatureMode.SIGN);
472
473
474 try {
475 return getSigner().generateSignature();
476 } catch (DataLengthException
477 | CryptoException e) {
478 throw new GordianCryptoException(BouncySignature.ERROR_SIGGEN, e);
479 }
480 }
481
482 @Override
483 public boolean verify(final byte[] pSignature) throws GordianException {
484
485 checkMode(GordianSignatureMode.VERIFY);
486
487
488 return getSigner().verifySignature(pSignature);
489 }
490 }
491
492
493
494
495 public static class BouncyRSAAgreementEngine
496 extends BouncyAgreementBase {
497
498
499
500 private static final int KEYLEN = 32;
501
502
503
504
505 private final DerivationFunction theDerivation;
506
507
508
509
510
511
512
513
514 BouncyRSAAgreementEngine(final GordianCoreAgreementFactory pFactory,
515 final GordianCoreAgreementSpec pSpec) throws GordianException {
516
517 super(pFactory, pSpec);
518
519
520 theDerivation = newDerivationFunction();
521 }
522
523 @Override
524 public void buildClientHello() throws GordianException {
525
526 try {
527
528 final BouncyRSAPublicKey myPublic = (BouncyRSAPublicKey) getPublicKey(getServerKeyPair());
529 final RSAKEMGenerator myGenerator = new RSAKEMGenerator(KEYLEN, theDerivation, getRandom());
530 final SecretWithEncapsulation myResult = myGenerator.generateEncapsulated(myPublic.getPublicKey());
531
532
533 setEncapsulated(myResult.getEncapsulation());
534
535
536 storeSecret(myResult.getSecret());
537 myResult.destroy();
538
539 } catch (DestroyFailedException e) {
540 throw new GordianIOException("Failed to destroy secret", e);
541 }
542 }
543
544 @Override
545 public void processClientHello() throws GordianException {
546
547 final BouncyRSAPrivateKey myPrivate = (BouncyRSAPrivateKey) getPrivateKey(getServerKeyPair());
548 final RSAKEMExtractor myExtractor = new RSAKEMExtractor(myPrivate.getPrivateKey(), KEYLEN, theDerivation);
549
550
551 final byte[] myMessage = getEncapsulated();
552 storeSecret(myExtractor.extractSecret(myMessage));
553 }
554 }
555
556
557
558
559 public static class BouncyRSAEncryptor
560 extends BouncyCoreEncryptor {
561
562
563
564
565
566
567
568 BouncyRSAEncryptor(final GordianBaseFactory pFactory,
569 final GordianCoreEncryptorSpec pSpec) throws GordianException {
570
571 super(pFactory, pSpec, new RSABlindedEngine());
572 }
573
574 @Override
575 protected BouncyRSAPublicKey getPublicKey() {
576 return (BouncyRSAPublicKey) super.getPublicKey();
577 }
578
579 @Override
580 protected BouncyRSAPrivateKey getPrivateKey() {
581 return (BouncyRSAPrivateKey) super.getPrivateKey();
582 }
583 }
584
585
586
587
588 public static class BouncyCoreEncryptor
589 extends GordianCoreEncryptor {
590
591
592
593 private final AsymmetricBlockCipher theEncryptor;
594
595
596
597
598
599
600
601
602
603 protected BouncyCoreEncryptor(final GordianBaseFactory pFactory,
604 final GordianCoreEncryptorSpec pSpec,
605 final AsymmetricBlockCipher pEngine) throws GordianException {
606
607 super(pFactory, pSpec);
608 final BouncyDigest myDigest = (BouncyDigest) pFactory.getDigestFactory().createDigest(pSpec.getDigestSpec());
609 theEncryptor = new OAEPEncoding(pEngine, myDigest.getDigest(), PSource.PSpecified.DEFAULT.getValue());
610 }
611
612 @Override
613 protected BouncyPublicKey<?> getPublicKey() {
614 return (BouncyPublicKey<?>) super.getPublicKey();
615 }
616
617 @Override
618 protected BouncyPrivateKey<?> getPrivateKey() {
619 return (BouncyPrivateKey<?>) super.getPrivateKey();
620 }
621
622 @Override
623 public void initForEncrypt(final GordianKeyPair pKeyPair) throws GordianException {
624
625 BouncyKeyPair.checkKeyPair(pKeyPair);
626 super.initForEncrypt(pKeyPair);
627
628
629 final ParametersWithRandom myParms = new ParametersWithRandom(getPublicKey().getPublicKey(), getRandom());
630 theEncryptor.init(true, myParms);
631 }
632
633 @Override
634 public void initForDecrypt(final GordianKeyPair pKeyPair) throws GordianException {
635
636 BouncyKeyPair.checkKeyPair(pKeyPair);
637 super.initForDecrypt(pKeyPair);
638
639
640 theEncryptor.init(false, getPrivateKey().getPrivateKey());
641 }
642
643 @Override
644 public byte[] encrypt(final byte[] pBytes) throws GordianException {
645
646 checkMode(GordianEncryptMode.ENCRYPT);
647
648
649 return processData(pBytes);
650 }
651
652 @Override
653 public byte[] decrypt(final byte[] pBytes) throws GordianException {
654
655 checkMode(GordianEncryptMode.DECRYPT);
656
657
658 return processData(pBytes);
659 }
660
661
662
663
664
665
666
667
668 private byte[] processData(final byte[] pData) throws GordianException {
669 try {
670
671 int myInLen = pData.length;
672 final byte[] myOutput = new byte[getProcessedLength(myInLen)];
673
674
675 final int myInBlockLength = theEncryptor.getInputBlockSize();
676
677
678 int myInOff = 0;
679 int myOutOff = 0;
680 while (myInLen > 0) {
681
682 final int myLen = Math.min(myInLen, myInBlockLength);
683 final byte[] myBlock = theEncryptor.processBlock(pData, myInOff, myLen);
684
685
686 final int myOutLen = myBlock.length;
687 System.arraycopy(myBlock, 0, myOutput, myOutOff, myOutLen);
688 myOutOff += myOutLen;
689
690
691 myInOff += myInBlockLength;
692 myInLen -= myInBlockLength;
693 }
694
695
696 if (myOutOff == myOutput.length) {
697 return myOutput;
698 }
699
700
701 final byte[] myReturn = Arrays.copyOf(myOutput, myOutOff);
702 Arrays.fill(myOutput, (byte) 0);
703 return myReturn;
704
705 } catch (InvalidCipherTextException e) {
706 throw new GordianCryptoException("Failed to process data", e);
707 }
708 }
709
710
711
712
713
714
715
716 private int getProcessedLength(final int pLength) {
717 return theEncryptor.getOutputBlockSize() * getNumBlocks(pLength, theEncryptor.getInputBlockSize());
718 }
719
720
721
722
723
724
725
726
727 private static int getNumBlocks(final int pLength, final int pBlockLength) {
728 return (pLength + pBlockLength - 1) / pBlockLength;
729 }
730 }
731 }