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.digest;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
20  
21  /**
22   * Digest SubSpec.
23   */
24  public interface GordianDigestSubSpec {
25      /**
26       * Obtain the possible subSpecTypes for the digestType.
27       *
28       * @param pType the digestType
29       * @return the subSpec types
30       */
31      static GordianDigestSubSpec[] getPossibleSubSpecsForType(final GordianDigestType pType) {
32          switch (pType) {
33              case SHA2:
34              case BLAKE2:
35              case HARAKA:
36                  return new GordianDigestState[]{GordianDigestState.STATE256, GordianDigestState.STATE512};
37              case SKEIN:
38                  return new GordianDigestState[]{GordianDigestState.STATE256, GordianDigestState.STATE512, GordianDigestState.STATE1024};
39              case SHAKE:
40              case KANGAROO:
41                  return new GordianDigestState[]{GordianDigestState.STATE128, GordianDigestState.STATE256};
42              default:
43                  return new GordianDigestState[]{null};
44          }
45      }
46  
47      /**
48       * Obtain the subSpec for the type and length.
49       *
50       * @param pType   the digestType
51       * @param pLength the length
52       * @return the subSpec
53       */
54      static GordianDigestSubSpec getDefaultSubSpecForTypeAndLength(final GordianDigestType pType,
55                                                                    final GordianLength pLength) {
56          switch (pType) {
57              case SHA2:
58                  return pLength == GordianLength.LEN_224 || pLength == GordianLength.LEN_256
59                          ? GordianDigestState.STATE256
60                          : GordianDigestState.STATE512;
61              case SKEIN:
62                  switch (pLength) {
63                      case LEN_1024:
64                          return GordianDigestState.STATE1024;
65                      case LEN_512:
66                      case LEN_384:
67                          return GordianDigestState.STATE512;
68                      default:
69                          return GordianDigestState.STATE256;
70                  }
71              case SHAKE:
72              case KANGAROO:
73                  return pLength == GordianLength.LEN_256
74                          ? GordianDigestState.STATE128
75                          : GordianDigestState.STATE256;
76              case BLAKE2:
77                  return pLength == GordianLength.LEN_128 || pLength == GordianLength.LEN_224
78                          ? GordianDigestState.STATE256
79                          : GordianDigestState.STATE512;
80              case HARAKA:
81                  return GordianDigestState.STATE256;
82              default:
83                  return null;
84          }
85      }
86  
87      /**
88       * State subSpecification.
89       */
90      enum GordianDigestState implements GordianDigestSubSpec {
91          /**
92           * 128.
93           */
94          STATE128(GordianLength.LEN_128),
95  
96          /**
97           * 256.
98           */
99          STATE256(GordianLength.LEN_256),
100 
101         /**
102          * 512.
103          */
104         STATE512(GordianLength.LEN_512),
105 
106         /**
107          * 1024.
108          */
109         STATE1024(GordianLength.LEN_1024);
110 
111         /**
112          * The length.
113          */
114         private final GordianLength theLength;
115 
116         /**
117          * Constructor.
118          *
119          * @param pLength the length
120          */
121         GordianDigestState(final GordianLength pLength) {
122             theLength = pLength;
123         }
124 
125         /**
126          * Obtain length for state.
127          *
128          * @return the length
129          */
130         public GordianLength getLength() {
131             return theLength;
132         }
133 
134         @Override
135         public String toString() {
136             return theLength.toString();
137         }
138 
139         /**
140          * Is this state a hybrid for sha2 length?
141          *
142          * @param pLength the length
143          * @return true/false
144          */
145         public boolean isSha2Hybrid(final GordianLength pLength) {
146             return this == STATE512
147                     && (GordianLength.LEN_224.equals(pLength)
148                     || GordianLength.LEN_256.equals(pLength));
149         }
150 
151         /**
152          * Obtain the length for an explicit Xof variant.
153          *
154          * @param pType the digestType
155          * @return the length
156          */
157         GordianLength lengthForXofType(final GordianDigestType pType) {
158             switch (pType) {
159                 case SKEIN:
160                     switch (this) {
161                         case STATE256:
162                         case STATE512:
163                         case STATE1024:
164                             return theLength;
165                         default:
166                             return null;
167                     }
168                 case BLAKE2:
169                     switch (this) {
170                         case STATE256:
171                         case STATE512:
172                             return theLength;
173                         default:
174                             return null;
175                     }
176                 default:
177                     return null;
178             }
179         }
180 
181         /**
182          * is length available for this type and length?
183          *
184          * @param pType   the digestType
185          * @param pLength the length
186          * @return true/false
187          */
188         boolean validForTypeAndLength(final GordianDigestType pType,
189                                       final GordianLength pLength) {
190             switch (pType) {
191                 case SHA2:
192                     return validForSha2Length(pLength);
193                 case SHAKE:
194                 case KANGAROO:
195                     return validForSHAKELength(pLength);
196                 case SKEIN:
197                     return validForSkeinLength(pLength);
198                 case BLAKE2:
199                     return validForBlake2Length(pLength);
200                 case HARAKA:
201                     return validForHarakaLength(pLength);
202                 default:
203                     return false;
204             }
205         }
206 
207         /**
208          * Is this state valid for the skeinLength?
209          *
210          * @param pLength the length
211          * @return true/false
212          */
213         private boolean validForSha2Length(final GordianLength pLength) {
214             switch (this) {
215                 case STATE512:
216                     switch (pLength) {
217                         case LEN_224:
218                         case LEN_256:
219                         case LEN_384:
220                         case LEN_512:
221                             return true;
222                         default:
223                             return false;
224                     }
225                 case STATE256:
226                     switch (pLength) {
227                         case LEN_224:
228                         case LEN_256:
229                             return true;
230                         default:
231                             return false;
232                     }
233                 default:
234                     return false;
235             }
236         }
237 
238         /**
239          * Is this state valid for the skeinLength?
240          *
241          * @param pLength the length
242          * @return true/false
243          */
244         private boolean validForSHAKELength(final GordianLength pLength) {
245             switch (this) {
246                 case STATE256:
247                     return pLength == GordianLength.LEN_512;
248                 case STATE128:
249                     return pLength == GordianLength.LEN_256;
250                 default:
251                     return false;
252             }
253         }
254 
255         /**
256          * Is this state valid for the skeinLength?
257          *
258          * @param pLength the length
259          * @return true/false
260          */
261         private boolean validForSkeinLength(final GordianLength pLength) {
262             switch (this) {
263                 case STATE1024:
264                     switch (pLength) {
265                         case LEN_384:
266                         case LEN_512:
267                         case LEN_1024:
268                             return true;
269                         default:
270                             return false;
271                     }
272                 case STATE512:
273                     switch (pLength) {
274                         case LEN_128:
275                         case LEN_160:
276                         case LEN_224:
277                         case LEN_256:
278                         case LEN_384:
279                         case LEN_512:
280                             return true;
281                         default:
282                             return false;
283                     }
284                 case STATE256:
285                     switch (pLength) {
286                         case LEN_128:
287                         case LEN_160:
288                         case LEN_224:
289                         case LEN_256:
290                             return true;
291                         default:
292                             return false;
293                     }
294                 default:
295                     return false;
296             }
297         }
298 
299         /**
300          * Is this state valid for the blake2Length.
301          *
302          * @param pLength the length
303          * @return true/false
304          */
305         private boolean validForBlake2Length(final GordianLength pLength) {
306             switch (this) {
307                 case STATE512:
308                     switch (pLength) {
309                         case LEN_160:
310                         case LEN_256:
311                         case LEN_384:
312                         case LEN_512:
313                             return true;
314                         default:
315                             return false;
316                     }
317                 case STATE256:
318                     switch (pLength) {
319                         case LEN_128:
320                         case LEN_160:
321                         case LEN_224:
322                         case LEN_256:
323                             return true;
324                         default:
325                             return false;
326                     }
327                 default:
328                     return false;
329             }
330         }
331 
332         /**
333          * Is this state valid for the harakaLength.
334          *
335          * @param pLength the length
336          * @return true/false
337          */
338         private boolean validForHarakaLength(final GordianLength pLength) {
339             switch (this) {
340                 case STATE512:
341                 case STATE256:
342                     return pLength == GordianLength.LEN_256;
343                 default:
344                     return false;
345             }
346         }
347 
348         /**
349          * Is this the Blake2b algorithm?
350          *
351          * @return true/false
352          */
353         public boolean isBlake2bState() {
354             return GordianDigestState.STATE512.equals(this);
355         }
356 
357         /**
358          * Obtain the blake2Algorithm name for State.
359          *
360          * @param pXofMode is this a Xof variant
361          * @return the algorithm name
362          */
363         public String getBlake2Algorithm(final boolean pXofMode) {
364             return (pXofMode ? "X" : "")
365                     + (isBlake2bState() ? "b" : "s");
366         }
367 
368         /**
369          * Obtain the kangarooAlgorithm name for State.
370          *
371          * @return the algorithmName
372          */
373         String getKangarooAlgorithm() {
374             return this == STATE256
375                     ? GordianDigestResource.DIGEST_MARSUPILAMI.getValue()
376                     : GordianDigestResource.DIGEST_KANGAROO.getValue();
377         }
378     }
379 }