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