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