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.bc;
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.spec.GordianKeyPairSpec;
22  import io.github.tonywasher.joceanus.gordianknot.api.sign.GordianNewSignParams;
23  import io.github.tonywasher.joceanus.gordianknot.api.sign.spec.GordianSignatureSpec;
24  import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPrivateKey;
25  import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncyKeyPair.BouncyPublicKey;
26  import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncySignature.BouncyDERCoder;
27  import io.github.tonywasher.joceanus.gordianknot.impl.bc.BouncySignature.BouncyDigestSignature;
28  import io.github.tonywasher.joceanus.gordianknot.impl.core.agree.GordianCoreAgreementFactory;
29  import io.github.tonywasher.joceanus.gordianknot.impl.core.base.GordianBaseFactory;
30  import io.github.tonywasher.joceanus.gordianknot.impl.core.encrypt.GordianCoreEncryptor;
31  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianCryptoException;
32  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianIOException;
33  import io.github.tonywasher.joceanus.gordianknot.impl.core.exc.GordianLogicException;
34  import io.github.tonywasher.joceanus.gordianknot.impl.core.keypair.GordianKeyPairValidity;
35  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.agree.GordianCoreAgreementSpec;
36  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.encrypt.GordianCoreEncryptorSpec;
37  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreElliptic;
38  import io.github.tonywasher.joceanus.gordianknot.impl.core.spec.keypair.GordianCoreKeyPairSpec;
39  import io.github.tonywasher.joceanus.gordianknot.impl.ext.engines.GordianEllipticEncryptor;
40  import org.bouncycastle.asn1.ASN1ObjectIdentifier;
41  import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
42  import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
43  import org.bouncycastle.asn1.x9.ECNamedCurveTable;
44  import org.bouncycastle.asn1.x9.X9ECParameters;
45  import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
46  import org.bouncycastle.crypto.DSA;
47  import org.bouncycastle.crypto.DerivationFunction;
48  import org.bouncycastle.crypto.InvalidCipherTextException;
49  import org.bouncycastle.crypto.SecretWithEncapsulation;
50  import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
51  import org.bouncycastle.crypto.agreement.ECDHCUnifiedAgreement;
52  import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
53  import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
54  import org.bouncycastle.crypto.kems.ECIESKEMExtractor;
55  import org.bouncycastle.crypto.kems.ECIESKEMGenerator;
56  import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
57  import org.bouncycastle.crypto.params.ECDHUPrivateParameters;
58  import org.bouncycastle.crypto.params.ECDHUPublicParameters;
59  import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
60  import org.bouncycastle.crypto.params.ECNamedDomainParameters;
61  import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
62  import org.bouncycastle.crypto.params.ECPublicKeyParameters;
63  import org.bouncycastle.crypto.params.MQVPrivateParameters;
64  import org.bouncycastle.crypto.params.MQVPublicParameters;
65  import org.bouncycastle.crypto.params.ParametersWithRandom;
66  import org.bouncycastle.crypto.util.PrivateKeyFactory;
67  import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
68  import org.bouncycastle.crypto.util.PublicKeyFactory;
69  import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
70  import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
71  import org.bouncycastle.util.BigIntegers;
72  
73  import javax.security.auth.DestroyFailedException;
74  import java.io.IOException;
75  import java.math.BigInteger;
76  import java.security.spec.PKCS8EncodedKeySpec;
77  import java.security.spec.X509EncodedKeySpec;
78  
79  /**
80   * EllipticCurve KeyPair classes.
81   */
82  public final class BouncyEllipticKeyPair {
83      /**
84       * Private constructor.
85       */
86      private BouncyEllipticKeyPair() {
87      }
88  
89      /**
90       * Bouncy Elliptic PublicKey.
91       */
92      public static class BouncyECPublicKey
93              extends BouncyPublicKey<ECPublicKeyParameters> {
94          /**
95           * Constructor.
96           *
97           * @param pKeySpec   the keySpec
98           * @param pPublicKey the public key
99           */
100         BouncyECPublicKey(final GordianKeyPairSpec pKeySpec,
101                           final ECPublicKeyParameters pPublicKey) {
102             super(pKeySpec, pPublicKey);
103         }
104 
105         @Override
106         protected boolean matchKey(final AsymmetricKeyParameter pThat) {
107             /* Access keys */
108             final ECPublicKeyParameters myThis = getPublicKey();
109             final ECPublicKeyParameters myThat = (ECPublicKeyParameters) pThat;
110 
111             /* Compare keys */
112             return compareKeys(myThis, myThat);
113         }
114 
115         /**
116          * Is the private key valid for this public key?
117          *
118          * @param pPrivate the private key
119          * @return true/false
120          */
121         public boolean validPrivate(final BouncyECPrivateKey pPrivate) {
122             final ECPrivateKeyParameters myPrivate = pPrivate.getPrivateKey();
123             return getPublicKey().getParameters().equals(myPrivate.getParameters());
124         }
125 
126         /**
127          * CompareKeys.
128          *
129          * @param pFirst  the first key
130          * @param pSecond the second key
131          * @return true/false
132          */
133         private static boolean compareKeys(final ECPublicKeyParameters pFirst,
134                                            final ECPublicKeyParameters pSecond) {
135             return pFirst.getQ().equals(pSecond.getQ())
136                     && pFirst.getParameters().equals(pSecond.getParameters());
137         }
138     }
139 
140     /**
141      * Bouncy Elliptic PrivateKey.
142      */
143     public static class BouncyECPrivateKey
144             extends BouncyPrivateKey<ECPrivateKeyParameters> {
145         /**
146          * Constructor.
147          *
148          * @param pKeySpec    the keySpec
149          * @param pPrivateKey the private key
150          */
151         BouncyECPrivateKey(final GordianKeyPairSpec pKeySpec,
152                            final ECPrivateKeyParameters pPrivateKey) {
153             super(pKeySpec, pPrivateKey);
154         }
155 
156         @Override
157         protected boolean matchKey(final AsymmetricKeyParameter pThat) {
158             /* Access keys */
159             final ECPrivateKeyParameters myThis = getPrivateKey();
160             final ECPrivateKeyParameters myThat = (ECPrivateKeyParameters) pThat;
161 
162             /* Compare keys */
163             return compareKeys(myThis, myThat);
164         }
165 
166         /**
167          * CompareKeys.
168          *
169          * @param pFirst  the first key
170          * @param pSecond the second key
171          * @return true/false
172          */
173         private static boolean compareKeys(final ECPrivateKeyParameters pFirst,
174                                            final ECPrivateKeyParameters pSecond) {
175             return pFirst.getD().equals(pSecond.getD())
176                     && pFirst.getParameters().equals(pSecond.getParameters());
177         }
178     }
179 
180     /**
181      * BouncyCastle Elliptic KeyPair generator.
182      */
183     public static class BouncyECKeyPairGenerator
184             extends BouncyKeyPairGenerator {
185         /**
186          * Generator.
187          */
188         private final ECKeyPairGenerator theGenerator;
189 
190         /**
191          * Constructor.
192          *
193          * @param pFactory the Security Factory
194          * @param pKeySpec the keySpec
195          * @throws GordianException on error
196          */
197         BouncyECKeyPairGenerator(final GordianBaseFactory pFactory,
198                                  final GordianKeyPairSpec pKeySpec) throws GordianException {
199             /* Initialise underlying class */
200             super(pFactory, pKeySpec);
201 
202             /* Create the generator */
203             theGenerator = newGenerator();
204 
205             /* Lookup the parameters */
206             final GordianCoreKeyPairSpec myKeySpec = (GordianCoreKeyPairSpec) pKeySpec;
207             final GordianCoreElliptic myElliptic = myKeySpec.getElliptic();
208             final String myCurve = myElliptic.getCurveName();
209             final X9ECParameters x9 = myElliptic.hasCustomCurve()
210                     ? ECUtil.getNamedCurveByName(myCurve)
211                     : ECNamedCurveTable.getByName(myCurve);
212             if (x9 == null) {
213                 throw new GordianLogicException("Invalid KeySpec - " + pKeySpec);
214             }
215 
216             /* Initialise the generator */
217             final ASN1ObjectIdentifier myOid = ECUtil.getNamedCurveOid(myCurve);
218             final ECNamedDomainParameters myDomain = new ECNamedDomainParameters(myOid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
219             final ECKeyGenerationParameters myParams = new ECKeyGenerationParameters(myDomain, getRandom());
220             theGenerator.init(myParams);
221         }
222 
223         /**
224          * Create the generator.
225          *
226          * @return the generator
227          */
228         ECKeyPairGenerator newGenerator() {
229             return new ECKeyPairGenerator();
230         }
231 
232         @Override
233         public BouncyKeyPair generateKeyPair() {
234             /* Generate and return the keyPair */
235             final AsymmetricCipherKeyPair myPair = theGenerator.generateKeyPair();
236             final BouncyECPublicKey myPublic = new BouncyECPublicKey(getKeySpec(), (ECPublicKeyParameters) myPair.getPublic());
237             final BouncyECPrivateKey myPrivate = new BouncyECPrivateKey(getKeySpec(), (ECPrivateKeyParameters) myPair.getPrivate());
238             return new BouncyKeyPair(myPublic, myPrivate);
239         }
240 
241         @Override
242         public PKCS8EncodedKeySpec getPKCS8Encoding(final GordianKeyPair pKeyPair) throws GordianException {
243             /* Protect against exceptions */
244             try {
245                 /* Check the keyPair type and keySpecs */
246                 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
247 
248                 /* build and return the encoding */
249                 final BouncyECPrivateKey myPrivateKey = (BouncyECPrivateKey) getPrivateKey(pKeyPair);
250                 final ECPrivateKeyParameters myParms = myPrivateKey.getPrivateKey();
251                 final PrivateKeyInfo myInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(myParms);
252                 return new PKCS8EncodedKeySpec(myInfo.getEncoded());
253 
254             } catch (IOException e) {
255                 throw new GordianCryptoException(ERROR_PARSE, e);
256             }
257         }
258 
259         @Override
260         public BouncyKeyPair deriveKeyPair(final X509EncodedKeySpec pPublicKey,
261                                            final PKCS8EncodedKeySpec pPrivateKey) throws GordianException {
262             /* Protect against exceptions */
263             try {
264                 /* Check the keySpecs */
265                 checkKeySpec(pPrivateKey);
266 
267                 /* derive keyPair */
268                 final BouncyECPublicKey myPublic = derivePublicKey(pPublicKey);
269                 final PrivateKeyInfo myInfo = PrivateKeyInfo.getInstance(pPrivateKey.getEncoded());
270                 final ECPrivateKeyParameters myParms = (ECPrivateKeyParameters) PrivateKeyFactory.createKey(myInfo);
271                 final BouncyECPrivateKey myPrivate = new BouncyECPrivateKey(getKeySpec(), myParms);
272                 final BouncyKeyPair myPair = new BouncyKeyPair(myPublic, myPrivate);
273 
274                 /* Check that we have a matching pair */
275                 GordianKeyPairValidity.checkValidity(getFactory(), myPair);
276 
277                 /* Return the keyPair */
278                 return myPair;
279 
280             } catch (IOException e) {
281                 throw new GordianCryptoException(ERROR_PARSE, e);
282             }
283         }
284 
285         @Override
286         public X509EncodedKeySpec getX509Encoding(final GordianKeyPair pKeyPair) throws GordianException {
287             /* Protect against exceptions */
288             try {
289                 /* Check the keyPair type and keySpecs */
290                 BouncyKeyPair.checkKeyPair(pKeyPair, getKeySpec());
291 
292                 /* build and return the encoding */
293                 final BouncyECPublicKey myPublicKey = (BouncyECPublicKey) getPublicKey(pKeyPair);
294                 final ECPublicKeyParameters myParms = myPublicKey.getPublicKey();
295                 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(myParms);
296                 return new X509EncodedKeySpec(myInfo.getEncoded());
297 
298             } catch (IOException e) {
299                 throw new GordianCryptoException(ERROR_PARSE, e);
300             }
301         }
302 
303         @Override
304         public BouncyKeyPair derivePublicOnlyKeyPair(final X509EncodedKeySpec pEncodedKey) throws GordianException {
305             final BouncyECPublicKey myPublic = derivePublicKey(pEncodedKey);
306             return new BouncyKeyPair(myPublic);
307         }
308 
309         /**
310          * Derive public key from encoded.
311          *
312          * @param pEncodedKey the encoded key
313          * @return the public key
314          * @throws GordianException on error
315          */
316         private BouncyECPublicKey derivePublicKey(final X509EncodedKeySpec pEncodedKey) throws GordianException {
317             /* Protect against exceptions */
318             try {
319                 /* Check the keySpecs */
320                 checkKeySpec(pEncodedKey);
321 
322                 /* derive publicKey */
323                 final SubjectPublicKeyInfo myInfo = SubjectPublicKeyInfo.getInstance(pEncodedKey.getEncoded());
324                 final ECPublicKeyParameters myParms = (ECPublicKeyParameters) PublicKeyFactory.createKey(myInfo);
325                 return new BouncyECPublicKey(getKeySpec(), myParms);
326 
327             } catch (IOException e) {
328                 throw new GordianCryptoException(ERROR_PARSE, e);
329             }
330         }
331     }
332 
333     /**
334      * EC signer.
335      */
336     public static class BouncyECSignature
337             extends BouncyDigestSignature {
338         /**
339          * The Signer.
340          */
341         private final DSA theSigner;
342 
343         /**
344          * The Coder.
345          */
346         private final BouncyDERCoder theCoder;
347 
348         /**
349          * Constructor.
350          *
351          * @param pFactory the factory
352          * @param pSpec    the signatureSpec.
353          * @throws GordianException on error
354          */
355         BouncyECSignature(final GordianBaseFactory pFactory,
356                           final GordianSignatureSpec pSpec) throws GordianException {
357             /* Initialise underlying class */
358             super(pFactory, pSpec);
359 
360             /* Create the signer and Coder */
361             theSigner = BouncySignature.getDSASigner(pFactory, pSpec);
362             theCoder = new BouncyDERCoder();
363         }
364 
365         @Override
366         public void initForSigning(final GordianNewSignParams pParams) throws GordianException {
367             /* Initialise detail */
368             super.initForSigning(pParams);
369             final BouncyKeyPair myPair = getKeyPair();
370             BouncyKeyPair.checkKeyPair(myPair);
371 
372             /* Initialise and set the signer */
373             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) myPair.getPrivateKey();
374             final ParametersWithRandom myParms = new ParametersWithRandom(myPrivate.getPrivateKey(), getRandom());
375             theSigner.init(true, myParms);
376         }
377 
378         @Override
379         public void initForVerify(final GordianNewSignParams pParams) throws GordianException {
380             /* Initialise detail */
381             super.initForVerify(pParams);
382             final BouncyKeyPair myPair = getKeyPair();
383             BouncyKeyPair.checkKeyPair(myPair);
384 
385             /* Initialise and set the signer */
386             final BouncyECPublicKey myPublic = (BouncyECPublicKey) myPair.getPublicKey();
387             theSigner.init(false, myPublic.getPublicKey());
388         }
389 
390         @Override
391         public byte[] sign() throws GordianException {
392             /* Check that we are in signing mode */
393             checkMode(GordianSignatureMode.SIGN);
394 
395             /* Sign the message */
396             final BigInteger[] myValues = theSigner.generateSignature(getDigest());
397             return theCoder.dsaEncode(myValues[0], myValues[1]);
398         }
399 
400         @Override
401         public boolean verify(final byte[] pSignature) throws GordianException {
402             /* Check that we are in verify mode */
403             checkMode(GordianSignatureMode.VERIFY);
404 
405             /* Verify the message */
406             final BigInteger[] myValues = theCoder.dsaDecode(pSignature);
407             return theSigner.verifySignature(getDigest(), myValues[0], myValues[1]);
408         }
409     }
410 
411     /**
412      * EC Agreement Engine.
413      */
414     public static class BouncyECIESAgreementEngine
415             extends BouncyAgreementBase {
416         /**
417          * Key Length.
418          */
419         private static final int KEYLEN = 32;
420 
421         /**
422          * Derivation function.
423          */
424         private final DerivationFunction theDerivation;
425 
426         /**
427          * Constructor.
428          *
429          * @param pFactory the security factory
430          * @param pSpec    the agreementSpec
431          * @throws GordianException on error
432          */
433         BouncyECIESAgreementEngine(final GordianCoreAgreementFactory pFactory,
434                                    final GordianCoreAgreementSpec pSpec) throws GordianException {
435             /* Initialize underlying class */
436             super(pFactory, pSpec);
437 
438             /* Initialise the derivation function */
439             theDerivation = newDerivationFunction();
440         }
441 
442         @Override
443         public void buildClientHello() throws GordianException {
444             /* Protect against exceptions */
445             try {
446                 /* Create encapsulation */
447                 final BouncyECPublicKey myPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
448                 final ECIESKEMGenerator myGenerator = new ECIESKEMGenerator(KEYLEN, theDerivation, getRandom());
449                 final SecretWithEncapsulation myResult = myGenerator.generateEncapsulated(myPublic.getPublicKey());
450 
451                 /* Store the encapsulation */
452                 setEncapsulated(myResult.getEncapsulation());
453 
454                 /* Store secret and create initVector */
455                 storeSecret(myResult.getSecret());
456                 myResult.destroy();
457 
458             } catch (DestroyFailedException e) {
459                 throw new GordianIOException("Failed to destroy secret", e);
460             }
461         }
462 
463         @Override
464         public void processClientHello() throws GordianException {
465             /* Create encapsulation */
466             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
467             final ECIESKEMExtractor myExtractor = new ECIESKEMExtractor(myPrivate.getPrivateKey(), KEYLEN, theDerivation);
468 
469             /* Parse encapsulated message and store secret */
470             final byte[] myMessage = getEncapsulated();
471             storeSecret(myExtractor.extractSecret(myMessage));
472         }
473     }
474 
475     /**
476      * EC Anonymous Agreement Engine.
477      */
478     public static class BouncyECAnonAgreementEngine
479             extends BouncyAgreementBase {
480         /**
481          * The agreement.
482          */
483         private final ECDHCBasicAgreement theAgreement;
484 
485         /**
486          * Constructor.
487          *
488          * @param pFactory the security factory
489          * @param pSpec    the agreementSpec
490          * @throws GordianException on error
491          */
492         BouncyECAnonAgreementEngine(final GordianCoreAgreementFactory pFactory,
493                                     final GordianCoreAgreementSpec pSpec) throws GordianException {
494             /* Initialize underlying class */
495             super(pFactory, pSpec);
496 
497             /* Create the agreement */
498             theAgreement = new ECDHCBasicAgreement();
499         }
500 
501         @Override
502         public void buildClientHello() throws GordianException {
503             /* Access keys */
504             final BouncyECPublicKey myPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
505             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getClientEphemeral());
506 
507             /* Derive the secret */
508             theAgreement.init(myPrivate.getPrivateKey());
509             final BigInteger mySecretInt = theAgreement.calculateAgreement(myPublic.getPublicKey());
510             final byte[] mySecret = BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), mySecretInt);
511 
512             /* Store secret */
513             storeSecret(mySecret);
514         }
515 
516         @Override
517         public void processClientHello() throws GordianException {
518             /* Access keys */
519             final BouncyECPublicKey myPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
520             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
521 
522             /* Derive the secret */
523             theAgreement.init(myPrivate.getPrivateKey());
524             final BigInteger mySecretInt = theAgreement.calculateAgreement(myPublic.getPublicKey());
525             final byte[] mySecret = BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), mySecretInt);
526 
527             /* Store secret */
528             storeSecret(mySecret);
529         }
530     }
531 
532     /**
533      * EC Basic Agreement Engine.
534      */
535     public static class BouncyECBasicAgreementEngine
536             extends BouncyAgreementBase {
537         /**
538          * The agreement.
539          */
540         private final ECDHCBasicAgreement theAgreement;
541 
542         /**
543          * Constructor.
544          *
545          * @param pFactory the security factory
546          * @param pSpec    the agreementSpec
547          * @throws GordianException on error
548          */
549         BouncyECBasicAgreementEngine(final GordianCoreAgreementFactory pFactory,
550                                      final GordianCoreAgreementSpec pSpec) throws GordianException {
551             /* Initialize underlying class */
552             super(pFactory, pSpec);
553 
554             /* Create the agreement */
555             theAgreement = new ECDHCBasicAgreement();
556         }
557 
558         @Override
559         public void processClientHello() throws GordianException {
560             /* Access keys */
561             final BouncyECPublicKey myPublic = (BouncyECPublicKey) getPublicKey(getClientKeyPair());
562             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
563 
564             /* Derive the secret */
565             theAgreement.init(myPrivate.getPrivateKey());
566             final BigInteger mySecretInt = theAgreement.calculateAgreement(myPublic.getPublicKey());
567             final byte[] mySecret = BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), mySecretInt);
568 
569             /* Store secret */
570             storeSecret(mySecret);
571         }
572 
573         @Override
574         public void processServerHello() throws GordianException {
575             /* Access keys */
576             final BouncyECPublicKey myPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
577             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getClientKeyPair());
578 
579             /* Derive the secret */
580             theAgreement.init(myPrivate.getPrivateKey());
581             final BigInteger mySecretInt = theAgreement.calculateAgreement(myPublic.getPublicKey());
582             final byte[] mySecret = BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), mySecretInt);
583 
584             /* Store secret */
585             storeSecret(mySecret);
586         }
587     }
588 
589     /**
590      * EC Unified Agreement Engine.
591      */
592     public static class BouncyECUnifiedAgreementEngine
593             extends BouncyAgreementBase {
594         /**
595          * The agreement.
596          */
597         private final ECDHCUnifiedAgreement theAgreement;
598 
599         /**
600          * Constructor.
601          *
602          * @param pFactory the security factory
603          * @param pSpec    the agreementSpec
604          * @throws GordianException on error
605          */
606         BouncyECUnifiedAgreementEngine(final GordianCoreAgreementFactory pFactory,
607                                        final GordianCoreAgreementSpec pSpec) throws GordianException {
608             /* Initialize underlying class */
609             super(pFactory, pSpec);
610 
611             /* Create the agreement */
612             theAgreement = new ECDHCUnifiedAgreement();
613         }
614 
615         @Override
616         public void processClientHello() throws GordianException {
617             /* Access keys */
618             final BouncyECPublicKey myClientPublic = (BouncyECPublicKey) getPublicKey(getClientKeyPair());
619             final BouncyECPublicKey myClientEphPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
620             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
621             final BouncyECPublicKey myEphPublic = (BouncyECPublicKey) getPublicKey(getServerEphemeral());
622             final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getServerEphemeral());
623 
624             /* Derive the secret */
625             final ECDHUPrivateParameters myPrivParams
626                     = new ECDHUPrivateParameters(myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey(), myEphPublic.getPublicKey());
627             theAgreement.init(myPrivParams);
628             final ECDHUPublicParameters myPubParams
629                     = new ECDHUPublicParameters(myClientPublic.getPublicKey(), myClientEphPublic.getPublicKey());
630             storeSecret(theAgreement.calculateAgreement(myPubParams));
631         }
632 
633         @Override
634         public void processServerHello() throws GordianException {
635             /* Access keys */
636             final BouncyECPublicKey myServerPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
637             final BouncyECPublicKey myServerEphPublic = (BouncyECPublicKey) getPublicKey(getServerEphemeral());
638             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getClientKeyPair());
639             final BouncyECPublicKey myEphPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
640             final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getClientEphemeral());
641 
642             /* Derive the secret */
643             final ECDHUPrivateParameters myPrivParams
644                     = new ECDHUPrivateParameters(myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey(), myEphPublic.getPublicKey());
645             theAgreement.init(myPrivParams);
646             final ECDHUPublicParameters myPubParams
647                     = new ECDHUPublicParameters(myServerPublic.getPublicKey(), myServerEphPublic.getPublicKey());
648             storeSecret(theAgreement.calculateAgreement(myPubParams));
649         }
650     }
651 
652     /**
653      * EC MQV Agreement Engine.
654      */
655     public static class BouncyECMQVAgreementEngine
656             extends BouncyAgreementBase {
657         /**
658          * The agreement.
659          */
660         private final ECMQVBasicAgreement theAgreement;
661 
662         /**
663          * Constructor.
664          *
665          * @param pFactory the security factory
666          * @param pSpec    the agreementSpec
667          * @throws GordianException on error
668          */
669         BouncyECMQVAgreementEngine(final GordianCoreAgreementFactory pFactory,
670                                    final GordianCoreAgreementSpec pSpec) throws GordianException {
671             /* Initialize underlying class */
672             super(pFactory, pSpec);
673 
674             /* Create the agreement */
675             theAgreement = new ECMQVBasicAgreement();
676         }
677 
678         @Override
679         public void processClientHello() throws GordianException {
680             /* Access keys */
681             final BouncyECPublicKey myClientPublic = (BouncyECPublicKey) getPublicKey(getClientKeyPair());
682             final BouncyECPublicKey myClientEphPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
683             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getServerKeyPair());
684             final BouncyECPublicKey myEphPublic = (BouncyECPublicKey) getPublicKey(getServerEphemeral());
685             final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getServerEphemeral());
686 
687             /* Derive the secret */
688             final MQVPrivateParameters myPrivParams
689                     = new MQVPrivateParameters(myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey(), myEphPublic.getPublicKey());
690             theAgreement.init(myPrivParams);
691             final MQVPublicParameters myPubParams
692                     = new MQVPublicParameters(myClientPublic.getPublicKey(), myClientEphPublic.getPublicKey());
693             storeSecret(BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), theAgreement.calculateAgreement(myPubParams)));
694         }
695 
696         @Override
697         public void processServerHello() throws GordianException {
698             /* Access keys */
699             final BouncyECPublicKey myServerPublic = (BouncyECPublicKey) getPublicKey(getServerKeyPair());
700             final BouncyECPublicKey myServerEphPublic = (BouncyECPublicKey) getPublicKey(getServerEphemeral());
701             final BouncyECPrivateKey myPrivate = (BouncyECPrivateKey) getPrivateKey(getClientKeyPair());
702             final BouncyECPublicKey myEphPublic = (BouncyECPublicKey) getPublicKey(getClientEphemeral());
703             final BouncyECPrivateKey myEphPrivate = (BouncyECPrivateKey) getPrivateKey(getClientEphemeral());
704 
705             /* Derive the secret */
706             final MQVPrivateParameters myPrivParams
707                     = new MQVPrivateParameters(myPrivate.getPrivateKey(), myEphPrivate.getPrivateKey(), myEphPublic.getPublicKey());
708             theAgreement.init(myPrivParams);
709             final MQVPublicParameters myPubParams
710                     = new MQVPublicParameters(myServerPublic.getPublicKey(), myServerEphPublic.getPublicKey());
711             storeSecret(BigIntegers.asUnsignedByteArray(theAgreement.getFieldSize(), theAgreement.calculateAgreement(myPubParams)));
712         }
713     }
714 
715     /**
716      * EC Encryptor.
717      */
718     public static class BouncyECEncryptor
719             extends GordianCoreEncryptor {
720         /**
721          * The underlying encryptor.
722          */
723         private final GordianEllipticEncryptor theEncryptor;
724 
725         /**
726          * Constructor.
727          *
728          * @param pFactory the factory
729          * @param pSpec    the encryptorSpec
730          */
731         BouncyECEncryptor(final GordianBaseFactory pFactory,
732                           final GordianCoreEncryptorSpec pSpec) {
733             /* Initialise underlying cipher */
734             super(pFactory, pSpec);
735             theEncryptor = new GordianEllipticEncryptor();
736         }
737 
738         @Override
739         protected BouncyPublicKey<?> getPublicKey() {
740             return (BouncyPublicKey<?>) super.getPublicKey();
741         }
742 
743         @Override
744         protected BouncyPrivateKey<?> getPrivateKey() {
745             return (BouncyPrivateKey<?>) super.getPrivateKey();
746         }
747 
748         @Override
749         public void initForEncrypt(final GordianKeyPair pKeyPair) throws GordianException {
750             /* Initialize underlying cipher */
751             BouncyKeyPair.checkKeyPair(pKeyPair);
752             super.initForEncrypt(pKeyPair);
753 
754             /* Initialize for encryption */
755             final ECPublicKeyParameters myParms = (ECPublicKeyParameters) getPublicKey().getPublicKey();
756             theEncryptor.initForEncrypt(myParms, getRandom());
757         }
758 
759         @Override
760         public void initForDecrypt(final GordianKeyPair pKeyPair) throws GordianException {
761             /* Initialize underlying cipher */
762             BouncyKeyPair.checkKeyPair(pKeyPair);
763             super.initForDecrypt(pKeyPair);
764 
765             /* Initialize for decryption */
766             final ECPrivateKeyParameters myParms = (ECPrivateKeyParameters) getPrivateKey().getPrivateKey();
767             theEncryptor.initForDecrypt(myParms);
768         }
769 
770         @Override
771         public byte[] encrypt(final byte[] pBytes) throws GordianException {
772             try {
773                 /* Check that we are in encryption mode */
774                 checkMode(GordianEncryptMode.ENCRYPT);
775 
776                 /* Encrypt the message */
777                 return theEncryptor.encrypt(pBytes);
778             } catch (InvalidCipherTextException e) {
779                 throw new GordianCryptoException("Failed to process data", e);
780             }
781         }
782 
783         @Override
784         public byte[] decrypt(final byte[] pBytes) throws GordianException {
785             try {
786                 /* Check that we are in decryption mode */
787                 checkMode(GordianEncryptMode.DECRYPT);
788 
789                 /* Decrypt the message */
790                 return theEncryptor.decrypt(pBytes);
791             } catch (InvalidCipherTextException e) {
792                 throw new GordianCryptoException("Failed to process data", e);
793             }
794         }
795     }
796 }