View Javadoc
1   /*
2    * GordianKnot: Security Suite
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
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   * GordianKnot StreamKeySpec.
30   */
31  public class GordianStreamKeySpec
32          implements GordianKeySpec {
33      /**
34       * The Separator.
35       */
36      private static final String SEP = "-";
37  
38      /**
39       * The StreamKey Type.
40       */
41      private final GordianStreamKeyType theStreamKeyType;
42  
43      /**
44       * The Key Length.
45       */
46      private final GordianLength theKeyLength;
47  
48      /**
49       * SubKeyType.
50       */
51      private final GordianStreamSubKeyType theSubKeyType;
52  
53      /**
54       * The Validity.
55       */
56      private final boolean isValid;
57  
58      /**
59       * The String name.
60       */
61      private String theName;
62  
63      /**
64       * Constructor.
65       *
66       * @param pStreamKeyType the streamKeyType
67       * @param pKeyLength     the keyLength
68       */
69      public GordianStreamKeySpec(final GordianStreamKeyType pStreamKeyType,
70                                  final GordianLength pKeyLength) {
71          this(pStreamKeyType, pKeyLength, defaultSubKeyType(pStreamKeyType));
72      }
73  
74      /**
75       * Constructor.
76       *
77       * @param pStreamKeyType the streamKeyType
78       * @param pKeyLength     the keyLength
79       * @param pSubKeyType    the subKeyType
80       */
81      public GordianStreamKeySpec(final GordianStreamKeyType pStreamKeyType,
82                                  final GordianLength pKeyLength,
83                                  final GordianStreamSubKeyType pSubKeyType) {
84          /* Store parameters */
85          theStreamKeyType = pStreamKeyType;
86          theKeyLength = pKeyLength;
87          theSubKeyType = pSubKeyType;
88          isValid = checkValidity();
89      }
90  
91      /**
92       * Obtain streamKey Type.
93       *
94       * @return the streamKeyType
95       */
96      public GordianStreamKeyType getStreamKeyType() {
97          return theStreamKeyType;
98      }
99  
100     @Override
101     public GordianLength getKeyLength() {
102         return theKeyLength;
103     }
104 
105     /**
106      * Obtain subKey Type.
107      *
108      * @return the subKeyType
109      */
110     public GordianStreamSubKeyType getSubKeyType() {
111         return theSubKeyType;
112     }
113 
114     /**
115      * Is the keySpec valid?
116      *
117      * @return true/false.
118      */
119     public boolean isValid() {
120         return isValid;
121     }
122 
123     /**
124      * Does this cipher need an IV?
125      *
126      * @return true/false
127      */
128     public boolean needsIV() {
129         return getIVLength() > 0;
130     }
131 
132     /**
133      * Check spec validity.
134      *
135      * @return valid true/false
136      */
137     private boolean checkValidity() {
138         /* Stream KeyType and Key length must be non-null */
139         if (theStreamKeyType == null
140                 || theKeyLength == null) {
141             return false;
142         }
143 
144         /* Check subKeyTypes */
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      * Check salsa spec validity.
175      *
176      * @return valid true/false
177      */
178     private boolean checkSalsaValidity() {
179         /* SubKeyType must be a SalsaKey */
180         if (!(theSubKeyType instanceof GordianSalsa20Key)) {
181             return false;
182         }
183 
184         /* Check keyLength validity */
185         return theSubKeyType != GordianSalsa20Key.STD
186                 ? theKeyLength == GordianLength.LEN_256
187                 : theStreamKeyType.validForKeyLength(theKeyLength);
188     }
189 
190     /**
191      * Check chacha spec validity.
192      *
193      * @return valid true/false
194      */
195     private boolean checkChaChaValidity() {
196         /* SubKeyType must be a ChaChaKey */
197         if (!(theSubKeyType instanceof GordianChaCha20Key)) {
198             return false;
199         }
200 
201         /* Check keyLength validity */
202         return theSubKeyType != GordianChaCha20Key.STD
203                 ? theKeyLength == GordianLength.LEN_256
204                 : theStreamKeyType.validForKeyLength(theKeyLength);
205     }
206 
207     /**
208      * Check vmpc spec validity.
209      *
210      * @return valid true/false
211      */
212     private boolean checkVMPCValidity() {
213         /* SubKeyType must be a GordianVMPCKey */
214         if (!(theSubKeyType instanceof GordianVMPCKey)) {
215             return false;
216         }
217 
218         /* Check keyLength validity */
219         return theStreamKeyType.validForKeyLength(theKeyLength);
220     }
221 
222     /**
223      * Check skein spec validity.
224      *
225      * @return valid true/false
226      */
227     private boolean checkSkeinValidity() {
228         /* SubKeyType must be a GordianSkeinXofKey */
229         if (!(theSubKeyType instanceof GordianSkeinXofKey)) {
230             return false;
231         }
232 
233         /* Check keyLength validity */
234         return theStreamKeyType.validForKeyLength(theKeyLength);
235     }
236 
237     /**
238      * Check blake2 spec validity.
239      *
240      * @return valid true/false
241      */
242     private boolean checkBlake2Validity() {
243         /* SubKeyType must be a GordianBlakeXofKey */
244         if (!(theSubKeyType instanceof GordianBlakeXofKey)) {
245             return false;
246         }
247 
248         /* Check keyLength validity */
249         final GordianBlakeXofKey myType = (GordianBlakeXofKey) theSubKeyType;
250         return theStreamKeyType.validForKeyLength(theKeyLength)
251                 && (myType != GordianBlakeXofKey.BLAKE2XS
252                 || theKeyLength != GordianLength.LEN_512);
253     }
254 
255     /**
256      * Check sparkle spec validity.
257      *
258      * @return valid true/false
259      */
260     private boolean checkSparkleValidity() {
261         /* SubKeyType must be a GordianSparkleKey */
262         if (!(theSubKeyType instanceof GordianSparkleKey)) {
263             return false;
264         }
265 
266         /* Check keyLength validity */
267         return theKeyLength == ((GordianSparkleKey) theSubKeyType).requiredKeyLength();
268     }
269 
270     @Override
271     public String toString() {
272         /* If we have not yet loaded the name */
273         if (theName == null) {
274             /* If the keySpec is valid */
275             if (isValid) {
276                 /* Load the name */
277                 theName = getName();
278                 theName += SEP + theKeyLength;
279             } else {
280                 /* Report invalid spec */
281                 theName = "InvalidStreamKeySpec: " + theStreamKeyType + ":" + theKeyLength;
282             }
283         }
284 
285         /* return the name */
286         return theName;
287     }
288 
289     /**
290      * Determine the name for the KeySpec.
291      *
292      * @return the name
293      */
294     private String getName() {
295         /* Handle VMPC-KSA */
296         if (theStreamKeyType == GordianStreamKeyType.VMPC
297                 && theSubKeyType == GordianVMPCKey.KSA) {
298             return theStreamKeyType + "KSA3";
299         }
300 
301         /* Handle XSalsa20 */
302         if (theStreamKeyType == GordianStreamKeyType.SALSA20
303                 && theSubKeyType == GordianSalsa20Key.XSALSA) {
304             return "X" + theStreamKeyType;
305         }
306 
307         /* Handle XChaCha20 */
308         if (theStreamKeyType == GordianStreamKeyType.CHACHA20
309                 && theSubKeyType == GordianChaCha20Key.XCHACHA) {
310             return "X" + theStreamKeyType;
311         }
312 
313         /* Handle ChaCha7539 */
314         if (theStreamKeyType == GordianStreamKeyType.CHACHA20
315                 && theSubKeyType == GordianChaCha20Key.ISO7539) {
316             return "ChaCha7539";
317         }
318 
319         /* Handle Skein */
320         if (theStreamKeyType == GordianStreamKeyType.SKEINXOF) {
321             return theStreamKeyType + SEP + theSubKeyType.toString();
322         }
323 
324         /* Handle Remaining types */
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      * Obtain the IV Length.
339      *
340      * @return the IV length.
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      * Does this keySpec optionally support AEAD?
386      *
387      * @return true/false
388      */
389     public boolean supportsAEAD() {
390         return theStreamKeyType == GordianStreamKeyType.CHACHA20
391                 && theSubKeyType != GordianChaCha20Key.STD;
392     }
393 
394     /**
395      * Is this keySpec an AEAD keySpec?
396      *
397      * @return true/false
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         /* Handle the trivial cases */
417         if (this == pThat) {
418             return true;
419         }
420         if (pThat == null) {
421             return false;
422         }
423 
424         /* Check subFields */
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      * Default subKeyType.
438      *
439      * @param pKeyType the keyType
440      * @return the default
441      */
442     private static GordianStreamSubKeyType defaultSubKeyType(final GordianStreamKeyType pKeyType) {
443         /* Switch on keyType */
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      * SubKeyType.
470      */
471     public interface GordianStreamSubKeyType {
472     }
473 
474     /**
475      * VMPC Key styles.
476      */
477     public enum GordianVMPCKey
478             implements GordianStreamSubKeyType {
479         /**
480          * VMPC.
481          */
482         STD,
483 
484         /**
485          * VMPC-KSA.
486          */
487         KSA;
488     }
489 
490     /**
491      * Salsa20 Key styles.
492      */
493     public enum GordianSalsa20Key
494             implements GordianStreamSubKeyType {
495         /**
496          * Salsa20.
497          */
498         STD,
499 
500         /**
501          * XSalsa20.
502          */
503         XSALSA;
504 
505         /**
506          * Obtain required ivLength.
507          *
508          * @return the ivLength
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      * ChaCha20 Key styles.
523      */
524     public enum GordianChaCha20Key
525             implements GordianStreamSubKeyType {
526         /**
527          * ChaCha20.
528          */
529         STD,
530 
531         /**
532          * ChaCha7539.
533          */
534         ISO7539,
535 
536         /**
537          * XChaCha20.
538          */
539         XCHACHA;
540 
541         /**
542          * Obtain required ivLength.
543          *
544          * @return the ivLength
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      * SkeinXof Key styles.
561      */
562     public enum GordianSkeinXofKey
563             implements GordianStreamSubKeyType {
564         /**
565          * 256State.
566          */
567         STATE256(GordianLength.LEN_256),
568 
569         /**
570          * 512State.
571          */
572         STATE512(GordianLength.LEN_512),
573 
574         /**
575          * 1024State.
576          */
577         STATE1024(GordianLength.LEN_1024);
578 
579         /**
580          * The length.
581          */
582         private final GordianLength theLength;
583 
584         /**
585          * Constructor.
586          *
587          * @param pLength the stateLength
588          */
589         GordianSkeinXofKey(final GordianLength pLength) {
590             theLength = pLength;
591         }
592 
593         /**
594          * Obtain length.
595          *
596          * @return the length.
597          */
598         public GordianLength getLength() {
599             return theLength;
600         }
601 
602         @Override
603         public String toString() {
604             return theLength.toString();
605         }
606 
607         /**
608          * Obtain subKeyType for stateLength.
609          *
610          * @param pLength the length
611          * @return the subKeyType
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      * BlakeXof Key styles.
625      */
626     public enum GordianBlakeXofKey
627             implements GordianStreamSubKeyType {
628         /**
629          * Blake2S.
630          */
631         BLAKE2XS,
632 
633         /**
634          * Blake2B.
635          */
636         BLAKE2XB;
637 
638         @Override
639         public String toString() {
640             return this == BLAKE2XB ? "Blake2Xb" : "Blake2Xs";
641         }
642 
643         /**
644          * Obtain required ivLength.
645          *
646          * @return the ivLength
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      * Elephant Key styles.
661      */
662     public enum GordianElephantKey
663             implements GordianStreamSubKeyType {
664         /**
665          * Elephant160.
666          */
667         ELEPHANT160,
668 
669         /**
670          * Elephant176.
671          */
672         ELEPHANT176,
673 
674         /**
675          * Elephant200.
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          * Obtain the elephant parameters.
695          *
696          * @return the parameters
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      * ISAP Key styles.
713      */
714     public enum GordianISAPKey
715             implements GordianStreamSubKeyType {
716         /**
717          * ISAPA128.
718          */
719         ISAPA128,
720 
721         /**
722          * ISAPA128A.
723          */
724         ISAPA128A,
725 
726         /**
727          * ISAPK128.
728          */
729         ISAPK128,
730 
731         /**
732          * ISAPK128A.
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          * Obtain the ISAP type.
754          *
755          * @return the type
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      * Romulus Key styles.
774      */
775     public enum GordianRomulusKey
776             implements GordianStreamSubKeyType {
777         /**
778          * Romulus-M.
779          */
780         ROMULUS_M,
781 
782         /**
783          * Romulus-N.
784          */
785         ROMULUS_N,
786 
787         /**
788          * Romulus-T.
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          * Obtain the RomulusParameters.
808          *
809          * @return the parameters
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      * Sparkle Key styles.
826      */
827     public enum GordianSparkleKey
828             implements GordianStreamSubKeyType {
829         /**
830          * Sparkle128_128.
831          */
832         SPARKLE128_128,
833 
834         /**
835          * Sparkle256_128.
836          */
837         SPARKLE256_128,
838 
839         /**
840          * Sparkle192_192.
841          */
842         SPARKLE192_192,
843 
844         /**
845          * Sparkle256_256.
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          * Obtain required keyLength.
867          *
868          * @return the keyLength
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          * Obtain required ivLength.
885          *
886          * @return the ivLength
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          * Obtain the Sparkle parameters.
903          *
904          * @return the parameters
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 }