1package org.bouncycastle.jcajce.provider.asymmetric.ec;
2
3import java.math.BigInteger;
4import java.security.InvalidAlgorithmParameterException;
5import java.security.InvalidKeyException;
6import java.security.Key;
7import java.security.PrivateKey;
8import java.security.PublicKey;
9import java.security.SecureRandom;
10import java.security.spec.AlgorithmParameterSpec;
11
12import org.bouncycastle.asn1.x9.X9IntegerConverter;
13import org.bouncycastle.crypto.BasicAgreement;
14import org.bouncycastle.crypto.CipherParameters;
15import org.bouncycastle.crypto.DerivationFunction;
16import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
17// BEGIN android-removed
18// import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
19// import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
20// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
21// import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
22// END android-removed
23import org.bouncycastle.crypto.params.ECDomainParameters;
24import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
25import org.bouncycastle.crypto.params.ECPublicKeyParameters;
26// BEGIN android-removed
27// import org.bouncycastle.crypto.params.MQVPrivateParameters;
28// import org.bouncycastle.crypto.params.MQVPublicParameters;
29// import org.bouncycastle.crypto.util.DigestFactory;
30// END android-removed
31import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
32import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
33// BEGIN android-removed
34// import org.bouncycastle.jcajce.spec.MQVParameterSpec;
35// END android-removed
36import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
37import org.bouncycastle.jce.interfaces.ECPrivateKey;
38import org.bouncycastle.jce.interfaces.ECPublicKey;
39// BEGIN android-removed
40// import org.bouncycastle.jce.interfaces.MQVPrivateKey;
41// import org.bouncycastle.jce.interfaces.MQVPublicKey;
42// END android-removed
43
44/**
45 * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
46 * both the simple one, and the simple one with cofactors are supported.
47 *
48 * Also, MQV key agreement per SEC-1
49 */
50public class KeyAgreementSpi
51    extends BaseAgreementSpi
52{
53    private static final X9IntegerConverter converter = new X9IntegerConverter();
54
55    private String                 kaAlgorithm;
56
57    private ECDomainParameters     parameters;
58    private BasicAgreement         agreement;
59
60    // BEGIN android-removed
61    // private MQVParameterSpec       mqvParameters;
62    // END android-removed
63    private BigInteger             result;
64
65    protected KeyAgreementSpi(
66        String kaAlgorithm,
67        BasicAgreement agreement,
68        DerivationFunction kdf)
69    {
70        super(kaAlgorithm, kdf);
71
72        this.kaAlgorithm = kaAlgorithm;
73        this.agreement = agreement;
74    }
75
76    protected byte[] bigIntToBytes(
77        BigInteger    r)
78    {
79        return converter.integerToBytes(r, converter.getByteLength(parameters.getCurve()));
80    }
81
82    protected Key engineDoPhase(
83        Key     key,
84        boolean lastPhase)
85        throws InvalidKeyException, IllegalStateException
86    {
87        if (parameters == null)
88        {
89            throw new IllegalStateException(kaAlgorithm + " not initialised.");
90        }
91
92        if (!lastPhase)
93        {
94            throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
95        }
96
97        CipherParameters pubKey;
98        // BEGIN android-removed
99        // if (agreement instanceof ECMQVBasicAgreement)
100        // {
101        //     if (!(key instanceof MQVPublicKey))
102        //     {
103        //         ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
104        //             ECUtils.generatePublicKeyParameter((PublicKey)key);
105        //         ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
106        //             ECUtils.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
107        //
108        //         pubKey = new MQVPublicParameters(staticKey, ephemKey);
109        //     }
110        //     else
111        //     {
112        //         MQVPublicKey mqvPubKey = (MQVPublicKey)key;
113        //         ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
114        //             ECUtils.generatePublicKeyParameter(mqvPubKey.getStaticKey());
115        //         ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
116        //             ECUtils.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
117        //
118        //         pubKey = new MQVPublicParameters(staticKey, ephemKey);
119        //     }
120        // }
121        // else
122        // END android-removed
123        {
124            if (!(key instanceof PublicKey))
125            {
126                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
127                    + getSimpleName(ECPublicKey.class) + " for doPhase");
128            }
129
130            pubKey = ECUtils.generatePublicKeyParameter((PublicKey)key);
131        }
132
133        try
134        {
135            result = agreement.calculateAgreement(pubKey);
136        } catch (final Exception e) {
137            throw new InvalidKeyException("calculation failed: " + e.getMessage())
138            {
139                public Throwable getCause()
140                            {
141                                return e;
142                            }
143            };
144        }
145        return null;
146    }
147
148    protected void engineInit(
149        Key                     key,
150        AlgorithmParameterSpec  params,
151        SecureRandom            random)
152        throws InvalidKeyException, InvalidAlgorithmParameterException
153    {
154        // BEGIN android-changed
155        if (params != null && !(params instanceof UserKeyingMaterialSpec))
156        // END android-changed
157        {
158            throw new InvalidAlgorithmParameterException("No algorithm parameters supported");
159        }
160
161        initFromKey(key, params);
162    }
163
164    protected void engineInit(
165        Key             key,
166        SecureRandom    random)
167        throws InvalidKeyException
168    {
169        initFromKey(key, null);
170    }
171
172    private void initFromKey(Key key, AlgorithmParameterSpec parameterSpec)
173        throws InvalidKeyException
174    {
175        // BEGIN android-removed
176        // if (agreement instanceof ECMQVBasicAgreement)
177        // {
178        //     mqvParameters = null;
179        //     if (!(key instanceof MQVPrivateKey) && !(parameterSpec instanceof MQVParameterSpec))
180        //     {
181        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
182        //             + getSimpleName(MQVParameterSpec.class) + " for initialisation");
183        //     }
184        //
185        //     ECPrivateKeyParameters staticPrivKey;
186        //     ECPrivateKeyParameters ephemPrivKey;
187        //     ECPublicKeyParameters ephemPubKey;
188        //     if (key instanceof MQVPrivateKey)
189        //     {
190        //         MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
191        //         staticPrivKey = (ECPrivateKeyParameters)
192        //             ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
193        //         ephemPrivKey = (ECPrivateKeyParameters)
194        //             ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
195        //
196        //         ephemPubKey = null;
197        //         if (mqvPrivKey.getEphemeralPublicKey() != null)
198        //         {
199        //             ephemPubKey = (ECPublicKeyParameters)
200        //                 ECUtils.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
201        //         }
202        //     }
203        //     else
204        //     {
205        //         MQVParameterSpec mqvParameterSpec = (MQVParameterSpec)parameterSpec;
206        //
207        //         staticPrivKey = (ECPrivateKeyParameters)
208        //             ECUtil.generatePrivateKeyParameter((PrivateKey)key);
209        //         ephemPrivKey = (ECPrivateKeyParameters)
210        //             ECUtil.generatePrivateKeyParameter(mqvParameterSpec.getEphemeralPrivateKey());
211        //
212        //         ephemPubKey = null;
213        //         if (mqvParameterSpec.getEphemeralPublicKey() != null)
214        //         {
215        //             ephemPubKey = (ECPublicKeyParameters)
216        //                 ECUtils.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey());
217        //         }
218        //         mqvParameters = mqvParameterSpec;
219        //         ukmParameters = mqvParameterSpec.getUserKeyingMaterial();
220        //     }
221        //
222        //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
223        //     this.parameters = staticPrivKey.getParameters();
224        //
225        //     // TODO Validate that all the keys are using the same parameters?
226        //
227        //     agreement.init(localParams);
228        // }
229        // else
230        // END android-removed
231        {
232            if (!(key instanceof PrivateKey))
233            {
234                throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
235                    + getSimpleName(ECPrivateKey.class) + " for initialisation");
236            }
237
238            ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
239            this.parameters = privKey.getParameters();
240            ukmParameters = (parameterSpec instanceof UserKeyingMaterialSpec) ? ((UserKeyingMaterialSpec)parameterSpec).getUserKeyingMaterial() : null;
241            agreement.init(privKey);
242        }
243    }
244
245    private static String getSimpleName(Class clazz)
246    {
247        String fullName = clazz.getName();
248
249        return fullName.substring(fullName.lastIndexOf('.') + 1);
250    }
251
252
253    protected byte[] calcSecret()
254    {
255        return bigIntToBytes(result);
256    }
257
258    public static class DH
259        extends KeyAgreementSpi
260    {
261        public DH()
262        {
263            super("ECDH", new ECDHBasicAgreement(), null);
264        }
265    }
266
267    // BEGIN android-removed
268    // public static class DHC
269    //     extends KeyAgreementSpi
270    // {
271    //     public DHC()
272    //     {
273    //         super("ECDHC", new ECDHCBasicAgreement(), null);
274    //     }
275    // }
276
277    // public static class MQV
278    //     extends KeyAgreementSpi
279    // {
280    //     public MQV()
281    //     {
282    //         super("ECMQV", new ECMQVBasicAgreement(), null);
283    //     }
284    // }
285
286    // public static class DHwithSHA1KDF
287    //     extends KeyAgreementSpi
288    // {
289    //     public DHwithSHA1KDF()
290    //     {
291    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
292    //     }
293    // }
294
295    // public static class DHwithSHA1KDFAndSharedInfo
296    //     extends KeyAgreementSpi
297    // {
298    //     public DHwithSHA1KDFAndSharedInfo()
299    //     {
300    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
301    //     }
302    // }
303
304    // public static class CDHwithSHA1KDFAndSharedInfo
305    //     extends KeyAgreementSpi
306    // {
307    //     public CDHwithSHA1KDFAndSharedInfo()
308    //     {
309    //         super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
310    //     }
311    // }
312
313    // public static class DHwithSHA224KDFAndSharedInfo
314    //     extends KeyAgreementSpi
315    // {
316    //     public DHwithSHA224KDFAndSharedInfo()
317    //     {
318    //         super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
319    //     }
320    // }
321
322    // public static class CDHwithSHA224KDFAndSharedInfo
323    //     extends KeyAgreementSpi
324    // {
325    //     public CDHwithSHA224KDFAndSharedInfo()
326    //     {
327    //         super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
328    //     }
329    // }
330
331    // public static class DHwithSHA256KDFAndSharedInfo
332    //     extends KeyAgreementSpi
333    // {
334    //     public DHwithSHA256KDFAndSharedInfo()
335    //     {
336    //         super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
337    //     }
338    // }
339
340    // public static class CDHwithSHA256KDFAndSharedInfo
341    //     extends KeyAgreementSpi
342    // {
343    //     public CDHwithSHA256KDFAndSharedInfo()
344    //     {
345    //         super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
346    //     }
347    // }
348
349    // public static class DHwithSHA384KDFAndSharedInfo
350    //     extends KeyAgreementSpi
351    // {
352    //     public DHwithSHA384KDFAndSharedInfo()
353    //     {
354    //         super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
355    //     }
356    // }
357
358    // public static class CDHwithSHA384KDFAndSharedInfo
359    //     extends KeyAgreementSpi
360    // {
361    //     public CDHwithSHA384KDFAndSharedInfo()
362    //     {
363    //         super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
364    //     }
365    // }
366
367    // public static class DHwithSHA512KDFAndSharedInfo
368    //      extends KeyAgreementSpi
369    //  {
370    //      public DHwithSHA512KDFAndSharedInfo()
371    //      {
372    //          super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
373    //      }
374    //  }
375
376    //  public static class CDHwithSHA512KDFAndSharedInfo
377    //      extends KeyAgreementSpi
378    //  {
379    //      public CDHwithSHA512KDFAndSharedInfo()
380    //      {
381    //          super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
382    //      }
383    //  }
384
385    // public static class MQVwithSHA1KDFAndSharedInfo
386    //     extends KeyAgreementSpi
387    // {
388    //     public MQVwithSHA1KDFAndSharedInfo()
389    //     {
390    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA1()));
391    //     }
392    // }
393
394    // public static class MQVwithSHA224KDFAndSharedInfo
395    //     extends KeyAgreementSpi
396    // {
397    //     public MQVwithSHA224KDFAndSharedInfo()
398    //     {
399    //         super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA224()));
400    //     }
401    // }
402
403    // public static class MQVwithSHA256KDFAndSharedInfo
404    //     extends KeyAgreementSpi
405    // {
406    //     public MQVwithSHA256KDFAndSharedInfo()
407    //     {
408    //         super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA256()));
409    //     }
410    // }
411
412    // public static class MQVwithSHA384KDFAndSharedInfo
413    //     extends KeyAgreementSpi
414    // {
415    //     public MQVwithSHA384KDFAndSharedInfo()
416    //     {
417    //         super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA384()));
418    //     }
419    // }
420
421    // public static class MQVwithSHA512KDFAndSharedInfo
422    //     extends KeyAgreementSpi
423    // {
424    //     public MQVwithSHA512KDFAndSharedInfo()
425    //     {
426    //         super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(DigestFactory.createSHA512()));
427    //     }
428    // }
429
430    // public static class DHwithSHA1CKDF
431    //     extends KeyAgreementSpi
432    // {
433    //     public DHwithSHA1CKDF()
434    //     {
435    //         super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
436    //     }
437    // }
438
439    // public static class DHwithSHA256CKDF
440    //     extends KeyAgreementSpi
441    // {
442    //     public DHwithSHA256CKDF()
443    //     {
444    //         super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
445    //     }
446    // }
447
448    // public static class DHwithSHA384CKDF
449    //     extends KeyAgreementSpi
450    // {
451    //     public DHwithSHA384CKDF()
452    //     {
453    //         super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
454    //     }
455    // }
456
457    // public static class DHwithSHA512CKDF
458    //     extends KeyAgreementSpi
459    // {
460    //     public DHwithSHA512CKDF()
461    //     {
462    //         super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
463    //     }
464    // }
465
466    // public static class MQVwithSHA1CKDF
467    //     extends KeyAgreementSpi
468    // {
469    //     public MQVwithSHA1CKDF()
470    //     {
471    //         super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA1()));
472    //     }
473    // }
474
475    // public static class MQVwithSHA224CKDF
476    //     extends KeyAgreementSpi
477    // {
478    //     public MQVwithSHA224CKDF()
479    //     {
480    //         super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA224()));
481    //     }
482    // }
483
484    // public static class MQVwithSHA256CKDF
485    //     extends KeyAgreementSpi
486    // {
487    //     public MQVwithSHA256CKDF()
488    //     {
489    //         super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA256()));
490    //     }
491    // }
492
493    // public static class MQVwithSHA384CKDF
494    //     extends KeyAgreementSpi
495    // {
496    //     public MQVwithSHA384CKDF()
497    //     {
498    //         super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA384()));
499    //     }
500    // }
501
502    // public static class MQVwithSHA512CKDF
503    //     extends KeyAgreementSpi
504    // {
505    //     public MQVwithSHA512CKDF()
506    //     {
507    //         super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(DigestFactory.createSHA512()));
508    //     }
509    // }
510    // END android-removed
511}
512