1package org.bouncycastle.jce.provider; 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; 9 10import javax.crypto.KeyAgreementSpi; 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 18/** 19 * Diffie-Hellman key agreement. There's actually a better way of doing this 20 * if you are using long term public keys, see the light-weight version for 21 * details. 22 */ 23public class JCEDHKeyAgreement 24 extends KeyAgreementSpi 25{ 26 private BigInteger x; 27 private BigInteger p; 28 private BigInteger g; 29 private BigInteger result; 30 31 private SecureRandom random; 32 33 private byte[] bigIntToBytes( 34 BigInteger r) 35 { 36 byte[] tmp = r.toByteArray(); 37 38 if (tmp[0] == 0) 39 { 40 byte[] ntmp = new byte[tmp.length - 1]; 41 42 System.arraycopy(tmp, 1, ntmp, 0, ntmp.length); 43 return ntmp; 44 } 45 46 return tmp; 47 } 48 49 protected Key engineDoPhase( 50 Key key, 51 boolean lastPhase) 52 throws InvalidKeyException, IllegalStateException 53 { 54 if (x == null) 55 { 56 throw new IllegalStateException("Diffie-Hellman not initialised."); 57 } 58 59 if (!(key instanceof DHPublicKey)) 60 { 61 throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey"); 62 } 63 DHPublicKey pubKey = (DHPublicKey)key; 64 65 if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p)) 66 { 67 throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!"); 68 } 69 70 if (lastPhase) 71 { 72 result = ((DHPublicKey)key).getY().modPow(x, p); 73 return null; 74 } 75 else 76 { 77 result = ((DHPublicKey)key).getY().modPow(x, p); 78 } 79 80 return new JCEDHPublicKey(result, pubKey.getParams()); 81 } 82 83 protected byte[] engineGenerateSecret() 84 throws IllegalStateException 85 { 86 if (x == null) 87 { 88 throw new IllegalStateException("Diffie-Hellman not initialised."); 89 } 90 91 return bigIntToBytes(result); 92 } 93 94 protected int engineGenerateSecret( 95 byte[] sharedSecret, 96 int offset) 97 throws IllegalStateException, ShortBufferException 98 { 99 if (x == null) 100 { 101 throw new IllegalStateException("Diffie-Hellman not initialised."); 102 } 103 104 byte[] secret = bigIntToBytes(result); 105 106 if (sharedSecret.length - offset < secret.length) 107 { 108 throw new ShortBufferException("DHKeyAgreement - buffer too short"); 109 } 110 111 System.arraycopy(secret, 0, sharedSecret, offset, secret.length); 112 113 return secret.length; 114 } 115 116 protected SecretKey engineGenerateSecret( 117 String algorithm) 118 { 119 if (x == null) 120 { 121 throw new IllegalStateException("Diffie-Hellman not initialised."); 122 } 123 124 return new SecretKeySpec(bigIntToBytes(result), algorithm); 125 } 126 127 protected void engineInit( 128 Key key, 129 AlgorithmParameterSpec params, 130 SecureRandom random) 131 throws InvalidKeyException, InvalidAlgorithmParameterException 132 { 133 if (!(key instanceof DHPrivateKey)) 134 { 135 throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation"); 136 } 137 DHPrivateKey privKey = (DHPrivateKey)key; 138 139 this.random = random; 140 141 if (params != null) 142 { 143 if (!(params instanceof DHParameterSpec)) 144 { 145 throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec"); 146 } 147 DHParameterSpec p = (DHParameterSpec)params; 148 149 this.p = p.getP(); 150 this.g = p.getG(); 151 } 152 else 153 { 154 this.p = privKey.getParams().getP(); 155 this.g = privKey.getParams().getG(); 156 } 157 158 this.x = this.result = privKey.getX(); 159 } 160 161 protected void engineInit( 162 Key key, 163 SecureRandom random) 164 throws InvalidKeyException 165 { 166 if (!(key instanceof DHPrivateKey)) 167 { 168 throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey"); 169 } 170 171 DHPrivateKey privKey = (DHPrivateKey)key; 172 173 this.random = random; 174 this.p = privKey.getParams().getP(); 175 this.g = privKey.getParams().getG(); 176 this.x = this.result = privKey.getX(); 177 } 178} 179