1package org.bouncycastle.crypto.agreement;
2
3import java.math.BigInteger;
4import java.security.SecureRandom;
5
6import org.bouncycastle.crypto.CipherParameters;
7import org.bouncycastle.crypto.params.DHParameters;
8import org.bouncycastle.crypto.params.DHPublicKeyParameters;
9import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
10import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
11import org.bouncycastle.crypto.params.ParametersWithRandom;
12
13/**
14 * a Diffie-Hellman key exchange engine.
15 * <p>
16 * note: This uses MTI/A0 key agreement in order to make the key agreement
17 * secure against passive attacks. If you're doing Diffie-Hellman and both
18 * parties have long term public keys you should look at using this. For
19 * further information have a look at RFC 2631.
20 * <p>
21 * It's possible to extend this to more than two parties as well, for the moment
22 * that is left as an exercise for the reader.
23 */
24public class DHAgreement
25{
26    private DHPrivateKeyParameters  key;
27    private DHParameters            dhParams;
28    private BigInteger              privateValue;
29    private SecureRandom            random;
30
31    public void init(
32        CipherParameters    param)
33    {
34        AsymmetricKeyParameter  kParam;
35
36        if (param instanceof ParametersWithRandom)
37        {
38            ParametersWithRandom    rParam = (ParametersWithRandom)param;
39
40            this.random = rParam.getRandom();
41            kParam = (AsymmetricKeyParameter)rParam.getParameters();
42        }
43        else
44        {
45            this.random = new SecureRandom();
46            kParam = (AsymmetricKeyParameter)param;
47        }
48
49
50        if (!(kParam instanceof DHPrivateKeyParameters))
51        {
52            throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
53        }
54
55        this.key = (DHPrivateKeyParameters)kParam;
56        this.dhParams = key.getParameters();
57    }
58
59    /**
60     * calculate our initial message.
61     */
62    public BigInteger calculateMessage()
63    {
64        this.privateValue = new BigInteger(
65                                    dhParams.getP().bitLength() - 1, 0, random);
66
67        return dhParams.getG().modPow(privateValue, dhParams.getP());
68    }
69
70    /**
71     * given a message from a given party and the coresponding public key
72     * calculate the next message in the agreement sequence. In this case
73     * this will represent the shared secret.
74     */
75    public BigInteger calculateAgreement(
76        DHPublicKeyParameters   pub,
77        BigInteger              message)
78    {
79        if (!pub.getParameters().equals(dhParams))
80        {
81            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
82        }
83
84        return message.modPow(key.getX(), dhParams.getP()).multiply(pub.getY().modPow(privateValue, dhParams.getP())).mod(dhParams.getP());
85    }
86}
87