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