KeyAgreementSpi.java revision e1142c149e244797ce73b0e7fad40816e447a817
1package org.bouncycastle.jcajce.provider.asymmetric.dh;
2
3import java.math.BigInteger;
4import java.security.InvalidAlgorithmParameterException;
5import java.security.InvalidKeyException;
6import java.security.Key;
7import java.security.SecureRandom;
8import java.security.spec.AlgorithmParameterSpec;
9import java.util.Hashtable;
10
11import javax.crypto.SecretKey;
12import javax.crypto.ShortBufferException;
13import javax.crypto.interfaces.DHPrivateKey;
14import javax.crypto.interfaces.DHPublicKey;
15import javax.crypto.spec.DHParameterSpec;
16import javax.crypto.spec.SecretKeySpec;
17
18import org.bouncycastle.crypto.params.DESParameters;
19import org.bouncycastle.util.Integers;
20import org.bouncycastle.util.Strings;
21
22/**
23 * Diffie-Hellman key agreement. There's actually a better way of doing this
24 * if you are using long term public keys, see the light-weight version for
25 * details.
26 */
27public class KeyAgreementSpi
28    extends javax.crypto.KeyAgreementSpi
29{
30    private BigInteger      x;
31    private BigInteger      p;
32    private BigInteger      g;
33    private BigInteger      result;
34
35    private static final Hashtable algorithms = new Hashtable();
36
37    static
38    {
39        Integer i64 = Integers.valueOf(64);
40        Integer i192 = Integers.valueOf(192);
41        Integer i128 = Integers.valueOf(128);
42        Integer i256 = Integers.valueOf(256);
43
44        algorithms.put("DES", i64);
45        algorithms.put("DESEDE", i192);
46        algorithms.put("BLOWFISH", i128);
47        algorithms.put("AES", i256);
48    }
49
50    private byte[] bigIntToBytes(
51        BigInteger    r)
52    {
53        byte[]    tmp = r.toByteArray();
54
55        if (tmp[0] == 0)
56        {
57            byte[]    ntmp = new byte[tmp.length - 1];
58
59            System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
60            return ntmp;
61        }
62
63        return tmp;
64    }
65
66    protected Key engineDoPhase(
67        Key     key,
68        boolean lastPhase)
69        throws InvalidKeyException, IllegalStateException
70    {
71        if (x == null)
72        {
73            throw new IllegalStateException("Diffie-Hellman not initialised.");
74        }
75
76        if (!(key instanceof DHPublicKey))
77        {
78            throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
79        }
80        DHPublicKey pubKey = (DHPublicKey)key;
81
82        if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
83        {
84            throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
85        }
86
87        if (lastPhase)
88        {
89            result = ((DHPublicKey)key).getY().modPow(x, p);
90            return null;
91        }
92        else
93        {
94            result = ((DHPublicKey)key).getY().modPow(x, p);
95        }
96
97        return new BCDHPublicKey(result, pubKey.getParams());
98    }
99
100    protected byte[] engineGenerateSecret()
101        throws IllegalStateException
102    {
103        if (x == null)
104        {
105            throw new IllegalStateException("Diffie-Hellman not initialised.");
106        }
107
108        return bigIntToBytes(result);
109    }
110
111    protected int engineGenerateSecret(
112        byte[]  sharedSecret,
113        int     offset)
114        throws IllegalStateException, ShortBufferException
115    {
116        if (x == null)
117        {
118            throw new IllegalStateException("Diffie-Hellman not initialised.");
119        }
120
121        byte[]  secret = bigIntToBytes(result);
122
123        if (sharedSecret.length - offset < secret.length)
124        {
125            throw new ShortBufferException("DHKeyAgreement - buffer too short");
126        }
127
128        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
129
130        return secret.length;
131    }
132
133    protected SecretKey engineGenerateSecret(
134        String algorithm)
135    {
136        if (x == null)
137        {
138            throw new IllegalStateException("Diffie-Hellman not initialised.");
139        }
140
141        String algKey = Strings.toUpperCase(algorithm);
142        byte[] res = bigIntToBytes(result);
143
144        if (algorithms.containsKey(algKey))
145        {
146            Integer length = (Integer)algorithms.get(algKey);
147
148            byte[] key = new byte[length.intValue() / 8];
149            System.arraycopy(res, 0, key, 0, key.length);
150
151            if (algKey.startsWith("DES"))
152            {
153                DESParameters.setOddParity(key);
154            }
155
156            return new SecretKeySpec(key, algorithm);
157        }
158
159        return new SecretKeySpec(res, algorithm);
160    }
161
162    protected void engineInit(
163        Key                     key,
164        AlgorithmParameterSpec  params,
165        SecureRandom            random)
166        throws InvalidKeyException, InvalidAlgorithmParameterException
167    {
168        if (!(key instanceof DHPrivateKey))
169        {
170            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
171        }
172        DHPrivateKey    privKey = (DHPrivateKey)key;
173
174        if (params != null)
175        {
176            if (!(params instanceof DHParameterSpec))
177            {
178                throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
179            }
180            DHParameterSpec p = (DHParameterSpec)params;
181
182            this.p = p.getP();
183            this.g = p.getG();
184        }
185        else
186        {
187            this.p = privKey.getParams().getP();
188            this.g = privKey.getParams().getG();
189        }
190
191        this.x = this.result = privKey.getX();
192    }
193
194    protected void engineInit(
195        Key             key,
196        SecureRandom    random)
197        throws InvalidKeyException
198    {
199        if (!(key instanceof DHPrivateKey))
200        {
201            throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
202        }
203
204        DHPrivateKey    privKey = (DHPrivateKey)key;
205
206        this.p = privKey.getParams().getP();
207        this.g = privKey.getParams().getG();
208        this.x = this.result = privKey.getX();
209    }
210}
211