1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.github.tonywasher.joceanus.gordianknot.api.cipher;
18
19 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianKeySpec;
20 import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
21 import org.bouncycastle.crypto.engines.ElephantEngine.ElephantParameters;
22 import org.bouncycastle.crypto.engines.ISAPEngine.IsapType;
23 import org.bouncycastle.crypto.engines.RomulusEngine.RomulusParameters;
24 import org.bouncycastle.crypto.engines.SparkleEngine.SparkleParameters;
25
26 import java.util.Objects;
27
28
29
30
31 public class GordianStreamKeySpec
32 implements GordianKeySpec {
33
34
35
36 private static final String SEP = "-";
37
38
39
40
41 private final GordianStreamKeyType theStreamKeyType;
42
43
44
45
46 private final GordianLength theKeyLength;
47
48
49
50
51 private final GordianStreamSubKeyType theSubKeyType;
52
53
54
55
56 private final boolean isValid;
57
58
59
60
61 private String theName;
62
63
64
65
66
67
68
69 public GordianStreamKeySpec(final GordianStreamKeyType pStreamKeyType,
70 final GordianLength pKeyLength) {
71 this(pStreamKeyType, pKeyLength, defaultSubKeyType(pStreamKeyType));
72 }
73
74
75
76
77
78
79
80
81 public GordianStreamKeySpec(final GordianStreamKeyType pStreamKeyType,
82 final GordianLength pKeyLength,
83 final GordianStreamSubKeyType pSubKeyType) {
84
85 theStreamKeyType = pStreamKeyType;
86 theKeyLength = pKeyLength;
87 theSubKeyType = pSubKeyType;
88 isValid = checkValidity();
89 }
90
91
92
93
94
95
96 public GordianStreamKeyType getStreamKeyType() {
97 return theStreamKeyType;
98 }
99
100 @Override
101 public GordianLength getKeyLength() {
102 return theKeyLength;
103 }
104
105
106
107
108
109
110 public GordianStreamSubKeyType getSubKeyType() {
111 return theSubKeyType;
112 }
113
114
115
116
117
118
119 public boolean isValid() {
120 return isValid;
121 }
122
123
124
125
126
127
128 public boolean needsIV() {
129 return getIVLength() > 0;
130 }
131
132
133
134
135
136
137 private boolean checkValidity() {
138
139 if (theStreamKeyType == null
140 || theKeyLength == null) {
141 return false;
142 }
143
144
145 switch (theStreamKeyType) {
146 case SALSA20:
147 return checkSalsaValidity();
148 case CHACHA20:
149 return checkChaChaValidity();
150 case VMPC:
151 return checkVMPCValidity();
152 case SKEINXOF:
153 return checkSkeinValidity();
154 case BLAKE2XOF:
155 return checkBlake2Validity();
156 case ELEPHANT:
157 return theSubKeyType instanceof GordianElephantKey
158 && theStreamKeyType.validForKeyLength(theKeyLength);
159 case ISAP:
160 return theSubKeyType instanceof GordianISAPKey
161 && theStreamKeyType.validForKeyLength(theKeyLength);
162 case ROMULUS:
163 return theSubKeyType instanceof GordianRomulusKey
164 && theStreamKeyType.validForKeyLength(theKeyLength);
165 case SPARKLE:
166 return checkSparkleValidity();
167 default:
168 return theSubKeyType == null
169 && theStreamKeyType.validForKeyLength(theKeyLength);
170 }
171 }
172
173
174
175
176
177
178 private boolean checkSalsaValidity() {
179
180 if (!(theSubKeyType instanceof GordianSalsa20Key)) {
181 return false;
182 }
183
184
185 return theSubKeyType != GordianSalsa20Key.STD
186 ? theKeyLength == GordianLength.LEN_256
187 : theStreamKeyType.validForKeyLength(theKeyLength);
188 }
189
190
191
192
193
194
195 private boolean checkChaChaValidity() {
196
197 if (!(theSubKeyType instanceof GordianChaCha20Key)) {
198 return false;
199 }
200
201
202 return theSubKeyType != GordianChaCha20Key.STD
203 ? theKeyLength == GordianLength.LEN_256
204 : theStreamKeyType.validForKeyLength(theKeyLength);
205 }
206
207
208
209
210
211
212 private boolean checkVMPCValidity() {
213
214 if (!(theSubKeyType instanceof GordianVMPCKey)) {
215 return false;
216 }
217
218
219 return theStreamKeyType.validForKeyLength(theKeyLength);
220 }
221
222
223
224
225
226
227 private boolean checkSkeinValidity() {
228
229 if (!(theSubKeyType instanceof GordianSkeinXofKey)) {
230 return false;
231 }
232
233
234 return theStreamKeyType.validForKeyLength(theKeyLength);
235 }
236
237
238
239
240
241
242 private boolean checkBlake2Validity() {
243
244 if (!(theSubKeyType instanceof GordianBlakeXofKey)) {
245 return false;
246 }
247
248
249 final GordianBlakeXofKey myType = (GordianBlakeXofKey) theSubKeyType;
250 return theStreamKeyType.validForKeyLength(theKeyLength)
251 && (myType != GordianBlakeXofKey.BLAKE2XS
252 || theKeyLength != GordianLength.LEN_512);
253 }
254
255
256
257
258
259
260 private boolean checkSparkleValidity() {
261
262 if (!(theSubKeyType instanceof GordianSparkleKey)) {
263 return false;
264 }
265
266
267 return theKeyLength == ((GordianSparkleKey) theSubKeyType).requiredKeyLength();
268 }
269
270 @Override
271 public String toString() {
272
273 if (theName == null) {
274
275 if (isValid) {
276
277 theName = getName();
278 theName += SEP + theKeyLength;
279 } else {
280
281 theName = "InvalidStreamKeySpec: " + theStreamKeyType + ":" + theKeyLength;
282 }
283 }
284
285
286 return theName;
287 }
288
289
290
291
292
293
294 private String getName() {
295
296 if (theStreamKeyType == GordianStreamKeyType.VMPC
297 && theSubKeyType == GordianVMPCKey.KSA) {
298 return theStreamKeyType + "KSA3";
299 }
300
301
302 if (theStreamKeyType == GordianStreamKeyType.SALSA20
303 && theSubKeyType == GordianSalsa20Key.XSALSA) {
304 return "X" + theStreamKeyType;
305 }
306
307
308 if (theStreamKeyType == GordianStreamKeyType.CHACHA20
309 && theSubKeyType == GordianChaCha20Key.XCHACHA) {
310 return "X" + theStreamKeyType;
311 }
312
313
314 if (theStreamKeyType == GordianStreamKeyType.CHACHA20
315 && theSubKeyType == GordianChaCha20Key.ISO7539) {
316 return "ChaCha7539";
317 }
318
319
320 if (theStreamKeyType == GordianStreamKeyType.SKEINXOF) {
321 return theStreamKeyType + SEP + theSubKeyType.toString();
322 }
323
324
325 switch (theStreamKeyType) {
326 case BLAKE2XOF:
327 case ELEPHANT:
328 case ISAP:
329 case ROMULUS:
330 case SPARKLE:
331 return theSubKeyType.toString();
332 default:
333 return theStreamKeyType.toString();
334 }
335 }
336
337
338
339
340
341
342 public int getIVLength() {
343 switch (theStreamKeyType) {
344 case RABBIT:
345 return GordianLength.LEN_64.getByteLength();
346 case GRAIN:
347 case ELEPHANT:
348 return GordianLength.LEN_96.getByteLength();
349 case SOSEMANUK:
350 case SNOW3G:
351 case BLAKE3XOF:
352 case SKEINXOF:
353 case ASCON:
354 case ISAP:
355 case PHOTONBEETLE:
356 case ROMULUS:
357 case XOODYAK:
358 return GordianLength.LEN_128.getByteLength();
359 case HC:
360 return GordianLength.LEN_128 == theKeyLength
361 ? GordianLength.LEN_128.getByteLength()
362 : GordianLength.LEN_256.getByteLength();
363 case ZUC:
364 return GordianLength.LEN_128 == theKeyLength
365 ? GordianLength.LEN_128.getByteLength()
366 : GordianLength.LEN_200.getByteLength();
367 case VMPC:
368 return theKeyLength.getByteLength();
369 case BLAKE2XOF:
370 return ((GordianBlakeXofKey) theSubKeyType).requiredIVLength().getByteLength();
371 case CHACHA20:
372 return ((GordianChaCha20Key) theSubKeyType).requiredIVLength().getByteLength();
373 case SALSA20:
374 return ((GordianSalsa20Key) theSubKeyType).requiredIVLength().getByteLength();
375 case SPARKLE:
376 return ((GordianSparkleKey) theSubKeyType).requiredIVLength().getByteLength();
377 case ISAAC:
378 case RC4:
379 default:
380 return 0;
381 }
382 }
383
384
385
386
387
388
389 public boolean supportsAEAD() {
390 return theStreamKeyType == GordianStreamKeyType.CHACHA20
391 && theSubKeyType != GordianChaCha20Key.STD;
392 }
393
394
395
396
397
398
399 public boolean isAEAD() {
400 switch (theStreamKeyType) {
401 case ASCON:
402 case ELEPHANT:
403 case ISAP:
404 case PHOTONBEETLE:
405 case ROMULUS:
406 case SPARKLE:
407 case XOODYAK:
408 return true;
409 default:
410 return false;
411 }
412 }
413
414 @Override
415 public boolean equals(final Object pThat) {
416
417 if (this == pThat) {
418 return true;
419 }
420 if (pThat == null) {
421 return false;
422 }
423
424
425 return pThat instanceof GordianStreamKeySpec myThat
426 && theStreamKeyType == myThat.getStreamKeyType()
427 && theKeyLength == myThat.getKeyLength()
428 && theSubKeyType == myThat.getSubKeyType();
429 }
430
431 @Override
432 public int hashCode() {
433 return Objects.hash(theStreamKeyType, theKeyLength, theSubKeyType);
434 }
435
436
437
438
439
440
441
442 private static GordianStreamSubKeyType defaultSubKeyType(final GordianStreamKeyType pKeyType) {
443
444 switch (pKeyType) {
445 case SALSA20:
446 return GordianSalsa20Key.STD;
447 case CHACHA20:
448 return GordianChaCha20Key.STD;
449 case VMPC:
450 return GordianVMPCKey.STD;
451 case SKEINXOF:
452 return GordianSkeinXofKey.STATE1024;
453 case BLAKE2XOF:
454 return GordianBlakeXofKey.BLAKE2XB;
455 case ELEPHANT:
456 return GordianElephantKey.ELEPHANT160;
457 case ISAP:
458 return GordianISAPKey.ISAPA128;
459 case ROMULUS:
460 return GordianRomulusKey.ROMULUS_M;
461 case SPARKLE:
462 return GordianSparkleKey.SPARKLE128_128;
463 default:
464 return null;
465 }
466 }
467
468
469
470
471 public interface GordianStreamSubKeyType {
472 }
473
474
475
476
477 public enum GordianVMPCKey
478 implements GordianStreamSubKeyType {
479
480
481
482 STD,
483
484
485
486
487 KSA;
488 }
489
490
491
492
493 public enum GordianSalsa20Key
494 implements GordianStreamSubKeyType {
495
496
497
498 STD,
499
500
501
502
503 XSALSA;
504
505
506
507
508
509
510 GordianLength requiredIVLength() {
511 switch (this) {
512 case STD:
513 return GordianLength.LEN_64;
514 case XSALSA:
515 default:
516 return GordianLength.LEN_192;
517 }
518 }
519 }
520
521
522
523
524 public enum GordianChaCha20Key
525 implements GordianStreamSubKeyType {
526
527
528
529 STD,
530
531
532
533
534 ISO7539,
535
536
537
538
539 XCHACHA;
540
541
542
543
544
545
546 GordianLength requiredIVLength() {
547 switch (this) {
548 case STD:
549 return GordianLength.LEN_64;
550 case ISO7539:
551 return GordianLength.LEN_96;
552 case XCHACHA:
553 default:
554 return GordianLength.LEN_192;
555 }
556 }
557 }
558
559
560
561
562 public enum GordianSkeinXofKey
563 implements GordianStreamSubKeyType {
564
565
566
567 STATE256(GordianLength.LEN_256),
568
569
570
571
572 STATE512(GordianLength.LEN_512),
573
574
575
576
577 STATE1024(GordianLength.LEN_1024);
578
579
580
581
582 private final GordianLength theLength;
583
584
585
586
587
588
589 GordianSkeinXofKey(final GordianLength pLength) {
590 theLength = pLength;
591 }
592
593
594
595
596
597
598 public GordianLength getLength() {
599 return theLength;
600 }
601
602 @Override
603 public String toString() {
604 return theLength.toString();
605 }
606
607
608
609
610
611
612
613 public static GordianSkeinXofKey getKeyTypeForLength(final GordianLength pLength) {
614 for (GordianSkeinXofKey myType : values()) {
615 if (pLength == myType.theLength) {
616 return myType;
617 }
618 }
619 throw new IllegalArgumentException("Unsupported state length");
620 }
621 }
622
623
624
625
626 public enum GordianBlakeXofKey
627 implements GordianStreamSubKeyType {
628
629
630
631 BLAKE2XS,
632
633
634
635
636 BLAKE2XB;
637
638 @Override
639 public String toString() {
640 return this == BLAKE2XB ? "Blake2Xb" : "Blake2Xs";
641 }
642
643
644
645
646
647
648 GordianLength requiredIVLength() {
649 switch (this) {
650 case BLAKE2XS:
651 return GordianLength.LEN_64;
652 case BLAKE2XB:
653 default:
654 return GordianLength.LEN_128;
655 }
656 }
657 }
658
659
660
661
662 public enum GordianElephantKey
663 implements GordianStreamSubKeyType {
664
665
666
667 ELEPHANT160,
668
669
670
671
672 ELEPHANT176,
673
674
675
676
677 ELEPHANT200;
678
679 @Override
680 public String toString() {
681 final String myBase = GordianStreamKeyType.ELEPHANT.toString();
682 switch (this) {
683 case ELEPHANT160:
684 return myBase + "160";
685 case ELEPHANT176:
686 return myBase + "176";
687 case ELEPHANT200:
688 default:
689 return myBase + "200";
690 }
691 }
692
693
694
695
696
697
698 public ElephantParameters getParameters() {
699 switch (this) {
700 case ELEPHANT160:
701 return ElephantParameters.elephant160;
702 case ELEPHANT176:
703 return ElephantParameters.elephant176;
704 case ELEPHANT200:
705 default:
706 return ElephantParameters.elephant200;
707 }
708 }
709 }
710
711
712
713
714 public enum GordianISAPKey
715 implements GordianStreamSubKeyType {
716
717
718
719 ISAPA128,
720
721
722
723
724 ISAPA128A,
725
726
727
728
729 ISAPK128,
730
731
732
733
734 ISAPK128A;
735
736 @Override
737 public String toString() {
738 final String myBase = GordianStreamKeyType.ISAP.toString();
739 switch (this) {
740 case ISAPA128:
741 return myBase + "A128";
742 case ISAPA128A:
743 return myBase + "A128A";
744 case ISAPK128:
745 return myBase + "K128";
746 case ISAPK128A:
747 default:
748 return myBase + "K128A";
749 }
750 }
751
752
753
754
755
756
757 public IsapType getType() {
758 switch (this) {
759 case ISAPA128:
760 return IsapType.ISAP_A_128;
761 case ISAPA128A:
762 return IsapType.ISAP_A_128A;
763 case ISAPK128:
764 return IsapType.ISAP_K_128;
765 case ISAPK128A:
766 default:
767 return IsapType.ISAP_K_128A;
768 }
769 }
770 }
771
772
773
774
775 public enum GordianRomulusKey
776 implements GordianStreamSubKeyType {
777
778
779
780 ROMULUS_M,
781
782
783
784
785 ROMULUS_N,
786
787
788
789
790 ROMULUS_T;
791
792 @Override
793 public String toString() {
794 final String myBase = GordianStreamKeyType.ROMULUS.toString();
795 switch (this) {
796 case ROMULUS_M:
797 return myBase + "-M";
798 case ROMULUS_N:
799 return myBase + "-N";
800 case ROMULUS_T:
801 default:
802 return myBase + "-T";
803 }
804 }
805
806
807
808
809
810
811 public RomulusParameters getParameters() {
812 switch (this) {
813 case ROMULUS_M:
814 return RomulusParameters.RomulusM;
815 case ROMULUS_N:
816 return RomulusParameters.RomulusN;
817 case ROMULUS_T:
818 default:
819 return RomulusParameters.RomulusT;
820 }
821 }
822 }
823
824
825
826
827 public enum GordianSparkleKey
828 implements GordianStreamSubKeyType {
829
830
831
832 SPARKLE128_128,
833
834
835
836
837 SPARKLE256_128,
838
839
840
841
842 SPARKLE192_192,
843
844
845
846
847 SPARKLE256_256;
848
849 @Override
850 public String toString() {
851 final String myBase = GordianStreamKeyType.SPARKLE.toString();
852 switch (this) {
853 case SPARKLE128_128:
854 return myBase + "128_128";
855 case SPARKLE256_128:
856 return myBase + "256_128";
857 case SPARKLE192_192:
858 return myBase + "192_192";
859 case SPARKLE256_256:
860 default:
861 return myBase + "256_256";
862 }
863 }
864
865
866
867
868
869
870 GordianLength requiredKeyLength() {
871 switch (this) {
872 case SPARKLE128_128:
873 case SPARKLE256_128:
874 return GordianLength.LEN_128;
875 case SPARKLE192_192:
876 return GordianLength.LEN_192;
877 case SPARKLE256_256:
878 default:
879 return GordianLength.LEN_256;
880 }
881 }
882
883
884
885
886
887
888 GordianLength requiredIVLength() {
889 switch (this) {
890 case SPARKLE128_128:
891 return GordianLength.LEN_128;
892 case SPARKLE192_192:
893 return GordianLength.LEN_192;
894 case SPARKLE256_128:
895 case SPARKLE256_256:
896 default:
897 return GordianLength.LEN_256;
898 }
899 }
900
901
902
903
904
905
906 public SparkleParameters getParameters() {
907 switch (this) {
908 case SPARKLE128_128:
909 return SparkleParameters.SCHWAEMM128_128;
910 case SPARKLE256_128:
911 return SparkleParameters.SCHWAEMM256_128;
912 case SPARKLE192_192:
913 return SparkleParameters.SCHWAEMM192_192;
914 case SPARKLE256_256:
915 default:
916 return SparkleParameters.SCHWAEMM256_256;
917 }
918 }
919 }
920 }