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.encrypt;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianLength;
20  import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestSpec;
21  import io.github.tonywasher.joceanus.gordianknot.api.digest.GordianDigestSpecBuilder;
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Objects;
26  
27  /**
28   * SM2 EncryptionSpec.
29   */
30  public class GordianSM2EncryptionSpec {
31      /**
32       * EncryptionType.
33       */
34      private final GordianSM2EncryptionType theType;
35  
36      /**
37       * DigestSpec.
38       */
39      private final GordianDigestSpec theDigest;
40  
41      /**
42       * The Validity.
43       */
44      private final boolean isValid;
45  
46      /**
47       * The String name.
48       */
49      private String theName;
50  
51      /**
52       * Constructor.
53       *
54       * @param pType   the encryptionType
55       * @param pDigest the digestSpec
56       */
57      GordianSM2EncryptionSpec(final GordianSM2EncryptionType pType,
58                               final GordianDigestSpec pDigest) {
59          /* Store parameters */
60          theType = pType;
61          theDigest = pDigest;
62          isValid = checkValidity();
63      }
64  
65      /**
66       * Create SM2 C1C2C3 Spec.
67       *
68       * @param pSpec the digestSpec
69       * @return the encryptionSpec
70       */
71      public static GordianSM2EncryptionSpec c1c2c3(final GordianDigestSpec pSpec) {
72          return new GordianSM2EncryptionSpec(GordianSM2EncryptionType.C1C2C3, pSpec);
73      }
74  
75      /**
76       * Create SM2 C1C2C3 Spec.
77       *
78       * @param pSpec the digestSpec
79       * @return the encryptionSpec
80       */
81      public static GordianSM2EncryptionSpec c1c3c2(final GordianDigestSpec pSpec) {
82          return new GordianSM2EncryptionSpec(GordianSM2EncryptionType.C1C3C2, pSpec);
83      }
84  
85      /**
86       * Obtain the encryptionType.
87       *
88       * @return the encryptionType
89       */
90      public GordianSM2EncryptionType getEncryptionType() {
91          return theType;
92      }
93  
94      /**
95       * Obtain the digestSpec.
96       *
97       * @return the digestSpec
98       */
99      public GordianDigestSpec getDigestSpec() {
100         return theDigest;
101     }
102 
103     /**
104      * Is the keySpec valid?
105      *
106      * @return true/false.
107      */
108     public boolean isValid() {
109         return isValid;
110     }
111 
112     /**
113      * Check spec validity.
114      *
115      * @return valid true/false
116      */
117     private boolean checkValidity() {
118         return theType != null
119                 && theDigest != null
120                 && isDigestSupported();
121     }
122 
123     /**
124      * Is the SM2 digestSpec supported?
125      *
126      * @return true/false
127      */
128     private boolean isDigestSupported() {
129         switch (theDigest.getDigestType()) {
130             case SHA2:
131                 return !theDigest.isSha2Hybrid();
132             case WHIRLPOOL:
133             case SM3:
134                 return true;
135             case BLAKE2:
136                 return theDigest.getDigestLength().equals(theDigest.getDigestState().getLength());
137             default:
138                 return false;
139         }
140     }
141 
142     @Override
143     public String toString() {
144         /* If we have not yet loaded the name */
145         if (theName == null) {
146             /* If the encryptionSpec is valid */
147             if (isValid) {
148                 /* Load the name */
149                 theName = theType.toString() + GordianEncryptorSpec.SEP + theDigest.toString();
150             } else {
151                 /* Report invalid spec */
152                 theName = "InvalidEncryptorSpec: " + theType + ":" + theDigest;
153             }
154         }
155 
156         /* return the name */
157         return theName;
158     }
159 
160     @Override
161     public boolean equals(final Object pThat) {
162         /* Handle the trivial cases */
163         if (this == pThat) {
164             return true;
165         }
166         if (pThat == null) {
167             return false;
168         }
169 
170         /* Make sure that the object is an EncryptorSpec */
171         if (pThat.getClass() != this.getClass()) {
172             return false;
173         }
174 
175         /* Access the target encryptionSpec */
176         final GordianSM2EncryptionSpec myThat = (GordianSM2EncryptionSpec) pThat;
177 
178         /* Match fields */
179         return theType == myThat.getEncryptionType()
180                 && Objects.equals(theDigest, myThat.getDigestSpec());
181     }
182 
183     @Override
184     public int hashCode() {
185         return Objects.hash(theType, theDigest);
186     }
187 
188     /**
189      * Obtain a list of all possible encryptionSpecs.
190      *
191      * @return the list
192      */
193     public static List<GordianSM2EncryptionSpec> listPossibleSpecs() {
194         /* Create list */
195         final List<GordianSM2EncryptionSpec> mySpecs = new ArrayList<>();
196 
197         /* Loop through the encryptionTypes */
198         for (GordianSM2EncryptionType myType : GordianSM2EncryptionType.values()) {
199             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.sm3()));
200             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.sha2(GordianLength.LEN_224)));
201             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.sha2(GordianLength.LEN_256)));
202             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.sha2(GordianLength.LEN_384)));
203             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.sha2(GordianLength.LEN_512)));
204             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.blake2s(GordianLength.LEN_256)));
205             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.blake2b(GordianLength.LEN_512)));
206             mySpecs.add(new GordianSM2EncryptionSpec(myType, GordianDigestSpecBuilder.whirlpool()));
207         }
208 
209         /* Return the list */
210         return mySpecs;
211     }
212 
213     /**
214      * SM2 EncryptionType.
215      */
216     public enum GordianSM2EncryptionType {
217         /**
218          * C1C2C3.
219          */
220         C1C2C3,
221 
222         /**
223          * C1C3C2.
224          */
225         C1C3C2;
226     }
227 }