org.spongycastle.jcajce.provider.asymmetric.dh.KeyAgreementSpi Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of prov Show documentation
Show all versions of prov Show documentation
Spongy Castle is a package-rename (org.bouncycastle.* to org.spongycastle.*) of Bouncy Castle
intended for the Android platform. Android unfortunately ships with a stripped-down version of
Bouncy Castle, which prevents easy upgrades - Spongy Castle overcomes this and provides a full,
up-to-date version of the Bouncy Castle cryptographic libs.
The newest version!
package org.spongycastle.jcajce.provider.asymmetric.dh;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
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.spongycastle.crypto.DerivationFunction;
import org.spongycastle.crypto.agreement.kdf.DHKEKGenerator;
import org.spongycastle.crypto.util.DigestFactory;
import org.spongycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
import org.spongycastle.jcajce.spec.UserKeyingMaterialSpec;
/**
* 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 KeyAgreementSpi
extends BaseAgreementSpi
{
private static final BigInteger ONE = BigInteger.valueOf(1);
private static final BigInteger TWO = BigInteger.valueOf(2);
private BigInteger x;
private BigInteger p;
private BigInteger g;
private BigInteger result;
public KeyAgreementSpi()
{
super("Diffie-Hellman", null);
}
public KeyAgreementSpi(
String kaAlgorithm,
DerivationFunction kdf)
{
super(kaAlgorithm, kdf);
}
protected byte[] bigIntToBytes(
BigInteger r)
{
//
// RFC 2631 (2.1.2) specifies that the secret should be padded with leading zeros if necessary
// must be the same length as p
//
int expectedLength = (p.bitLength() + 7) / 8;
byte[] tmp = r.toByteArray();
if (tmp.length == expectedLength)
{
return tmp;
}
if (tmp[0] == 0 && tmp.length == expectedLength + 1)
{
byte[] rv = new byte[tmp.length - 1];
System.arraycopy(tmp, 1, rv, 0, rv.length);
return rv;
}
// tmp must be shorter than expectedLength
// pad to the left with zeros.
byte[] rv = new byte[expectedLength];
System.arraycopy(tmp, 0, rv, rv.length - tmp.length, tmp.length);
return rv;
}
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!");
}
BigInteger peerY = ((DHPublicKey)key).getY();
if (peerY == null || peerY.compareTo(TWO) < 0
|| peerY.compareTo(p.subtract(ONE)) >= 0)
{
throw new InvalidKeyException("Invalid DH PublicKey");
}
result = peerY.modPow(x, p);
if (result.compareTo(ONE) == 0)
{
throw new InvalidKeyException("Shared key can't be 1");
}
if (lastPhase)
{
return null;
}
return new BCDHPublicKey(result, pubKey.getParams());
}
protected byte[] engineGenerateSecret()
throws IllegalStateException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
return super.engineGenerateSecret();
}
protected int engineGenerateSecret(
byte[] sharedSecret,
int offset)
throws IllegalStateException, ShortBufferException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
return super.engineGenerateSecret(sharedSecret, offset);
}
protected SecretKey engineGenerateSecret(
String algorithm)
throws NoSuchAlgorithmException
{
if (x == null)
{
throw new IllegalStateException("Diffie-Hellman not initialised.");
}
byte[] res = bigIntToBytes(result);
// for JSSE compatibility
if (algorithm.equals("TlsPremasterSecret"))
{
return new SecretKeySpec(trimZeroes(res), algorithm);
}
return super.engineGenerateSecret(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) // p, g override.
{
DHParameterSpec p = (DHParameterSpec)params;
this.p = p.getP();
this.g = p.getG();
}
else if (params instanceof UserKeyingMaterialSpec)
{
this.p = privKey.getParams().getP();
this.g = privKey.getParams().getG();
this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial();
}
else
{
throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
}
}
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();
}
protected byte[] calcSecret()
{
return bigIntToBytes(result);
}
public static class DHwithRFC2631KDF
extends KeyAgreementSpi
{
public DHwithRFC2631KDF()
{
super("DHwithRFC2631KDF", new DHKEKGenerator(DigestFactory.createSHA1()));
}
}
}