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.GordianStateAwareKeyPair;
22  import io.github.tonywasher.joceanus.gordianknot.api.keypair.spec.GordianKeyPairSpec;
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 myThat)) {
156                 return false;
157             }
158 
159             /* Check differences */
160             return getKeySpec().equals(myThat.getKeySpec())
161                     && theKey.equals(myThat.getPublicKey());
162         }
163 
164         @Override
165         public int hashCode() {
166             return Objects.hash(getKeySpec(), theKey);
167         }
168     }
169 
170     /**
171      * Jca PrivateKey.
172      */
173     public static class JcaPrivateKey
174             extends GordianPrivateKey {
175         /**
176          * Private Key details.
177          */
178         private final PrivateKey theKey;
179 
180         /**
181          * Constructor.
182          *
183          * @param pKeySpec    the keySpec
184          * @param pPrivateKey the private key
185          */
186         protected JcaPrivateKey(final GordianKeyPairSpec pKeySpec,
187                                 final PrivateKey pPrivateKey) {
188             super(pKeySpec);
189             theKey = pPrivateKey;
190         }
191 
192         /**
193          * Obtain the private key.
194          *
195          * @return the key
196          */
197         protected PrivateKey getPrivateKey() {
198             return theKey;
199         }
200 
201         @Override
202         public boolean equals(final Object pThat) {
203             /* Handle the trivial cases */
204             if (pThat == this) {
205                 return true;
206             }
207             if (pThat == null) {
208                 return false;
209             }
210 
211             /* Make sure that the object is the same class */
212             if (!(pThat instanceof JcaPrivateKey myThat)) {
213                 return false;
214             }
215 
216             /* Check differences */
217             return getKeySpec().equals(myThat.getKeySpec())
218                     && theKey.equals(myThat.getPrivateKey());
219         }
220 
221         @Override
222         public int hashCode() {
223             return Objects.hash(getKeySpec(), theKey);
224         }
225     }
226 
227     /**
228      * Jca StateAware PrivateKey.
229      */
230     public static class JcaStateAwarePrivateKey
231             extends JcaPrivateKey
232             implements GordianStateAwarePrivateKey {
233         /**
234          * The private key.
235          */
236         private final PrivateKey thePrivateKey;
237 
238         /**
239          * Constructor.
240          *
241          * @param pKeySpec the key spec
242          * @param pKey     the key
243          */
244         JcaStateAwarePrivateKey(final GordianKeyPairSpec pKeySpec,
245                                 final PrivateKey pKey) {
246             super(pKeySpec, pKey);
247             thePrivateKey = pKey;
248         }
249 
250         @Override
251         public PrivateKey getPrivateKey() {
252             return thePrivateKey;
253         }
254 
255         @Override
256         public long getUsagesRemaining() {
257             if (thePrivateKey instanceof LMSPrivateKey) {
258                 return ((LMSPrivateKey) getPrivateKey()).getUsagesRemaining();
259             }
260             if (thePrivateKey instanceof XMSSMTPrivateKey) {
261                 return ((XMSSMTPrivateKey) getPrivateKey()).getUsagesRemaining();
262             }
263             return thePrivateKey instanceof XMSSPrivateKey
264                     ? ((XMSSPrivateKey) getPrivateKey()).getUsagesRemaining()
265                     : 0;
266         }
267 
268         @Override
269         public JcaStateAwarePrivateKey getKeyShard(final int pNumUsages) {
270             if (thePrivateKey instanceof LMSPrivateKey) {
271                 return new JcaStateAwarePrivateKey(getKeySpec(), ((LMSPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages));
272             }
273             if (thePrivateKey instanceof XMSSMTPrivateKey) {
274                 return new JcaStateAwarePrivateKey(getKeySpec(), ((XMSSMTPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages));
275             }
276             return thePrivateKey instanceof XMSSPrivateKey
277                     ? new JcaStateAwarePrivateKey(getKeySpec(), ((XMSSPrivateKey) getPrivateKey()).extractKeyShard(pNumUsages))
278                     : null;
279         }
280 
281         @Override
282         public boolean equals(final Object pThat) {
283             /* Handle the trivial cases */
284             if (pThat == this) {
285                 return true;
286             }
287             if (pThat == null) {
288                 return false;
289             }
290 
291             /* Make sure that the object is the same class */
292             if (!(pThat instanceof JcaStateAwarePrivateKey myThat)) {
293                 return false;
294             }
295 
296             /* Check differences */
297             return getKeySpec().equals(myThat.getKeySpec())
298                     && thePrivateKey.equals(myThat.getPrivateKey());
299         }
300 
301         @Override
302         public int hashCode() {
303             return Objects.hash(getKeySpec(), thePrivateKey);
304         }
305     }
306 
307     /**
308      * Jca DH PublicKey.
309      */
310     public static class JcaDHPublicKey
311             extends JcaPublicKey {
312         /**
313          * Public Key details.
314          */
315         private final BCDHPublicKey theKey;
316 
317         /**
318          * Constructor.
319          *
320          * @param pKeySpec   the keySpec
321          * @param pPublicKey the public key
322          */
323         protected JcaDHPublicKey(final GordianKeyPairSpec pKeySpec,
324                                  final BCDHPublicKey pPublicKey) {
325             super(pKeySpec, pPublicKey);
326             theKey = pPublicKey;
327         }
328 
329         @Override
330         protected BCDHPublicKey getPublicKey() {
331             return theKey;
332         }
333 
334         @Override
335         public boolean equals(final Object pThat) {
336             /* Handle the trivial cases */
337             if (pThat == this) {
338                 return true;
339             }
340             if (pThat == null) {
341                 return false;
342             }
343 
344             /* Make sure that the object is the same class */
345             if (!(pThat instanceof JcaDHPublicKey myThat)) {
346                 return false;
347             }
348 
349             /* Check differences */
350             return getKeySpec().equals(myThat.getKeySpec())
351                     && theKey.getY().equals(myThat.getPublicKey().getY())
352                     && dhParamsAreEqual(theKey.getParams(), myThat.getPublicKey().getParams());
353         }
354 
355         @Override
356         public int hashCode() {
357             return Objects.hash(getKeySpec(), theKey);
358         }
359     }
360 
361     /**
362      * check DH Parameters are equal (ignoring L!!).
363      *
364      * @param pFirst  the first parameters
365      * @param pSecond the second parameters
366      * @return true/false
367      */
368     private static boolean dhParamsAreEqual(final DHParameterSpec pFirst,
369                                             final DHParameterSpec pSecond) {
370         final DHDomainParameterSpec myFirst = (DHDomainParameterSpec) pFirst;
371         final DHDomainParameterSpec mySecond = (DHDomainParameterSpec) pSecond;
372         return myFirst.getP().equals(mySecond.getP())
373                 && myFirst.getG().equals(mySecond.getG())
374                 && myFirst.getQ().equals(mySecond.getQ());
375     }
376 
377     /**
378      * Jca DH PrivateKey.
379      */
380     public static class JcaDHPrivateKey
381             extends JcaPrivateKey {
382         /**
383          * The private key.
384          */
385         private final BCDHPrivateKey thePrivateKey;
386 
387         /**
388          * Constructor.
389          *
390          * @param pKeySpec the key spec
391          * @param pKey     the key
392          */
393         JcaDHPrivateKey(final GordianKeyPairSpec pKeySpec,
394                         final BCDHPrivateKey pKey) {
395             super(pKeySpec, pKey);
396             thePrivateKey = pKey;
397         }
398 
399         @Override
400         public BCDHPrivateKey getPrivateKey() {
401             return thePrivateKey;
402         }
403 
404         @Override
405         public boolean equals(final Object pThat) {
406             /* Handle the trivial cases */
407             if (pThat == this) {
408                 return true;
409             }
410             if (pThat == null) {
411                 return false;
412             }
413 
414             /* Make sure that the object is the same class */
415             if (!(pThat instanceof JcaDHPrivateKey myThat)) {
416                 return false;
417             }
418 
419             /* Check differences */
420             return getKeySpec().equals(myThat.getKeySpec())
421                     && thePrivateKey.getX().equals(myThat.getPrivateKey().getX())
422                     && dhParamsAreEqual(thePrivateKey.getParams(), myThat.getPrivateKey().getParams());
423         }
424 
425         @Override
426         public int hashCode() {
427             return Objects.hash(getKeySpec(), thePrivateKey);
428         }
429     }
430 
431     /**
432      * Jca StateAware KeyPair.
433      */
434     public static class JcaStateAwareKeyPair
435             extends JcaKeyPair
436             implements GordianStateAwareKeyPair {
437         /**
438          * Constructor.
439          *
440          * @param pPublic  the public key
441          * @param pPrivate the private key
442          */
443         JcaStateAwareKeyPair(final JcaPublicKey pPublic,
444                              final JcaStateAwarePrivateKey pPrivate) {
445             super(pPublic, pPrivate);
446         }
447 
448         @Override
449         public JcaStateAwarePrivateKey getPrivateKey() {
450             return (JcaStateAwarePrivateKey) super.getPrivateKey();
451         }
452 
453         @Override
454         public long getUsagesRemaining() {
455             return getPrivateKey().getUsagesRemaining();
456         }
457 
458         @Override
459         public JcaStateAwareKeyPair getKeyPairShard(final int pNumUsages) {
460             return new JcaStateAwareKeyPair(getPublicKey(), getPrivateKey().getKeyShard(pNumUsages));
461         }
462     }
463 }