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.keypair.GordianKeyPair;
21 import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
22 import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianNewSignParams;
23 import io.github.tonywasher.joceanus.gordianknot.api.sign.spec.GordianSignatureSpec;
24 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPrivateKey;
25 import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPublicKey;
26 import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
27 import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
28 import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
29 import io.github.tonywasher.joceanus.gordianknot.impl.core.sign.GordianCoreSignature;
30 import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
31 import org.bouncycastle.asn1.ASN1Encoding;
32 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
33 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
34 import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
35 import org.bouncycastle.crypto.CryptoException;
36 import org.bouncycastle.crypto.Signer;
37 import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
38 import org.bouncycastle.crypto.generators.Ed448KeyPairGenerator;
39 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
40 import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
41 import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
42 import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
43 import org.bouncycastle.crypto.params.Ed448KeyGenerationParameters;
44 import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters;
45 import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
46 import org.bouncycastle.crypto.signers.Ed25519Signer;
47 import org.bouncycastle.crypto.signers.Ed448Signer;
48 import org.bouncycastle.crypto.util.PrivateKeyFactory;
49 import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
50 import org.bouncycastle.crypto.util.PublicKeyFactory;
51 import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
52
53 import java.io.IOException;
54 import java.security.spec.PKCS8EncodedKeySpec;
55 import java.security.spec.X509EncodedKeySpec;
56 import java.util.Arrays;
57
58
59
60
61 public final class BouncyEdDSAKeyPair {
62
63
64
65 private BouncyEdDSAKeyPair() {
66 }
67
68
69
70
71 public static class BouncyEd25519PublicKey
72 extends BouncyPublicKey<Ed25519PublicKeyParameters> {
73
74
75
76
77
78
79 BouncyEd25519PublicKey(final GordianKeyPairSpec pKeySpec,
80 final Ed25519PublicKeyParameters pPublicKey) {
81 super(pKeySpec, pPublicKey);
82 }
83
84 @Override
85 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
86
87 final Ed25519PublicKeyParameters myThis = getPublicKey();
88 final Ed25519PublicKeyParameters myThat = (Ed25519PublicKeyParameters) pThat;
89
90
91 return Arrays.equals(myThis.getEncoded(), myThat.getEncoded());
92 }
93 }
94
95
96
97
98 public static class BouncyEd25519PrivateKey
99 extends BouncyPrivateKey<Ed25519PrivateKeyParameters> {
100
101
102
103
104
105
106 BouncyEd25519PrivateKey(final GordianKeyPairSpec pKeySpec,
107 final Ed25519PrivateKeyParameters pPrivateKey) {
108 super(pKeySpec, pPrivateKey);
109 }
110
111
112 @Override
113 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
114
115 final Ed25519PrivateKeyParameters myThis = getPrivateKey();
116 final Ed25519PrivateKeyParameters myThat = (Ed25519PrivateKeyParameters) pThat;
117
118
119 return Arrays.equals(myThis.getEncoded(), myThat.getEncoded());
120 }
121 }
122
123
124
125
126 public static class BouncyEd448PublicKey
127 extends BouncyPublicKey<Ed448PublicKeyParameters> {
128
129
130
131
132
133
134 BouncyEd448PublicKey(final GordianKeyPairSpec pKeySpec,
135 final Ed448PublicKeyParameters pPublicKey) {
136 super(pKeySpec, pPublicKey);
137 }
138
139 @Override
140 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
141
142 final Ed448PublicKeyParameters myThis = getPublicKey();
143 final Ed448PublicKeyParameters myThat = (Ed448PublicKeyParameters) pThat;
144
145
146 return Arrays.equals(myThis.getEncoded(), myThat.getEncoded());
147 }
148 }
149
150
151
152
153 public static class BouncyEd448PrivateKey
154 extends BouncyPrivateKey<Ed448PrivateKeyParameters> {
155
156
157
158
159
160
161 BouncyEd448PrivateKey(final GordianKeyPairSpec pKeySpec,
162 final Ed448PrivateKeyParameters pPrivateKey) {
163 super(pKeySpec, pPrivateKey);
164 }
165
166
167 @Override
168 protected boolean matchKey(final AsymmetricKeyParameter pThat) {
169
170 final Ed448PrivateKeyParameters myThis = getPrivateKey();
171 final Ed448PrivateKeyParameters myThat = (Ed448PrivateKeyParameters) pThat;
172
173
174 return Arrays.equals(myThis.getEncoded(), myThat.getEncoded());
175 }
176 }
177
178
179
180
181 public static class BouncyEd25519KeyPairGenerator
182 extends BouncyKeyPairGenerator {
183
184
185
186 private final Ed25519KeyPairGenerator theGenerator;
187
188
189
190
191
192
193
194 BouncyEd25519KeyPairGenerator(final GordianBaseFactory pFactory,
195 final GordianKeyPairSpec pKeySpec) {
196
197 super(pFactory, pKeySpec);
198
199
200 theGenerator = new Ed25519KeyPairGenerator();
201
202
203 final Ed25519KeyGenerationParameters myParams = new Ed25519KeyGenerationParameters(getRandom());
204 theGenerator.init(myParams);
205 }
206
207 @Override
208 public BouncyKeyPair generateKeyPair() {
209
210 final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
211 final BouncyEd25519PublicKey myPublic = new BouncyEd25519PublicKey(getKeySpec(), (Ed25519PublicKeyParameters) myPair.getPublic());
212 final BouncyEd25519PrivateKey myPrivate = new BouncyEd25519PrivateKey(getKeySpec(), (Ed25519PrivateKeyParameters) myPair.getPrivate());
213 return new BouncyKeyPair(myPublic, myPrivate);
214 }
215
216 @Override
217 public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
218
219 try {
220
221 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
222
223
224 final BouncyEd25519PrivateKey myPrivateKey = (BouncyEd25519PrivateKey) getPrivateKey(pKeyPair);
225 final Ed25519PrivateKeyParameters myParms = myPrivateKey.getPrivateKey();
226 final PrivateKeyInfo myInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(myParms);
227 return new PKCS8EncodedKeySpec(myInfo.getEncoded());
228
229 } catch (IOException e) {
230 throw new GordianCryptoException(ERROR_PARSE, e);
231 }
232 }
233
234 @Override
235 public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
236 final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
237
238 try {
239
240 checkKeySpec(pPrivateKey);
241
242
243 final BouncyEd25519PublicKey myPublic = derivePublicKey(pPublicKey);
244 final PrivateKeyInfo myInfo = PrivateKeyInfo.getInstance(pPrivateKey.getEncoded());
245 final Ed25519PrivateKeyParameters myParms = (Ed25519PrivateKeyParameters) PrivateKeyFactory.createKey(myInfo);
246 final BouncyEd25519PrivateKey myPrivate = new BouncyEd25519PrivateKey(getKeySpec(), myParms);
247 final BouncyKeyPair myPair = new BouncyKeyPair(myPublic, myPrivate);
248
249
250 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
251
252
253 return myPair;
254
255 } catch (IOException e) {
256 throw new GordianCryptoException(ERROR_PARSE, e);
257 }
258 }
259
260 @Override
261 public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
262
263 try {
264
265 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
266
267
268 final BouncyEd25519PublicKey myPublicKey = (BouncyEd25519PublicKey) getPublicKey(pKeyPair);
269 final Ed25519PublicKeyParameters myParms = myPublicKey.getPublicKey();
270 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(myParms);
271 final byte[] myBytes = myInfo.getEncoded(ASN1Encoding.DER);
272 return new X509EncodedKeySpec(myBytes);
273
274 } catch (IOException e) {
275 throw new GordianCryptoException(ERROR_PARSE, e);
276 }
277 }
278
279 @Override
280 public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
281 final BouncyEd25519PublicKey myPublic = derivePublicKey(pEncodedKey);
282 return new BouncyKeyPair(myPublic);
283 }
284
285
286
287
288
289
290
291
292 private BouncyEd25519PublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
293
294 try {
295
296 checkKeySpec(pEncodedKey);
297
298
299 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfo.getInstance(pEncodedKey.getEncoded());
300 final Ed25519PublicKeyParameters myParms = (Ed25519PublicKeyParameters) PublicKeyFactory.createKey(myInfo);
301 return new BouncyEd25519PublicKey(getKeySpec(), myParms);
302
303 } catch (IOException e) {
304 throw new GordianCryptoException(ERROR_PARSE, e);
305 }
306 }
307 }
308
309
310
311
312 public static class BouncyEd448KeyPairGenerator
313 extends BouncyKeyPairGenerator {
314
315
316
317 private final Ed448KeyPairGenerator theGenerator;
318
319
320
321
322
323
324
325 BouncyEd448KeyPairGenerator(final GordianBaseFactory pFactory,
326 final GordianKeyPairSpec pKeySpec) {
327
328 super(pFactory, pKeySpec);
329
330
331 theGenerator = new Ed448KeyPairGenerator();
332
333
334 final Ed448KeyGenerationParameters myParams = new Ed448KeyGenerationParameters(getRandom());
335 theGenerator.init(myParams);
336 }
337
338 @Override
339 public BouncyKeyPair generateKeyPair() {
340 final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
341 final BouncyEd448PublicKey myPublic = new BouncyEd448PublicKey(getKeySpec(), (Ed448PublicKeyParameters) myPair.getPublic());
342 final BouncyEd448PrivateKey myPrivate = new BouncyEd448PrivateKey(getKeySpec(), (Ed448PrivateKeyParameters) myPair.getPrivate());
343 return new BouncyKeyPair(myPublic, myPrivate);
344 }
345
346 @Override
347 public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
348 try {
349 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
350 final BouncyEd448PrivateKey myPrivateKey = (BouncyEd448PrivateKey) getPrivateKey(pKeyPair);
351 final Ed448PrivateKeyParameters myParms = myPrivateKey.getPrivateKey();
352 final PrivateKeyInfo myInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(myParms);
353 return new PKCS8EncodedKeySpec(myInfo.getEncoded());
354 } catch (IOException e) {
355 throw new GordianCryptoException(ERROR_PARSE, e);
356 }
357 }
358
359 @Override
360 public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
361 final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
362 try {
363 checkKeySpec(pPrivateKey);
364 final BouncyEd448PublicKey myPublic = derivePublicKey(pPublicKey);
365 final PrivateKeyInfo myInfo = PrivateKeyInfo.getInstance(pPrivateKey.getEncoded());
366 final Ed448PrivateKeyParameters myParms = (Ed448PrivateKeyParameters) PrivateKeyFactory.createKey(myInfo);
367 final BouncyEd448PrivateKey myPrivate = new BouncyEd448PrivateKey(getKeySpec(), myParms);
368 final BouncyKeyPair myPair = new BouncyKeyPair(myPublic, myPrivate);
369 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
370 return myPair;
371 } catch (IOException e) {
372 throw new GordianCryptoException(ERROR_PARSE, e);
373 }
374 }
375
376 @Override
377 public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
378 try {
379 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
380 final BouncyEd448PublicKey myPublicKey = (BouncyEd448PublicKey) getPublicKey(pKeyPair);
381 final Ed448PublicKeyParameters myParms = myPublicKey.getPublicKey();
382 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(myParms);
383 final byte[] myBytes = myInfo.getEncoded(ASN1Encoding.DER);
384 return new X509EncodedKeySpec(myBytes);
385 } catch (IOException e) {
386 throw new GordianCryptoException(ERROR_PARSE, e);
387 }
388 }
389
390 @Override
391 public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
392 final BouncyEd448PublicKey myPublic = derivePublicKey(pEncodedKey);
393 return new BouncyKeyPair(myPublic);
394 }
395
396
397
398
399
400
401
402
403 private BouncyEd448PublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
404 try {
405 checkKeySpec(pEncodedKey);
406 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfo.getInstance(pEncodedKey.getEncoded());
407 final Ed448PublicKeyParameters myParms = (Ed448PublicKeyParameters) PublicKeyFactory.createKey(myInfo);
408 return new BouncyEd448PublicKey(getKeySpec(), myParms);
409 } catch (IOException e) {
410 throw new GordianCryptoException(ERROR_PARSE, e);
411 }
412 }
413 }
414
415
416
417
418 public static class BouncyEdDSASignature
419 extends GordianCoreSignature {
420
421
422
423 private Signer theSigner;
424
425
426
427
428
429
430
431 BouncyEdDSASignature(final GordianBaseFactory pFactory,
432 final GordianSignatureSpec pSpec) {
433
434 super(pFactory, pSpec);
435 }
436
437
438
439
440
441
442
443 private static Signer createSigner(final GordianKeyPair pKeyPair) {
444
445 final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeyPair.getKeyPairSpec();
446 final boolean is25519 = myKeySpec.getEdwardsSpec().is25519();
447 final byte[] myContext = new byte[0];
448
449
450 return is25519
451 ? new Ed25519Signer()
452 : new Ed448Signer(myContext);
453 }
454
455 @Override
456 public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
457
458 super.initForSigning(pParams);
459 final GordianKeyPair myPair = getKeyPair();
460 BouncyKeyPair.checkKeyPair(myPair);
461
462
463 theSigner = createSigner(myPair);
464 final BouncyPrivateKey<?> myPrivate = getKeyPair().getPrivateKey();
465 theSigner.init(true, myPrivate.getPrivateKey());
466 }
467
468 @Override
469 public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
470
471 super.initForVerify(pParams);
472 final GordianKeyPair myPair = getKeyPair();
473 BouncyKeyPair.checkKeyPair(myPair);
474
475
476 theSigner = createSigner(myPair);
477 final BouncyPublicKey<?> myPublic = getKeyPair().getPublicKey();
478 theSigner.init(false, myPublic.getPublicKey());
479 }
480
481 @Override
482 public void update(final byte[] pBytes,
483 final int pOffset,
484 final int pLength) {
485 theSigner.update(pBytes, pOffset, pLength);
486 }
487
488 @Override
489 public void update(final byte pByte) {
490 theSigner.update(pByte);
491 }
492
493 @Override
494 public void update(final byte[] pBytes) {
495 theSigner.update(pBytes, 0, pBytes.length);
496 }
497
498 @Override
499 public void reset() {
500 theSigner.reset();
501 }
502
503 @Override
504 protected BouncyKeyPair getKeyPair() {
505 return (BouncyKeyPair) super.getKeyPair();
506 }
507
508 @Override
509 public byte[] sign() throws GordianException {
510
511 checkMode(GordianSignatureMode.SIGN);
512
513
514 try {
515 return theSigner.generateSignature();
516 } catch (CryptoException e) {
517 throw new GordianCryptoException(BouncySignature.ERROR_SIGGEN, e);
518 }
519 }
520
521 @Override
522 public boolean verify(final byte[] pSignature) throws GordianException {
523
524 checkMode(GordianSignatureMode.VERIFY);
525
526
527 return theSigner.verifySignature(pSignature);
528 }
529 }
530 }