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