org.spongycastle.jcajce.provider.asymmetric.ecgost12.BCECGOST3410_2012PublicKey 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.ecgost12;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import org.spongycastle.asn1.ASN1Encodable;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.ASN1OctetString;
import org.spongycastle.asn1.ASN1Primitive;
import org.spongycastle.asn1.DERBitString;
import org.spongycastle.asn1.DEROctetString;
import org.spongycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.spongycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.spongycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.spongycastle.asn1.x509.AlgorithmIdentifier;
import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
import org.spongycastle.asn1.x9.X962Parameters;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.params.ECDomainParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
import org.spongycastle.jce.ECGOST3410NamedCurveTable;
import org.spongycastle.jce.interfaces.ECPointEncoder;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.jce.spec.ECNamedCurveParameterSpec;
import org.spongycastle.jce.spec.ECNamedCurveSpec;
import org.spongycastle.math.ec.ECCurve;
/**
* Represent two kind of GOST34.10 2012 PublicKeys: with 256 and 512 size
*/
public class BCECGOST3410_2012PublicKey
implements ECPublicKey, org.spongycastle.jce.interfaces.ECPublicKey, ECPointEncoder
{
static final long serialVersionUID = 7026240464295649314L;
private String algorithm = "ECGOST3410-2012";
private boolean withCompression;
private transient ECPublicKeyParameters ecPublicKey;
private transient ECParameterSpec ecSpec;
private transient GOST3410PublicKeyAlgParameters gostParams;
public BCECGOST3410_2012PublicKey(
BCECGOST3410_2012PublicKey key)
{
this.ecPublicKey = key.ecPublicKey;
this.ecSpec = key.ecSpec;
this.withCompression = key.withCompression;
this.gostParams = key.gostParams;
}
public BCECGOST3410_2012PublicKey(
ECPublicKeySpec spec)
{
this.ecSpec = spec.getParams();
this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, spec.getParams()));
}
public BCECGOST3410_2012PublicKey(
org.spongycastle.jce.spec.ECPublicKeySpec spec,
ProviderConfiguration configuration)
{
if (spec.getParams() != null) // can be null if implictlyCa
{
ECCurve curve = spec.getParams().getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
// this may seem a little long-winded but it's how we pick up the custom curve.
this.ecPublicKey = new ECPublicKeyParameters(
spec.getQ(), ECUtil.getDomainParameters(configuration, spec.getParams()));
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
}
else
{
org.spongycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
this.ecPublicKey = new ECPublicKeyParameters(s.getCurve().createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger()), EC5Util.getDomainParameters(configuration, (ECParameterSpec)null));
this.ecSpec = null;
}
}
public BCECGOST3410_2012PublicKey(
String algorithm,
ECPublicKeyParameters params,
ECParameterSpec spec)
{
ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
this.ecPublicKey = params;
if (spec == null)
{
EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
this.ecSpec = createSpec(ellipticCurve, dp);
}
else
{
this.ecSpec = spec;
}
}
public BCECGOST3410_2012PublicKey(
String algorithm,
ECPublicKeyParameters params,
org.spongycastle.jce.spec.ECParameterSpec spec)
{
ECDomainParameters dp = params.getParameters();
this.algorithm = algorithm;
this.ecPublicKey = params;
if (spec == null)
{
EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
this.ecSpec = createSpec(ellipticCurve, dp);
}
else
{
EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
}
}
/*
* called for implicitCA
*/
public BCECGOST3410_2012PublicKey(
String algorithm,
ECPublicKeyParameters params)
{
this.algorithm = algorithm;
this.ecPublicKey = params;
this.ecSpec = null;
}
private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
{
return new ECParameterSpec(
ellipticCurve,
new ECPoint(
dp.getG().getAffineXCoord().toBigInteger(),
dp.getG().getAffineYCoord().toBigInteger()),
dp.getN(),
dp.getH().intValue());
}
public BCECGOST3410_2012PublicKey(
ECPublicKey key)
{
this.algorithm = key.getAlgorithm();
this.ecSpec = key.getParams();
this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(null, key.getParams()));
}
BCECGOST3410_2012PublicKey(
SubjectPublicKeyInfo info)
{
populateFromPubKeyInfo(info);
}
private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
{
ASN1ObjectIdentifier algOid = info.getAlgorithm().getAlgorithm();
DERBitString bits = info.getPublicKeyData();
ASN1OctetString key;
this.algorithm = "ECGOST3410-2012";
try
{
key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes());
}
catch (IOException ex)
{
throw new IllegalArgumentException("error recovering public key");
}
byte[] keyEnc = key.getOctets();
int keySize = 64;
if (algOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512))
{
keySize = 128;
}
int arraySize = keySize / 2;
byte[] x = new byte[arraySize];
byte[] y = new byte[arraySize];
for (int i = 0; i != x.length; i++)
{
x[i] = keyEnc[arraySize - 1 - i];
}
for (int i = 0; i != y.length; i++)
{
y[i] = keyEnc[keySize - 1 - i];
}
gostParams = GOST3410PublicKeyAlgParameters.getInstance(info.getAlgorithm().getParameters());
ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
ECCurve curve = spec.getCurve();
EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
this.ecPublicKey = new ECPublicKeyParameters(curve.createPoint(new BigInteger(1, x), new BigInteger(1, y)), ECUtil.getDomainParameters(null, spec));
ecSpec = new ECNamedCurveSpec(
ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
ellipticCurve,
new ECPoint(
spec.getG().getAffineXCoord().toBigInteger(),
spec.getG().getAffineYCoord().toBigInteger()),
spec.getN(), spec.getH());
}
public String getAlgorithm()
{
return algorithm;
}
public String getFormat()
{
return "X.509";
}
public byte[] getEncoded()
{
ASN1Encodable params;
SubjectPublicKeyInfo info;
// ecPublicKey.getQ().
BigInteger bX = this.ecPublicKey.getQ().getAffineXCoord().toBigInteger();
BigInteger bY = this.ecPublicKey.getQ().getAffineYCoord().toBigInteger();
// need to detect key size
boolean is512 = (bX.bitLength() > 256);
if (gostParams != null)
{
params = gostParams;
}
else
{
if (ecSpec instanceof ECNamedCurveSpec)
{
if (is512)
{
params = new GOST3410PublicKeyAlgParameters(
ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512);
}
else
{
params = new GOST3410PublicKeyAlgParameters(
ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256);
}
}
else
{ // strictly speaking this may not be applicable...
ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
X9ECParameters ecP = new X9ECParameters(
curve,
EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
ecSpec.getOrder(),
BigInteger.valueOf(ecSpec.getCofactor()),
ecSpec.getCurve().getSeed());
params = new X962Parameters(ecP);
}
}
int encKeySize;
int offset;
ASN1ObjectIdentifier algIdentifier;
if (is512)
{
encKeySize = 128;
offset = 64;
algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512;
}
else
{
encKeySize = 64;
offset = 32;
algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256;
}
byte[] encKey = new byte[encKeySize];
extractBytes(encKey, encKeySize / 2, 0, bX);
extractBytes(encKey, encKeySize / 2, offset, bY);
try
{
info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(algIdentifier, params),
new DEROctetString(encKey));
}
catch (IOException e)
{
return null;
}
return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
}
private void extractBytes(byte[] encKey, int size, int offSet, BigInteger bI)
{
byte[] val = bI.toByteArray();
if (val.length < size)
{
byte[] tmp = new byte[size];
System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
val = tmp;
}
for (int i = 0; i != size; i++)
{
encKey[offSet + i] = val[val.length - 1 - i];
}
}
public ECParameterSpec getParams()
{
return ecSpec;
}
public org.spongycastle.jce.spec.ECParameterSpec getParameters()
{
if (ecSpec == null) // implictlyCA
{
return null;
}
return EC5Util.convertSpec(ecSpec, withCompression);
}
public ECPoint getW()
{
return new ECPoint(ecPublicKey.getQ().getAffineXCoord().toBigInteger(), ecPublicKey.getQ().getAffineYCoord().toBigInteger());
}
public org.spongycastle.math.ec.ECPoint getQ()
{
if (ecSpec == null)
{
return ecPublicKey.getQ().getDetachedPoint();
}
return ecPublicKey.getQ();
}
ECPublicKeyParameters engineGetKeyParameters()
{
return ecPublicKey;
}
org.spongycastle.jce.spec.ECParameterSpec engineGetSpec()
{
if (ecSpec != null)
{
return EC5Util.convertSpec(ecSpec, withCompression);
}
return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
}
public String toString()
{
return ECUtil.publicKeyToString(algorithm, ecPublicKey.getQ(), engineGetSpec());
}
public void setPointFormat(String style)
{
withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
}
public boolean equals(Object o)
{
if (!(o instanceof BCECGOST3410_2012PublicKey))
{
return false;
}
BCECGOST3410_2012PublicKey other = (BCECGOST3410_2012PublicKey)o;
return ecPublicKey.getQ().equals(other.ecPublicKey.getQ()) && (engineGetSpec().equals(other.engineGetSpec()));
}
public int hashCode()
{
return ecPublicKey.getQ().hashCode() ^ engineGetSpec().hashCode();
}
private void readObject(
ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
byte[] enc = (byte[])in.readObject();
populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
}
private void writeObject(
ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
out.writeObject(this.getEncoded());
}
public GOST3410PublicKeyAlgParameters getGostParams()
{
return gostParams;
}
}