1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.api.keypair;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianLMSKeySpec.GordianHSSKeySpec;
20 import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianXMSSKeySpec.GordianXMSSDigestType;
21
22 import java.util.ArrayList;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Objects;
26
27
28
29
30 public class GordianKeyPairSpec {
31
32
33
34 private static final String SEP = "-";
35
36
37
38
39 private final GordianKeyPairType theKeyPairType;
40
41
42
43
44 private final Object theSubKeyType;
45
46
47
48
49 private final boolean isValid;
50
51
52
53
54 private String theName;
55
56
57
58
59
60
61
62 public GordianKeyPairSpec(final GordianKeyPairType pKeyType,
63 final Object pSubKeyType) {
64 theKeyPairType = pKeyType;
65 theSubKeyType = pSubKeyType;
66 isValid = checkValidity();
67 }
68
69
70
71
72
73
74 public GordianKeyPairType getKeyPairType() {
75 return theKeyPairType;
76 }
77
78
79
80
81
82
83 public Object getSubKeyType() {
84 return theSubKeyType;
85 }
86
87
88
89
90
91
92 public boolean isValid() {
93 return isValid;
94 }
95
96
97
98
99
100
101 public GordianRSAModulus getRSAModulus() {
102 if (theSubKeyType instanceof GordianRSAModulus myMod) {
103 return myMod;
104 }
105 throw new IllegalArgumentException();
106 }
107
108
109
110
111
112
113 public GordianDSAKeyType getDSAKeyType() {
114 if (theSubKeyType instanceof GordianDSAKeyType myType) {
115 return myType;
116 }
117 throw new IllegalArgumentException();
118 }
119
120
121
122
123
124
125 public GordianDHGroup getDHGroup() {
126 if (theSubKeyType instanceof GordianDHGroup myGroup) {
127 return myGroup;
128 }
129 throw new IllegalArgumentException();
130 }
131
132
133
134
135
136
137 public GordianElliptic getElliptic() {
138 if (theSubKeyType instanceof GordianElliptic myElliptic) {
139 return myElliptic;
140 }
141 throw new IllegalArgumentException();
142 }
143
144
145
146
147
148
149 public GordianEdwardsElliptic getEdwardsElliptic() {
150 if (theSubKeyType instanceof GordianEdwardsElliptic myElliptic) {
151 return myElliptic;
152 }
153 throw new IllegalArgumentException();
154 }
155
156
157
158
159
160
161 public GordianLMSKeySpec getLMSKeySpec() {
162 if (theSubKeyType instanceof GordianLMSKeySpec mySpec) {
163 return mySpec;
164 }
165 throw new IllegalArgumentException();
166 }
167
168
169
170
171
172
173 public GordianHSSKeySpec getHSSKeySpec() {
174 if (theSubKeyType instanceof GordianHSSKeySpec mySpec) {
175 return mySpec;
176 }
177 throw new IllegalArgumentException();
178 }
179
180
181
182
183
184
185 public GordianXMSSKeySpec getXMSSKeySpec() {
186 if (theSubKeyType instanceof GordianXMSSKeySpec mySpec) {
187 return mySpec;
188 }
189 throw new IllegalArgumentException();
190 }
191
192
193
194
195
196
197 public GordianXMSSDigestType getXMSSDigestType() {
198 return getXMSSKeySpec().getDigestType();
199 }
200
201
202
203
204
205
206 public GordianSLHDSASpec getSLHDSAKeySpec() {
207 if (theSubKeyType instanceof GordianSLHDSASpec mySpec) {
208 return mySpec;
209 }
210 throw new IllegalArgumentException();
211 }
212
213
214
215
216
217
218 public GordianCMCESpec getCMCEKeySpec() {
219 if (theSubKeyType instanceof GordianCMCESpec mySpec) {
220 return mySpec;
221 }
222 throw new IllegalArgumentException();
223 }
224
225
226
227
228
229
230 public GordianFRODOSpec getFRODOKeySpec() {
231 if (theSubKeyType instanceof GordianFRODOSpec mySpec) {
232 return mySpec;
233 }
234 throw new IllegalArgumentException();
235 }
236
237
238
239
240
241
242 public GordianSABERSpec getSABERKeySpec() {
243 if (theSubKeyType instanceof GordianSABERSpec mySpec) {
244 return mySpec;
245 }
246 throw new IllegalArgumentException();
247 }
248
249
250
251
252
253
254 public GordianMLKEMSpec getMLKEMKeySpec() {
255 if (theSubKeyType instanceof GordianMLKEMSpec mySpec) {
256 return mySpec;
257 }
258 throw new IllegalArgumentException();
259 }
260
261
262
263
264
265
266 public GordianMLDSASpec getMLDSAKeySpec() {
267 if (theSubKeyType instanceof GordianMLDSASpec mySpec) {
268 return mySpec;
269 }
270 throw new IllegalArgumentException();
271 }
272
273
274
275
276
277
278 public GordianHQCSpec getHQCKeySpec() {
279 if (theSubKeyType instanceof GordianHQCSpec mySpec) {
280 return mySpec;
281 }
282 throw new IllegalArgumentException();
283 }
284
285
286
287
288
289
290 public GordianBIKESpec getBIKEKeySpec() {
291 if (theSubKeyType instanceof GordianBIKESpec mySpec) {
292 return mySpec;
293 }
294 throw new IllegalArgumentException();
295 }
296
297
298
299
300
301
302 public GordianNTRUSpec getNTRUKeySpec() {
303 if (theSubKeyType instanceof GordianNTRUSpec mySpec) {
304 return mySpec;
305 }
306 throw new IllegalArgumentException();
307 }
308
309
310
311
312
313
314 public GordianNTRUPrimeSpec getNTRUPrimeKeySpec() {
315 if (theSubKeyType instanceof GordianNTRUPrimeSpec mySpec) {
316 return mySpec;
317 }
318 throw new IllegalArgumentException();
319 }
320
321
322
323
324
325
326 public GordianFalconSpec getFalconKeySpec() {
327 if (theSubKeyType instanceof GordianFalconSpec mySpec) {
328 return mySpec;
329 }
330 throw new IllegalArgumentException();
331 }
332
333
334
335
336
337
338 public GordianMayoSpec getMayoKeySpec() {
339 if (theSubKeyType instanceof GordianMayoSpec mySpec) {
340 return mySpec;
341 }
342 throw new IllegalArgumentException();
343 }
344
345
346
347
348
349
350 public GordianSnovaSpec getSnovaKeySpec() {
351 if (theSubKeyType instanceof GordianSnovaSpec mySpec) {
352 return mySpec;
353 }
354 throw new IllegalArgumentException();
355 }
356
357
358
359
360
361
362 public GordianPicnicSpec getPicnicKeySpec() {
363 if (theSubKeyType instanceof GordianPicnicSpec mySpec) {
364 return mySpec;
365 }
366 throw new IllegalArgumentException();
367 }
368
369
370
371
372
373
374 @SuppressWarnings("unchecked")
375 public Iterator<GordianKeyPairSpec> keySpecIterator() {
376 if (theSubKeyType instanceof List) {
377 return ((List<GordianKeyPairSpec>) theSubKeyType).iterator();
378 }
379 throw new IllegalArgumentException();
380 }
381
382 @Override
383 public String toString() {
384
385 if (theName == null) {
386
387 if (isValid) {
388
389 deriveName();
390 } else {
391
392 theName = "InvalidKeyPairSpec: " + theKeyPairType + ":" + theSubKeyType;
393 }
394 }
395
396
397 return theName;
398 }
399
400
401
402
403 private void deriveName() {
404
405 theName = theKeyPairType.toString();
406 if (theSubKeyType != null) {
407 switch (theKeyPairType) {
408 case XMSS:
409 theName = theSubKeyType.toString();
410 break;
411 case EDDSA:
412 theName = "Ed" + ((GordianEdwardsElliptic) theSubKeyType).getSuffix();
413 break;
414 case XDH:
415 theName = "X" + ((GordianEdwardsElliptic) theSubKeyType).getSuffix();
416 break;
417 case COMPOSITE:
418 final Iterator<GordianKeyPairSpec> myIterator = keySpecIterator();
419 final StringBuilder myBuilder = new StringBuilder(theName);
420 while (myIterator.hasNext()) {
421 myBuilder.append(SEP).append(myIterator.next().toString());
422 }
423 theName = myBuilder.toString();
424 break;
425 default:
426 theName += SEP + theSubKeyType;
427 break;
428 }
429 }
430 }
431
432 @Override
433 public boolean equals(final Object pThat) {
434
435 if (this == pThat) {
436 return true;
437 }
438 if (pThat == null) {
439 return false;
440 }
441
442
443 return pThat instanceof GordianKeyPairSpec myThat
444 && theKeyPairType == myThat.getKeyPairType()
445 && Objects.equals(theSubKeyType, myThat.theSubKeyType);
446 }
447
448 @Override
449 public int hashCode() {
450 return Objects.hash(theKeyPairType, theSubKeyType);
451 }
452
453
454
455
456
457
458 private boolean checkValidity() {
459
460 if (theKeyPairType == null) {
461 return false;
462 }
463
464
465 switch (theKeyPairType) {
466 case RSA:
467 return theSubKeyType instanceof GordianRSAModulus;
468 case DSA:
469 return theSubKeyType instanceof GordianDSAKeyType;
470 case DH:
471 case ELGAMAL:
472 return theSubKeyType instanceof GordianDHGroup;
473 case EC:
474 return theSubKeyType instanceof GordianDSAElliptic;
475 case SM2:
476 return theSubKeyType instanceof GordianSM2Elliptic;
477 case GOST2012:
478 return theSubKeyType instanceof GordianGOSTElliptic;
479 case DSTU4145:
480 return theSubKeyType instanceof GordianDSTU4145Elliptic;
481 case XMSS:
482 return theSubKeyType instanceof GordianXMSSKeySpec s && s.isValid();
483 case SLHDSA:
484 return theSubKeyType instanceof GordianSLHDSASpec;
485 case CMCE:
486 return theSubKeyType instanceof GordianCMCESpec;
487 case FRODO:
488 return theSubKeyType instanceof GordianFRODOSpec;
489 case SABER:
490 return theSubKeyType instanceof GordianSABERSpec;
491 case MLKEM:
492 return theSubKeyType instanceof GordianMLKEMSpec;
493 case MLDSA:
494 return theSubKeyType instanceof GordianMLDSASpec;
495 case HQC:
496 return theSubKeyType instanceof GordianHQCSpec;
497 case BIKE:
498 return theSubKeyType instanceof GordianBIKESpec;
499 case NTRU:
500 return theSubKeyType instanceof GordianNTRUSpec;
501 case NTRUPRIME:
502 return theSubKeyType instanceof GordianNTRUPrimeSpec;
503 case FALCON:
504 return theSubKeyType instanceof GordianFalconSpec;
505 case MAYO:
506 return theSubKeyType instanceof GordianMayoSpec;
507 case SNOVA:
508 return theSubKeyType instanceof GordianSnovaSpec;
509 case PICNIC:
510 return theSubKeyType instanceof GordianPicnicSpec;
511 case NEWHOPE:
512 return theSubKeyType == null;
513 case LMS:
514 return (theSubKeyType instanceof GordianLMSKeySpec ls && ls.isValid())
515 || (theSubKeyType instanceof GordianHSSKeySpec hs && hs.isValid());
516 case EDDSA:
517 case XDH:
518 return theSubKeyType instanceof GordianEdwardsElliptic;
519 case COMPOSITE:
520 return theSubKeyType instanceof List && checkComposite();
521 default:
522 return false;
523 }
524 }
525
526
527
528
529
530
531 private boolean checkComposite() {
532 Boolean stateAware = null;
533 final List<GordianKeyPairType> myExisting = new ArrayList<>();
534 final Iterator<GordianKeyPairSpec> myIterator = keySpecIterator();
535 while (myIterator.hasNext()) {
536
537 final GordianKeyPairSpec mySpec = myIterator.next();
538 if (mySpec == null) {
539 return false;
540 }
541
542
543 final GordianKeyPairType myType = mySpec.getKeyPairType();
544 if (myExisting.contains(myType) || myType == GordianKeyPairType.COMPOSITE) {
545 return false;
546 }
547
548
549 if (stateAware == null) {
550 stateAware = mySpec.isStateAware();
551 } else if (mySpec.isStateAware() != stateAware) {
552 return false;
553 }
554
555
556 myExisting.add(myType);
557 }
558
559
560 return myExisting.size() > 1;
561 }
562
563
564
565
566
567
568 public boolean isStateAware() {
569 switch (theKeyPairType) {
570 case XMSS:
571 case LMS:
572 return true;
573 case COMPOSITE:
574 return keySpecIterator().next().isStateAware();
575 default:
576 return false;
577 }
578 }
579 }