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.agree;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPairSpec;
20  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPairType;
21  
22  import java.util.Objects;
23  
24  /**
25   * KeyPair Agreement Specification.
26   */
27  public final class GordianAgreementSpec {
28      /**
29       * The Separator.
30       */
31      private static final String SEP = "-";
32  
33      /**
34       * KeyPairSpec.
35       */
36      private final GordianKeyPairSpec theKeyPairSpec;
37  
38      /**
39       * AgreementType.
40       */
41      private final GordianAgreementType theAgreementType;
42  
43      /**
44       * KDFType.
45       */
46      private final GordianAgreementKDF theKDFType;
47  
48      /**
49       * With Confirmation?.
50       */
51      private final Boolean withConfirm;
52  
53      /**
54       * The Validity.
55       */
56      private final boolean isValid;
57  
58      /**
59       * The String name.
60       */
61      private String theName;
62  
63      /**
64       * Constructor.
65       *
66       * @param pKeyPairSpec   the keyPairSpec
67       * @param pAgreementType the agreement type
68       * @param pKDFType       the KDF type
69       */
70      public GordianAgreementSpec(final GordianKeyPairSpec pKeyPairSpec,
71                                  final GordianAgreementType pAgreementType,
72                                  final GordianAgreementKDF pKDFType) {
73          this(pKeyPairSpec, pAgreementType, pKDFType, Boolean.FALSE);
74      }
75  
76      /**
77       * Constructor.
78       *
79       * @param pKeyPairSpec   the keyPairSpec
80       * @param pAgreementType the agreement type
81       * @param pKDFType       the KDF type
82       * @param pConfirm       with key confirmation
83       */
84      public GordianAgreementSpec(final GordianKeyPairSpec pKeyPairSpec,
85                                  final GordianAgreementType pAgreementType,
86                                  final GordianAgreementKDF pKDFType,
87                                  final Boolean pConfirm) {
88          theKeyPairSpec = pKeyPairSpec;
89          theAgreementType = pAgreementType;
90          theKDFType = pKDFType;
91          withConfirm = pConfirm;
92          isValid = checkValidity();
93      }
94  
95      /**
96       * Obtain the keyPairSpec.
97       *
98       * @return the keyPairSpec
99       */
100     public GordianKeyPairSpec getKeyPairSpec() {
101         return theKeyPairSpec;
102     }
103 
104     /**
105      * Obtain the agreementType.
106      *
107      * @return the agreementType
108      */
109     public GordianAgreementType getAgreementType() {
110         return theAgreementType;
111     }
112 
113     /**
114      * Obtain the kdfType.
115      *
116      * @return the kdfType
117      */
118     public GordianAgreementKDF getKDFType() {
119         return theKDFType;
120     }
121 
122     /**
123      * Is this agreement with key confirmation?
124      *
125      * @return true/false
126      */
127     public Boolean withConfirm() {
128         return withConfirm;
129     }
130 
131     /**
132      * Is this Agreement supported?
133      *
134      * @return true/false
135      */
136     public boolean isSupported() {
137         final GordianKeyPairType myType = theKeyPairSpec.getKeyPairType();
138         return theAgreementType.isSupported(myType) && theKDFType.isSupported(myType, theAgreementType);
139     }
140 
141     /**
142      * Is the agreementSpec valid?
143      *
144      * @return true/false.
145      */
146     public boolean isValid() {
147         return isValid;
148     }
149 
150     /**
151      * Check spec validity.
152      *
153      * @return valid true/false
154      */
155     private boolean checkValidity() {
156         /* All components must be non-null */
157         if (theKeyPairSpec == null
158                 || theAgreementType == null
159                 || theKDFType == null
160                 || withConfirm == null) {
161             return false;
162         }
163 
164         /* Confirmation is restricted to certain agreement types */
165         if (Boolean.TRUE.equals(withConfirm)) {
166             switch (theAgreementType) {
167                 case UNIFIED:
168                 case MQV:
169                 case SM2:
170                     return true;
171                 default:
172                     return false;
173             }
174         }
175 
176         /* Valid if supported */
177         return isSupported();
178     }
179 
180     @Override
181     public String toString() {
182         /* If we have not yet loaded the name */
183         if (theName == null) {
184             /* If the agreementSpec is valid */
185             if (isValid) {
186                 /* Load the name */
187                 theName = theKeyPairSpec.toString()
188                         + SEP + theAgreementType;
189 
190                 /* Add KDF type if present */
191                 if (GordianAgreementKDF.NONE != theKDFType) {
192                     theName += SEP + theKDFType;
193                 }
194 
195                 /* Add Confirm if present */
196                 if (Boolean.TRUE.equals(withConfirm)) {
197                     theName += SEP + "CONFIRM";
198                 }
199             } else {
200                 /* Report invalid spec */
201                 theName = "InvalidAgreementSpec: " + theKeyPairSpec + ":" + theAgreementType + ":" + theKDFType;
202             }
203         }
204 
205         /* return the name */
206         return theName;
207     }
208 
209     @Override
210     public boolean equals(final Object pThat) {
211         /* Handle the trivial cases */
212         if (this == pThat) {
213             return true;
214         }
215         if (pThat == null) {
216             return false;
217         }
218 
219         /* Match subfields */
220         return pThat instanceof GordianAgreementSpec myThat
221                 && Objects.equals(theKeyPairSpec, myThat.getKeyPairSpec())
222                 && theAgreementType == myThat.getAgreementType()
223                 && theKDFType == myThat.getKDFType()
224                 && withConfirm == myThat.withConfirm();
225     }
226 
227     @Override
228     public int hashCode() {
229         return Objects.hash(theKeyPairSpec, theAgreementType, theKDFType, withConfirm);
230     }
231 }