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