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.impl.jca;
18  
19  import io.github.tonywasher.joceanus.gordianknot.api.base.GordianException;
20  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPair;
21  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianKeyPairSpec;
22  import io.github.tonywasher.joceanus.gordianknot.api.keypair.GordianStateAwareKeyPair;
23  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianDataException;
24  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianCoreKeyPair;
25  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianPrivateKey;
26  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianPrivateKey.GordianStateAwarePrivateKey;
27  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianPublicKey;
28  import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPrivateKey;
29  import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey;
30  import org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
31  import org.bouncycastle.pqc.jcajce.interfaces.LMSPrivateKey;
32  import org.bouncycastle.pqc.jcajce.interfaces.XMSSMTPrivateKey;
33  import org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey;
34  
35  import javax.crypto.spec.DHParameterSpec;
36  import java.security.PrivateKey;
37  import java.security.PublicKey;
38  import java.util.Objects;
39  
40  /**
41   * BouncyCastle Asymmetric KeyPair.
42   */
43  public class JcaKeyPair
44          extends GordianCoreKeyPair {
45      /**
46       * Constructor.
47       *
48       * @param pPublic the public key
49       */
50      protected JcaKeyPair(final JcaPublicKey pPublic) {
51          this(pPublic, null);
52      }
53  
54      /**
55       * Constructor.
56       *
57       * @param pPublic  the public key
58       * @param pPrivate the private key
59       */
60      protected JcaKeyPair(final JcaPublicKey pPublic,
61                           final JcaPrivateKey pPrivate) {
62          super(pPublic, pPrivate);
63      }
64  
65      @Override
66      public JcaPublicKey getPublicKey() {
67          return (JcaPublicKey) super.getPublicKey();
68      }
69  
70      @Override
71      public JcaPrivateKey getPrivateKey() {
72          return (JcaPrivateKey) super.getPrivateKey();
73      }
74  
75      @Override
76      public JcaKeyPair getPublicOnly() {
77          return new JcaKeyPair(getPublicKey());
78      }
79  
80      /**
81       * Check for jcaKeyPair.
82       *
83       * @param pKeyPair the keyPair to check
84       * @throws GordianException on error
85       */
86      public static void checkKeyPair(final GordianKeyPair pKeyPair) throws GordianException {
87          /* Check that it is a JcaKeyPair */
88          if (!(pKeyPair instanceof JcaKeyPair)) {
89              /* Reject keyPair */
90              throw new GordianDataException("Invalid KeyPair");
91          }
92      }
93  
94      /**
95       * Check for jcaKeyPair.
96       *
97       * @param pKeyPair the keyPair to check
98       * @param pSpec    the required keySpec
99       * @throws GordianException on error
100      */
101     public static void checkKeyPair(final GordianKeyPair pKeyPair,
102                                     final GordianKeyPairSpec pSpec) throws GordianException {
103         /* Check the keyPair */
104         checkKeyPair(pKeyPair);
105 
106         /* Check that it the correct key type */
107         if (!pSpec.equals(pKeyPair.getKeyPairSpec())) {
108             /* Reject keyPair */
109             throw new GordianDataException("Invalid KeyPairType");
110         }
111     }
112 
113     /**
114      * Jca PublicKey.
115      */
116     public static class JcaPublicKey
117             extends GordianPublicKey {
118         /**
119          * Public Key details.
120          */
121         private final PublicKey theKey;
122 
123         /**
124          * Constructor.
125          *
126          * @param pKeySpec   the keySpec
127          * @param pPublicKey the public key
128          */
129         protected JcaPublicKey(final GordianKeyPairSpec pKeySpec,
130                                final PublicKey pPublicKey) {
131             super(pKeySpec);
132             theKey = pPublicKey;
133         }
134 
135         /**
136          * Obtain the public key.
137          *
138          * @return the key
139          */
140         protected PublicKey getPublicKey() {
141             return theKey;
142         }
143 
144         @Override
145         public boolean equals(final Object pThat) {
146             /* Handle the trivial cases */
147             if (pThat == this) {
148                 return true;
149             }
150             if (pThat == null) {
151                 return false;
152             }
153 
154             /* Make sure that the object is the same class */
155             if (!(pThat instanceof JcaPublicKey)) {
156                 return false;
157             }
158 
159             /* Access the target field */
160             final JcaPublicKey myThat = (JcaPublicKey) pThat;
161 
162             /* Check differences */
163             return getKeySpec().equals(myThat.getKeySpec())
164                     && theKey.equals(myThat.getPublicKey());
165         }
166 
167         @Override
168         public int hashCode() {
169             return Objects.hash(getKeySpec(), theKey);
170         }
171     }
172 
173     /**
174      * Jca PrivateKey.
175      */
176     public static class JcaPrivateKey
177             extends GordianPrivateKey {
178         /**
179          * Private Key details.
180          */
181         private final PrivateKey theKey;
182 
183         /**
184          * Constructor.
185          *
186          * @param pKeySpec    the keySpec
187          * @param pPrivateKey the private key
188          */
189         protected JcaPrivateKey(final GordianKeyPairSpec pKeySpec,
190                                 final PrivateKey pPrivateKey) {
191             super(pKeySpec);
192             theKey = pPrivateKey;
193         }
194 
195         /**
196          * Obtain the private key.
197          *
198          * @return the key
199          */
200         protected PrivateKey getPrivateKey() {
201             return theKey;
202         }
203 
204         @Override
205         public boolean equals(final Object pThat) {
206             /* Handle the trivial cases */
207             if (pThat == this) {
208                 return true;
209             }
210             if (pThat == null) {
211                 return false;
212             }
213 
214             /* Make sure that the object is the same class */
215             if (!(pThat instanceof JcaPrivateKey)) {
216                 return false;
217             }
218 
219             /* Access the target field */
220             final JcaPrivateKey myThat = (JcaPrivateKey) pThat;
221 
222             /* Check differences */
223             return getKeySpec().equals(myThat.getKeySpec())
224                     && theKey.equals(myThat.getPrivateKey());
225         }
226 
227         @Override
228         public int hashCode() {
229             return Objects.hash(getKeySpec(), theKey);
230         }
231     }
232 
233     /**
234      * Jca StateAware PrivateKey.
235      */
236     public static class JcaStateAwarePrivateKey
237             extends JcaPrivateKey
238             implements GordianStateAwarePrivateKey {
239         /**
240          * The private key.
241          */
242         private final PrivateKey thePrivateKey;
243 
244         /**
245          * Constructor.
246          *
247          * @param pKeySpec the key spec
248          * @param pKey     the key
249          */
250         JcaStateAwarePrivateKey(final GordianKeyPairSpec pKeySpec,
251                                 final PrivateKey pKey) {
252             super(pKeySpec, pKey);
253             thePrivateKey = pKey;
254         }
255 
256         @Override
257         public PrivateKey getPrivateKey() {
258             return thePrivateKey;
259         }
260 
261         @Override
262         public long getUsagesRemaining() {
263             if (thePrivateKey instanceof LMSPrivateKey) {
264                 return ((LMSPrivateKey) getPrivateKey()).getUsagesRemaining();
265             }
266             if (thePrivateKey instanceof XMSSMTPrivateKey) {
267                 return ((XMSSMTPrivateKey) getPrivateKey()).getUsagesRemaining();
268             }
269             return thePrivateKey instanceof XMSSPrivateKey
270                     ? ((XMSSPrivateKey) getPrivateKey()).getUsagesRemaining()
271                     : 0;
272         }
273 
274         @Override
275         public JcaStateAwarePrivateKey getKeyShard(final int pNumUsages) {
276             if (thePrivateKey instanceof LMSPrivateKey) {
277                 return new JcaStateAwarePrivateKey(getKeySpec(), ((LMSPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages));
278             }
279             if (thePrivateKey instanceof XMSSMTPrivateKey) {
280                 return new JcaStateAwarePrivateKey(getKeySpec(), ((XMSSMTPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages));
281             }
282             return thePrivateKey instanceof XMSSPrivateKey
283                     ? new JcaStateAwarePrivateKey(getKeySpec(), ((XMSSPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages))
284                     : null;
285         }
286 
287         @Override
288         public boolean equals(final Object pThat) {
289             /* Handle the trivial cases */
290             if (pThat == this) {
291                 return true;
292             }
293             if (pThat == null) {
294                 return false;
295             }
296 
297             /* Make sure that the object is the same class */
298             if (!(pThat instanceof JcaStateAwarePrivateKey)) {
299                 return false;
300             }
301 
302             /* Access the target field */
303             final JcaStateAwarePrivateKey myThat = (JcaStateAwarePrivateKey) pThat;
304 
305             /* Check differences */
306             return getKeySpec().equals(myThat.getKeySpec())
307                     && thePrivateKey.equals(myThat.getPrivateKey());
308         }
309 
310         @Override
311         public int hashCode() {
312             return Objects.hash(getKeySpec(), thePrivateKey);
313         }
314     }
315 
316     /**
317      * Jca DH PublicKey.
318      */
319     public static class JcaDHPublicKey
320             extends JcaPublicKey {
321         /**
322          * Public Key details.
323          */
324         private final BCDHPublicKey theKey;
325 
326         /**
327          * Constructor.
328          *
329          * @param pKeySpec   the keySpec
330          * @param pPublicKey the public key
331          */
332         protected JcaDHPublicKey(final GordianKeyPairSpec pKeySpec,
333                                  final BCDHPublicKey pPublicKey) {
334             super(pKeySpec, pPublicKey);
335             theKey = pPublicKey;
336         }
337 
338         @Override
339         protected BCDHPublicKey getPublicKey() {
340             return theKey;
341         }
342 
343         @Override
344         public boolean equals(final Object pThat) {
345             /* Handle the trivial cases */
346             if (pThat == this) {
347                 return true;
348             }
349             if (pThat == null) {
350                 return false;
351             }
352 
353             /* Make sure that the object is the same class */
354             if (!(pThat instanceof JcaDHPublicKey)) {
355                 return false;
356             }
357 
358             /* Access the target field */
359             final JcaDHPublicKey myThat = (JcaDHPublicKey) pThat;
360 
361             /* Check differences */
362             return getKeySpec().equals(myThat.getKeySpec())
363                     && theKey.getY().equals(myThat.getPublicKey().getY())
364                     && dhParamsAreEqual(theKey.getParams(), myThat.getPublicKey().getParams());
365         }
366 
367         @Override
368         public int hashCode() {
369             return Objects.hash(getKeySpec(), theKey);
370         }
371     }
372 
373     /**
374      * check DH Parameters are equal (ignoring L!!).
375      *
376      * @param pFirst  the first parameters
377      * @param pSecond the second parameters
378      * @return true/false
379      */
380     private static boolean dhParamsAreEqual(final DHParameterSpec pFirst,
381                                             final DHParameterSpec pSecond) {
382         final DHDomainParameterSpec myFirst = (DHDomainParameterSpec) pFirst;
383         final DHDomainParameterSpec mySecond = (DHDomainParameterSpec) pSecond;
384         return myFirst.getP().equals(mySecond.getP())
385                 && myFirst.getG().equals(mySecond.getG())
386                 && myFirst.getQ().equals(mySecond.getQ());
387     }
388 
389     /**
390      * Jca DH PrivateKey.
391      */
392     public static class JcaDHPrivateKey
393             extends JcaPrivateKey {
394         /**
395          * The private key.
396          */
397         private final BCDHPrivateKey thePrivateKey;
398 
399         /**
400          * Constructor.
401          *
402          * @param pKeySpec the key spec
403          * @param pKey     the key
404          */
405         JcaDHPrivateKey(final GordianKeyPairSpec pKeySpec,
406                         final BCDHPrivateKey pKey) {
407             super(pKeySpec, pKey);
408             thePrivateKey = pKey;
409         }
410 
411         @Override
412         public BCDHPrivateKey getPrivateKey() {
413             return thePrivateKey;
414         }
415 
416         @Override
417         public boolean equals(final Object pThat) {
418             /* Handle the trivial cases */
419             if (pThat == this) {
420                 return true;
421             }
422             if (pThat == null) {
423                 return false;
424             }
425 
426             /* Make sure that the object is the same class */
427             if (!(pThat instanceof JcaDHPrivateKey)) {
428                 return false;
429             }
430 
431             /* Access the target field */
432             final JcaDHPrivateKey myThat = (JcaDHPrivateKey) pThat;
433 
434             /* Check differences */
435             return getKeySpec().equals(myThat.getKeySpec())
436                     && thePrivateKey.getX().equals(myThat.getPrivateKey().getX())
437                     && dhParamsAreEqual(thePrivateKey.getParams(), myThat.getPrivateKey().getParams());
438         }
439 
440         @Override
441         public int hashCode() {
442             return Objects.hash(getKeySpec(), thePrivateKey);
443         }
444     }
445 
446     /**
447      * Jca StateAware KeyPair.
448      */
449     public static class JcaStateAwareKeyPair
450             extends JcaKeyPair
451             implements GordianStateAwareKeyPair {
452         /**
453          * Constructor.
454          *
455          * @param pPublic  the public key
456          * @param pPrivate the private key
457          */
458         JcaStateAwareKeyPair(final JcaPublicKey pPublic,
459                              final JcaStateAwarePrivateKey pPrivate) {
460             super(pPublic, pPrivate);
461         }
462 
463         @Override
464         public JcaStateAwarePrivateKey getPrivateKey() {
465             return (JcaStateAwarePrivateKey) super.getPrivateKey();
466         }
467 
468         @Override
469         public long getUsagesRemaining() {
470             return getPrivateKey().getUsagesRemaining();
471         }
472 
473         @Override
474         public JcaStateAwareKeyPair getKeyPairShard(final int pNumUsages) {
475             return new JcaStateAwareKeyPair(getPublicKey(), getPrivateKey().getKeyShard(pNumUsages));
476         }
477     }
478 }