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.digest.GordianDigestSpec;
20  
21  import java.util.Objects;
22  
23  /**
24   * PBE Specification.
25   */
26  public abstract class GordianPBESpec {
27      /**
28       * The Separator.
29       */
30      private static final String SEP = "-";
31  
32      /**
33       * The PBEType.
34       */
35      private final GordianPBEType theType;
36  
37      /**
38       * is the Spec valid?
39       */
40      private boolean isValid;
41  
42      /**
43       * Constructor.
44       *
45       * @param pPBEType the PBEType.
46       */
47      GordianPBESpec(final GordianPBEType pPBEType) {
48          theType = pPBEType;
49      }
50  
51      /**
52       * Obtain the PBEType.
53       *
54       * @return the PBEType
55       */
56      public GordianPBEType getPBEType() {
57          return theType;
58      }
59  
60      /**
61       * Is the Spec valid?
62       *
63       * @return true/false
64       */
65      public boolean isValid() {
66          return isValid;
67      }
68  
69      /**
70       * Set as valid.
71       */
72      void setValid() {
73          isValid = true;
74      }
75  
76      /**
77       * DigestAndCountSpec.
78       */
79      public static class GordianPBEDigestAndCountSpec
80              extends GordianPBESpec {
81          /**
82           * The DigestSpec.
83           */
84          private final GordianDigestSpec theDigestSpec;
85  
86          /**
87           * The count.
88           */
89          private final int theCount;
90  
91          /**
92           * Constructor.
93           *
94           * @param pPBEType    the PBEType.
95           * @param pDigestSpec the digestSpec.
96           * @param pCount      the iteration count
97           */
98          GordianPBEDigestAndCountSpec(final GordianPBEType pPBEType,
99                                       final GordianDigestSpec pDigestSpec,
100                                      final int pCount) {
101             /* Init underlying class and store params */
102             super(pPBEType);
103             theDigestSpec = pDigestSpec;
104             theCount = pCount;
105 
106             /* Check validity */
107             checkValidity();
108         }
109 
110         /**
111          * Obtain the digestSpec.
112          *
113          * @return the digestSpec
114          */
115         public GordianDigestSpec getDigestSpec() {
116             return theDigestSpec;
117         }
118 
119         /**
120          * Obtain the iteration count.
121          *
122          * @return the count
123          */
124         public int getIterationCount() {
125             return theCount;
126         }
127 
128         /**
129          * Check validity.
130          */
131         private void checkValidity() {
132             /* Check PBEType */
133             if (getPBEType() != GordianPBEType.PBKDF2
134                     && getPBEType() != GordianPBEType.PKCS12) {
135                 return;
136             }
137 
138             /* Check DigestSpec and Count > 0 */
139             if (theDigestSpec != null
140                     && theDigestSpec.isValid()
141                     && theCount > 0) {
142                 setValid();
143             }
144         }
145 
146         @Override
147         public boolean equals(final Object pThat) {
148             /* Handle trivial cases */
149             if (this == pThat) {
150                 return true;
151             }
152             if (pThat == null) {
153                 return false;
154             }
155 
156             /* Check count, digestSpec and PBEType */
157             return pThat instanceof GordianPBEDigestAndCountSpec myThat
158                     && theCount == myThat.getIterationCount()
159                     && theDigestSpec.equals(myThat.getDigestSpec())
160                     && getPBEType() == myThat.getPBEType();
161         }
162 
163         @Override
164         public int hashCode() {
165             return Objects.hash(theDigestSpec, theCount, getPBEType());
166         }
167 
168         @Override
169         public String toString() {
170             return getPBEType().toString() + SEP + theDigestSpec.toString() + SEP + theCount;
171         }
172     }
173 
174     /**
175      * SCryptSpec.
176      */
177     public static class GordianPBESCryptSpec
178             extends GordianPBESpec {
179         /**
180          * Max Small Block Cost.
181          */
182         private static final int MAX_SMALL_COST = 0xFFFF;
183 
184         /**
185          * Parallel limit.
186          */
187         private static final int PARALLEL_LIMIT = 128;
188 
189         /**
190          * The BlockSize.
191          */
192         private final int theBlockSize;
193 
194         /**
195          * The cost.
196          */
197         private final int theCost;
198 
199         /**
200          * The Parallelism.
201          */
202         private final int theParallel;
203 
204         /**
205          * Constructor.
206          *
207          * @param pCost      the cost
208          * @param pBlockSize the blockSize
209          * @param pParallel  the parallelism
210          */
211         GordianPBESCryptSpec(final int pCost,
212                              final int pBlockSize,
213                              final int pParallel) {
214             /* Init underlying class and store params */
215             super(GordianPBEType.SCRYPT);
216             theCost = pCost;
217             theBlockSize = pBlockSize;
218             theParallel = pParallel;
219 
220             /* Check validity */
221             checkValidity();
222         }
223 
224         /**
225          * Obtain the blockSize.
226          *
227          * @return the blockSize
228          */
229         public int getBlockSize() {
230             return theBlockSize;
231         }
232 
233         /**
234          * Obtain the cost.
235          *
236          * @return the cost
237          */
238         public int getCost() {
239             return theCost;
240         }
241 
242         /**
243          * Obtain the parallelism.
244          *
245          * @return the parallelism
246          */
247         public int getParallel() {
248             return theParallel;
249         }
250 
251         /**
252          * Check validity.
253          */
254         private void checkValidity() {
255             /* Check BlockSize is > 0 */
256             if (theBlockSize <= 0) {
257                 return;
258             }
259 
260             /* Check Cost is > 1 and power of two */
261             if (theCost <= 1
262                     || (theCost & (theCost - 1)) != 0) {
263                 return;
264             }
265 
266             /* Check Cost restriction for BlockSize of 1 */
267             if (theBlockSize == 1
268                     && theCost > MAX_SMALL_COST) {
269                 return;
270             }
271 
272             /* Check Parallel restriction */
273             final int maxParallel = Integer.MAX_VALUE / (PARALLEL_LIMIT * theBlockSize * Byte.SIZE);
274             if (theParallel >= 1
275                     && theParallel <= maxParallel) {
276                 setValid();
277             }
278         }
279 
280         @Override
281         public boolean equals(final Object pThat) {
282             /* Handle trivial cases */
283             if (this == pThat) {
284                 return true;
285             }
286             if (pThat == null) {
287                 return false;
288             }
289 
290             /* Check cost, blockSize and parallel */
291             return pThat instanceof GordianPBESCryptSpec myThat
292                     && theCost == myThat.getCost()
293                     && theBlockSize == myThat.getBlockSize()
294                     && theParallel == myThat.getParallel()
295                     && getPBEType() == myThat.getPBEType();
296         }
297 
298         @Override
299         public int hashCode() {
300             return Objects.hash(theBlockSize, theCost, theParallel, getPBEType());
301         }
302 
303         @Override
304         public String toString() {
305             return getPBEType().toString() + SEP + theBlockSize + SEP + theCost + SEP + theParallel;
306         }
307     }
308 
309     /**
310      * Argon2Spec.
311      */
312     public static class GordianPBEArgon2Spec
313             extends GordianPBESpec {
314         /**
315          * The Memory.
316          */
317         private final int theMemory;
318 
319         /**
320          * The lanes.
321          */
322         private final int theLanes;
323 
324         /**
325          * The Iterations.
326          */
327         private final int theIterations;
328 
329         /**
330          * Constructor.
331          *
332          * @param pLanes      the Lanes
333          * @param pMemory     the Memory
334          * @param pIterations the iterations
335          */
336         GordianPBEArgon2Spec(final int pLanes,
337                              final int pMemory,
338                              final int pIterations) {
339             /* Init underlying class and store params */
340             super(GordianPBEType.ARGON2);
341             theLanes = pLanes;
342             theMemory = pMemory;
343             theIterations = pIterations;
344 
345             /* Check validity */
346             checkValidity();
347         }
348 
349         /**
350          * Obtain the lanes.
351          *
352          * @return the lanes
353          */
354         public int getLanes() {
355             return theLanes;
356         }
357 
358         /**
359          * Obtain the memory.
360          *
361          * @return the memory
362          */
363         public int getMemory() {
364             return theMemory;
365         }
366 
367         /**
368          * Obtain the iteration count.
369          *
370          * @return the count
371          */
372         public int getIterationCount() {
373             return theIterations;
374         }
375 
376         /**
377          * Check validity.
378          */
379         private void checkValidity() {
380             /* Check Iterations and Lanes are > 0 */
381             if (theIterations <= 0
382                     || theLanes <= 0) {
383                 return;
384             }
385 
386             /* Check Memory is >= 2 * lanes */
387             if (theMemory >= theLanes << 1) {
388                 setValid();
389             }
390         }
391 
392         @Override
393         public boolean equals(final Object pThat) {
394             /* Handle trivial cases */
395             if (this == pThat) {
396                 return true;
397             }
398             if (pThat == null) {
399                 return false;
400             }
401 
402             /* Check lanes, memory and iterations */
403             return pThat instanceof GordianPBEArgon2Spec myThat
404                     && theLanes == myThat.getLanes()
405                     && theMemory == myThat.getMemory()
406                     && theIterations == myThat.getIterationCount()
407                     && getPBEType() == myThat.getPBEType();
408         }
409 
410         @Override
411         public int hashCode() {
412             return Objects.hash(theLanes, theMemory, theIterations, getPBEType());
413         }
414 
415         @Override
416         public String toString() {
417             return getPBEType().toString() + SEP + theLanes + SEP + theMemory + SEP + theIterations;
418         }
419     }
420 }