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.random;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.cipher.GordianSymKeySpec;
20  import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestSpec;
21  
22  import java.util.Objects;
23  
24  /**
25   * SecureRandom Specification.
26   */
27  public class GordianRandomSpec {
28      /**
29       * The Separator.
30       */
31      private static final String SEP = "-";
32  
33      /**
34       * The RandomType.
35       */
36      private final GordianRandomType theRandomType;
37  
38      /**
39       * The SubSpec.
40       */
41      private final Object theSubSpec;
42  
43      /**
44       * Is the secureRandom predicationResistant?
45       */
46      private final boolean isPredictionResistant;
47  
48      /**
49       * The Validity.
50       */
51      private final boolean isValid;
52  
53      /**
54       * The String name.
55       */
56      private String theName;
57  
58      /**
59       * Constructor.
60       *
61       * @param pRandomType the randomType
62       * @param pSubSpec    the subSpec
63       * @param pResistant  is the secureRandom predicationResistant?
64       */
65      public GordianRandomSpec(final GordianRandomType pRandomType,
66                               final Object pSubSpec,
67                               final boolean pResistant) {
68          theRandomType = pRandomType;
69          theSubSpec = pSubSpec;
70          isPredictionResistant = pResistant;
71          isValid = checkValidity();
72      }
73  
74      /**
75       * Obtain the randomType.
76       *
77       * @return the randomType.
78       */
79      public GordianRandomType getRandomType() {
80          return theRandomType;
81      }
82  
83      /**
84       * Obtain the subSpec.
85       *
86       * @return the subSpec.
87       */
88      private Object getSubSpec() {
89          return theSubSpec;
90      }
91  
92      /**
93       * Is the macSpec valid?
94       *
95       * @return true/false.
96       */
97      public boolean isValid() {
98          return isValid;
99      }
100 
101     /**
102      * Obtain the digestSpec.
103      *
104      * @return the digestSpec.
105      */
106     public GordianDigestSpec getDigestSpec() {
107         return theSubSpec instanceof GordianDigestSpec mySpec
108                 ? mySpec
109                 : null;
110     }
111 
112     /**
113      * Obtain the symKeySpec.
114      *
115      * @return the symKeySpec.
116      */
117     public GordianSymKeySpec getSymKeySpec() {
118         return theSubSpec instanceof GordianSymKeySpec mySpec
119                 ? mySpec
120                 : null;
121     }
122 
123     /**
124      * Obtain the predication resistance.
125      *
126      * @return the resistance.
127      */
128     public boolean isPredictionResistant() {
129         return isPredictionResistant;
130     }
131 
132     /**
133      * Check spec validity.
134      *
135      * @return valid true/false
136      */
137     private boolean checkValidity() {
138         if (theRandomType == null) {
139             return false;
140         }
141         switch (theRandomType) {
142             case HMAC:
143             case HASH:
144                 return theSubSpec instanceof GordianDigestSpec mySpec
145                         && mySpec.isValid()
146                         && mySpec.getDigestType().supportsLargeData();
147             case CTR:
148             case X931:
149                 return theSubSpec instanceof GordianSymKeySpec mySpec
150                         && mySpec.isValid();
151             default:
152                 return false;
153         }
154     }
155 
156     @Override
157     public String toString() {
158         /* If we have not yet loaded the name */
159         if (theName == null) {
160             /* If the randomSpec is valid */
161             if (isValid) {
162                 /* Load the name */
163                 theName = theRandomType.toString();
164                 theName += SEP + theSubSpec;
165                 if (isPredictionResistant) {
166                     theName += SEP + "resistant";
167                 }
168             } else {
169                 /* Report invalid spec */
170                 theName = "InvalidRandomSpec: " + theRandomType + ":" + theSubSpec + ":" + isPredictionResistant;
171             }
172         }
173 
174         /* return the name */
175         return theName;
176     }
177 
178     @Override
179     public boolean equals(final Object pThat) {
180         /* Handle the trivial cases */
181         if (this == pThat) {
182             return true;
183         }
184         if (pThat == null) {
185             return false;
186         }
187 
188         /* Check KeyType, prediction and subSpec */
189         return pThat instanceof GordianRandomSpec myThat
190                 && theRandomType == myThat.getRandomType()
191                 && isPredictionResistant == myThat.isPredictionResistant()
192                 && Objects.equals(theSubSpec, myThat.getSubSpec());
193     }
194 
195     @Override
196     public int hashCode() {
197         return Objects.hash(theRandomType, theSubSpec, isPredictionResistant);
198     }
199 }