1package org.bouncycastle.crypto.agreement;
2
3import java.math.BigInteger;
4
5import org.bouncycastle.crypto.BasicAgreement;
6import org.bouncycastle.crypto.CipherParameters;
7import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
8import org.bouncycastle.crypto.params.DHParameters;
9import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
10import org.bouncycastle.crypto.params.DHPublicKeyParameters;
11import org.bouncycastle.crypto.params.ParametersWithRandom;
12
13/**
14 * a Diffie-Hellman key agreement class.
15 * <p>
16 * note: This is only the basic algorithm, it doesn't take advantage of
17 * long term public keys if they are available. See the DHAgreement class
18 * for a "better" implementation.
19 */
20public class DHBasicAgreement
21    implements BasicAgreement
22{
23    private static final BigInteger ONE = BigInteger.valueOf(1);
24
25    private DHPrivateKeyParameters  key;
26    private DHParameters            dhParams;
27
28    public void init(
29        CipherParameters    param)
30    {
31        AsymmetricKeyParameter  kParam;
32
33        if (param instanceof ParametersWithRandom)
34        {
35            ParametersWithRandom rParam = (ParametersWithRandom)param;
36            kParam = (AsymmetricKeyParameter)rParam.getParameters();
37        }
38        else
39        {
40            kParam = (AsymmetricKeyParameter)param;
41        }
42
43        if (!(kParam instanceof DHPrivateKeyParameters))
44        {
45            throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
46        }
47
48        this.key = (DHPrivateKeyParameters)kParam;
49        this.dhParams = key.getParameters();
50    }
51
52    public int getFieldSize()
53    {
54        return (key.getParameters().getP().bitLength() + 7) / 8;
55    }
56
57    /**
58     * given a short term public key from a given party calculate the next
59     * message in the agreement sequence.
60     */
61    public BigInteger calculateAgreement(
62        CipherParameters   pubKey)
63    {
64        DHPublicKeyParameters   pub = (DHPublicKeyParameters)pubKey;
65
66        if (!pub.getParameters().equals(dhParams))
67        {
68            throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
69        }
70
71        BigInteger result = pub.getY().modPow(key.getX(), dhParams.getP());
72        if (result.compareTo(ONE) == 0)
73        {
74            throw new IllegalStateException("Shared key can't be 1");
75        }
76
77        return result;
78    }
79}
80