blob: ef8f76a8bda3fcc9568d993e3fdaa0c7035f3751 [file] [log] [blame]
package org.bouncycastle.jce.provider;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Hashtable;
import javax.crypto.KeyAgreementSpi;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.util.Strings;
/**
* Diffie-Hellman key agreement. There's actually a better way of doing this
* if you are using long term public keys, see the light-weight version for
* details.
*/
public class JCEDHKeyAgreement
extends KeyAgreementSpi
{
private BigInteger x;
private BigInteger p;
private BigInteger g;
private BigInteger result;
private static final Hashtable algorithms = new Hashtable();
static
{
// BEGIN android-changed
Integer i64 = Integer.valueOf(64);
Integer i192 = Integer.valueOf(192);
Integer i128 = Integer.valueOf(128);
Integer i256 = Integer.valueOf(256);
// END android-changed
algorithms.put("DES", i64);
algorithms.put("DESEDE", i192);
algorithms.put("BLOWFISH", i128);
algorithms.put("AES", i256);
}
private byte[] bigIntToBytes(
BigInteger r)
{
byte[] tmp = r.toByteArray();
if (tmp[0] == 0)
{
byte[] ntmp = new byte[tmp.length - 1];
System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
return ntmp;
}
return tmp;
}
protected Key engineDoPhase(
Key key,
boolean lastPhase)
throws InvalidKeyException, IllegalStateException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
if (!(key instanceof DHPublicKey))
{
throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
}
DHPublicKey pubKey = (DHPublicKey)key;
if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
{
throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
}
if (lastPhase)
{
result = ((DHPublicKey)key).getY().modPow(x, p);
return null;
}
else
{
result = ((DHPublicKey)key).getY().modPow(x, p);
}
return new JCEDHPublicKey(result, pubKey.getParams());
}
protected byte[] engineGenerateSecret()
throws IllegalStateException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
return bigIntToBytes(result);
}
protected int engineGenerateSecret(
byte[] sharedSecret,
int offset)
throws IllegalStateException, ShortBufferException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
byte[] secret = bigIntToBytes(result);
if (sharedSecret.length - offset < secret.length)
{
throw new ShortBufferException("DHKeyAgreement - buffer too short");
}
System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
return secret.length;
}
protected SecretKey engineGenerateSecret(
String algorithm)
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
String algKey = Strings.toUpperCase(algorithm);
byte[] res = bigIntToBytes(result);
if (algorithms.containsKey(algKey))
{
Integer length = (Integer)algorithms.get(algKey);
byte[] key = new byte[length.intValue() / 8];
System.arraycopy(res, 0, key, 0, key.length);
if (algKey.startsWith("DES"))
{
DESParameters.setOddParity(key);
}
return new SecretKeySpec(key, algorithm);
}
return new SecretKeySpec(res, algorithm);
}
protected void engineInit(
Key key,
AlgorithmParameterSpec params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
if (!(key instanceof DHPrivateKey))
{
throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
}
DHPrivateKey privKey = (DHPrivateKey)key;
if (params != null)
{
if (!(params instanceof DHParameterSpec))
{
throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
}
DHParameterSpec p = (DHParameterSpec)params;
this.p = p.getP();
this.g = p.getG();
}
else
{
this.p = privKey.getParams().getP();
this.g = privKey.getParams().getG();
}
this.x = this.result = privKey.getX();
}
protected void engineInit(
Key key,
SecureRandom random)
throws InvalidKeyException
{
if (!(key instanceof DHPrivateKey))
{
throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
}
DHPrivateKey privKey = (DHPrivateKey)key;
this.p = privKey.getParams().getP();
this.g = privKey.getParams().getG();
this.x = this.result = privKey.getX();
}
}