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