1 package org.bouncycastle.crypto.agreement;
2 
3 import java.math.BigInteger;
4 
5 import org.bouncycastle.crypto.BasicAgreement;
6 import org.bouncycastle.crypto.CipherParameters;
7 import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
8 import org.bouncycastle.crypto.params.DHParameters;
9 import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
10 import org.bouncycastle.crypto.params.DHPublicKeyParameters;
11 import 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  */
20 public 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 
init( CipherParameters param)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 
getFieldSize()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      */
calculateAgreement( CipherParameters pubKey)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 p = dhParams.getP();
72 
73         BigInteger peerY = pub.getY();
74         if (peerY == null || peerY.compareTo(ONE) <= 0 || peerY.compareTo(p.subtract(ONE)) >= 0)
75         {
76             throw new IllegalArgumentException("Diffie-Hellman public key is weak");
77         }
78 
79         BigInteger result = peerY.modPow(key.getX(), p);
80         if (result.equals(ONE))
81         {
82             throw new IllegalStateException("Shared key can't be 1");
83         }
84 
85         return result;
86     }
87 }
88