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