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 }