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 }