org.bouncycastle.tls.crypto.impl.jcajce.JceTlsECDomain Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bctls-fips Show documentation
Show all versions of bctls-fips Show documentation
The Bouncy Castle Java APIs for the TLS, including a JSSE provider. The APIs are designed primarily to be used in conjunction with the BC FIPS provider. The APIs may also be used with other providers although if being used in a FIPS context it is the responsibility of the user to ensure that any other providers used are FIPS certified and used appropriately.
package org.bouncycastle.tls.crypto.impl.jcajce;
import java.io.IOException;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECField;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECFieldFp;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import javax.crypto.SecretKey;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.tls.AlertDescription;
import org.bouncycastle.tls.NamedGroup;
import org.bouncycastle.tls.TlsFatalAlert;
import org.bouncycastle.tls.crypto.TlsAgreement;
import org.bouncycastle.tls.crypto.TlsCryptoException;
import org.bouncycastle.tls.crypto.TlsECConfig;
import org.bouncycastle.tls.crypto.TlsECDomain;
/**
* EC domain class for generating key pairs and performing key agreement.
*/
public class JceTlsECDomain
implements TlsECDomain
{
protected final JcaTlsCrypto crypto;
protected final TlsECConfig ecConfig;
protected ECGenParameterSpec ecGenSpec;
protected ECParameterSpec ecParameterSpec;
protected ECCurve ecCurve;
public JceTlsECDomain(JcaTlsCrypto crypto, TlsECConfig ecConfig)
{
this.crypto = crypto;
this.ecConfig = ecConfig;
init(ecConfig.getNamedGroup());
}
public JceTlsSecret calculateECDHAgreement(ECPrivateKey privateKey, ECPublicKey publicKey)
throws IOException
{
try
{
/*
* RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
* FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
* any given field; leading zeros found in this octet string MUST NOT be truncated.
*
* We use the convention established by the JSSE to signal this by asking for "TlsPremasterSecret".
*/
SecretKey secretKey = crypto.calculateKeyAgreement("ECDH", privateKey, publicKey, "TlsPremasterSecret");
// TODO Need to consider cases where SecretKey may not be encodable
return crypto.adoptLocalSecret(secretKey.getEncoded());
}
catch (GeneralSecurityException e)
{
throw new TlsCryptoException("cannot calculate secret", e);
}
}
public TlsAgreement createECDH()
{
return new JceTlsECDH(this);
}
public ECPoint decodePoint(byte[] encoding)
throws IOException
{
return ecCurve.decodePoint(encoding);
}
public ECPublicKey decodePublicKey(byte[] encoding)
throws IOException
{
try
{
KeyFactory keyFact = crypto.getHelper().createKeyFactory("EC");
ECPoint point = decodePoint(encoding);
ECPublicKeySpec keySpec = new ECPublicKeySpec(
new java.security.spec.ECPoint(point.getAffineXCoord().toBigInteger(), point.getAffineYCoord().toBigInteger()),
ecParameterSpec);
return (ECPublicKey)keyFact.generatePublic(keySpec);
}
catch (Exception e)
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter, e);
}
}
public byte[] encodePoint(ECPoint point)
throws IOException
{
return point.getEncoded(ecConfig.getPointCompression());
}
public byte[] encodePublicKey(ECPublicKey publicKey)
throws IOException
{
java.security.spec.ECPoint w = publicKey.getW();
return encodePoint(ecCurve.createPoint(w.getAffineX(), w.getAffineY()));
}
public KeyPair generateKeyPair()
{
try
{
KeyPairGenerator keyPairGenerator = crypto.getHelper().createKeyPairGenerator("EC");
keyPairGenerator.initialize(ecGenSpec, crypto.getSecureRandom());
return keyPairGenerator.generateKeyPair();
}
catch (GeneralSecurityException e)
{
throw new IllegalStateException("unable to create key pair: " + e.getMessage(), e);
}
}
private void init(int namedGroup)
{
this.ecCurve = null;
this.ecGenSpec = null;
this.ecParameterSpec = null;
if (!NamedGroup.refersToASpecificCurve(namedGroup))
{
return;
}
String curveName = NamedGroup.getName(namedGroup);
if (curveName == null)
{
return;
}
try
{
AlgorithmParameters ecDomain = crypto.getHelper().createAlgorithmParameters("EC");
this.ecGenSpec = new ECGenParameterSpec(curveName);
try
{
// Try the "modern" way
ecDomain.init(ecGenSpec);
// It's a bit inefficient to do this conversion every time
ECParameterSpec ecSpec = ecDomain.getParameterSpec(ECParameterSpec.class);
this.ecCurve = convertCurve(ecSpec.getCurve(), ecSpec.getOrder(), ecSpec.getCofactor());
this.ecParameterSpec = ecSpec;
}
catch (Exception e)
{
// Try a more round about way (the IBM JCE is an example of this)
KeyPairGenerator kpGen = crypto.getHelper().createKeyPairGenerator("EC");
kpGen.initialize(ecGenSpec, crypto.getSecureRandom());
KeyPair kp = kpGen.generateKeyPair();
ECParameterSpec ecSpec = ((ECPrivateKey)kp.getPrivate()).getParams();
this.ecCurve = convertCurve(ecSpec.getCurve(), ecSpec.getOrder(), ecSpec.getCofactor());
this.ecParameterSpec = ecSpec;
}
}
catch (GeneralSecurityException e)
{
throw new IllegalStateException("unable to create key pair: " + e.getMessage(), e);
}
}
private static ECCurve convertCurve(EllipticCurve ec, BigInteger order, int cofactor)
{
ECField field = ec.getField();
BigInteger a = ec.getA();
BigInteger b = ec.getB();
if (field instanceof ECFieldFp)
{
return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b, order, BigInteger.valueOf(cofactor));
}
else
{
ECFieldF2m fieldF2m = (ECFieldF2m)field;
int m = fieldF2m.getM();
int ks[] = convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b, order, BigInteger.valueOf(cofactor));
}
}
private static int[] convertMidTerms(int[] k)
{
int[] res = new int[3];
if (k.length == 1)
{
res[0] = k[0];
}
else
{
if (k.length != 3)
{
throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
}
if (k[0] < k[1] && k[0] < k[2])
{
res[0] = k[0];
if (k[1] < k[2])
{
res[1] = k[1];
res[2] = k[2];
}
else
{
res[1] = k[2];
res[2] = k[1];
}
}
else if (k[1] < k[2])
{
res[0] = k[1];
if (k[0] < k[2])
{
res[1] = k[0];
res[2] = k[2];
}
else
{
res[1] = k[2];
res[2] = k[0];
}
}
else
{
res[0] = k[2];
if (k[0] < k[1])
{
res[1] = k[0];
res[2] = k[1];
}
else
{
res[1] = k[1];
res[2] = k[0];
}
}
}
return res;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy