问题
I need to implement ECC (Elliptic Curve Cryptography) algorithm using jdk 1.7. I tried using bouncy castle, sunEC, but all of them gave errors and errors. My target is to generate an elliptic curve using the private key, I will be given to the system.
Thus, I need to get a accurate code to generate a public key using a given private key using jdk1.7. The IDE I use is ecllipse. And I need to know, what are the other parameters I should be given other than a private key? Is it enough to provide just a curve point and the private key?
Can someone help me to generate public key from private key?? I can manage the rest of my implementation.
Anyone who knows to implement keys of Elliptic Curve Cryptography using java, please tell me whether this code is correct?
public class ECCrypt {
private ECPoint curve_point;
public ECCrypt(ECPoint curve_point) {
this.curve_point = curve_point;
}
public BigInteger makePublicKey(BigInteger privateKey) {
ECPoint ecPublicKey = new ECPoint(curve_point);
ecPublicKey.mult(privateKey);
return ecPublicKey.pack();
}
public static void main(String[] argv) throws Exception {
java.util.Random rnd = new java.util.Random();
ECPoint cp = new ECPoint();
cp.random(rnd);
ECCrypt ec = new ECCrypt(cp);
BigInteger priv = new BigInteger(255,rnd);
BigInteger pub = ec.makePublicKey(priv);
}
Thanks!
回答1:
I wrote a sample program that outputs the following:
FL261:java jvah$ javac -cp bcprov-ext-jdk15on-149.jar ECTest.java
FL261:java jvah$ java -cp bcprov-ext-jdk15on-149.jar:. ECTest
Private key: 7ba78909571fbc336b2b94054dfb745a6b0776ff36a8fa98a598dc32cb83cc8e
Public key: 035b9e4a6148c9f9b08b573871ac66a832e6e9f63cf117545523a45b8017b7c43f
Calculated public key: 035b9e4a6148c9f9b08b573871ac66a832e6e9f63cf117545523a45b8017b7c43f
Congratulations, public keys match!
FL261:java jvah$
The code should be clear enough so that you can understand what is done here. Please note that you really have to know which curve your private key is generated for, otherwise it is impossible to generate the matching public key. The sample code uses secp256r1
curve, which is quite commonly used.
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.math.ec.ECPoint;
class ECTest {
public static String toHex(byte[] data) {
StringBuilder sb = new StringBuilder();
for (byte b: data) {
sb.append(String.format("%02x", b&0xff));
}
return sb.toString();
}
public static void main(String[] argv) {
// Get domain parameters for example curve secp256r1
X9ECParameters ecp = SECNamedCurves.getByName("secp256r1");
ECDomainParameters domainParams = new ECDomainParameters(ecp.getCurve(),
ecp.getG(), ecp.getN(), ecp.getH(),
ecp.getSeed());
// Generate a private key and a public key
AsymmetricCipherKeyPair keyPair;
ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(domainParams, new SecureRandom());
ECKeyPairGenerator generator = new ECKeyPairGenerator();
generator.init(keyGenParams);
keyPair = generator.generateKeyPair();
ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getD().toByteArray();
// First print our generated private key and public key
System.out.println("Private key: " + toHex(privateKeyBytes));
System.out.println("Public key: " + toHex(publicKey.getQ().getEncoded(true)));
// Then calculate the public key only using domainParams.getG() and private key
ECPoint Q = domainParams.getG().multiply(new BigInteger(privateKeyBytes));
System.out.println("Calculated public key: " + toHex(Q.getEncoded(true)));
// The calculated public key and generated public key should always match
if (!toHex(publicKey.getQ().getEncoded(true)).equals(toHex(Q.getEncoded(true)))) {
System.out.println("ERROR: Public keys do not match!");
} else {
System.out.println("Congratulations, public keys match!");
}
}
}
回答2:
i use this method to recover ECPublicKey from ECPrivateKey. At the end the main Routine prove that it works. It is plain java without any external library.
public final class MULT {
private static ECPoint doublePoint(final BigInteger p, final BigInteger a, final ECPoint R) {
if (R.equals(ECPoint.POINT_INFINITY)) return R;
BigInteger slope = (R.getAffineX().pow(2)).multiply(FieldP._3);
slope = slope.add(a);
slope = slope.multiply((R.getAffineY().multiply(FieldP._2)).modInverse(p));
final BigInteger Xout = slope.pow(2).subtract(R.getAffineX().multiply(FieldP._2)).mod(p);
final BigInteger Yout = (R.getAffineY().negate()).add(slope.multiply(R.getAffineX().subtract(Xout))).mod(p);
return new ECPoint(Xout, Yout);
}
private static ECPoint addPoint (final BigInteger p, final BigInteger a, final ECPoint r, final ECPoint g) {
if (r.equals(ECPoint.POINT_INFINITY)) return g;
if (g.equals(ECPoint.POINT_INFINITY)) return r;
if (r==g || r.equals(g)) return doublePoint(p, a, r);
final BigInteger gX = g.getAffineX();
final BigInteger sY = g.getAffineY();
final BigInteger rX = r.getAffineX();
final BigInteger rY = r.getAffineY();
final BigInteger slope = (rY.subtract(sY)).multiply(rX.subtract(gX).modInverse(p)).mod(p);
final BigInteger Xout = (slope.modPow(FieldP._2, p).subtract(rX)).subtract(gX).mod(p);
BigInteger Yout = sY.negate().mod(p);
Yout = Yout.add(slope.multiply(gX.subtract(Xout))).mod(p);
return new ECPoint(Xout, Yout);
}
public static ECPoint scalmult (final EllipticCurve curve, final ECPoint g, final BigInteger kin) {
final ECField field = curve.getField();
if(!(field instanceof ECFieldFp)) throw new UnsupportedOperationException(field.getClass().getCanonicalName());
final BigInteger p = ((ECFieldFp)field).getP();
final BigInteger a = curve.getA();
ECPoint R = ECPoint.POINT_INFINITY;
BigInteger k = kin.mod(p);
final int length = k.bitLength();
final byte[] binarray = new byte[length];
for(int i=0;i<=length-1;i++){
binarray[i] = k.mod(FieldP._2).byteValue();
k = k.shiftRight(1);
}
for(int i = length-1;i >= 0;i--){
R = doublePoint(p, a, R);
if(binarray[i]== 1) R = addPoint(p, a, R, g);
}
return R;
}
public static ECPublicKey getPublicKey(final ECPrivateKey pk) throws GeneralSecurityException {
final ECParameterSpec params = pk.getParams();
final ECPoint w = scalmult(params.getCurve(), pk.getParams().getGenerator(), pk.getS());
final KeyFactory kg = KeyFactory.getInstance("EC");
return (ECPublicKey)kg.generatePublic (new ECPublicKeySpec (w, params));
}
}
回答3:
Some more improvement to the answer of @markw on Generate ECPublicKey from ECPrivateKey, extended with curve name detection by @bas-goossen from here: How to find the matching curve name from an ECPublicKey
public static ECPublicKey publicFromPrivate(final ECPrivateKey privateKey) throws Exception {
ECParameterSpec params = privateKey.getParams();
org.bouncycastle.jce.spec.ECParameterSpec bcSpec = org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util
.convertSpec(params, false);
org.bouncycastle.math.ec.ECPoint q = bcSpec.getG().multiply(privateKey.getS());
org.bouncycastle.math.ec.ECPoint bcW = bcSpec.getCurve().decodePoint(q.getEncoded(false));
ECPoint w = new ECPoint(
bcW.getAffineXCoord().toBigInteger(),
bcW.getAffineYCoord().toBigInteger());
ECPublicKeySpec keySpec = new ECPublicKeySpec(w, tryFindNamedCurveSpec(params));
return (ECPublicKey) KeyFactory
.getInstance("EC", org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME)
.generatePublic(keySpec);
}
@SuppressWarnings("unchecked")
public static ECParameterSpec tryFindNamedCurveSpec(ECParameterSpec params) {
org.bouncycastle.jce.spec.ECParameterSpec bcSpec
= org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util.convertSpec(params, false);
for (Object name : Collections.list(org.bouncycastle.jce.ECNamedCurveTable.getNames())) {
org.bouncycastle.jce.spec.ECNamedCurveParameterSpec bcNamedSpec
= org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec((String) name);
if (bcNamedSpec.getN().equals(bcSpec.getN())
&& bcNamedSpec.getH().equals(bcSpec.getH())
&& bcNamedSpec.getCurve().equals(bcSpec.getCurve())
&& bcNamedSpec.getG().equals(bcSpec.getG())) {
return new org.bouncycastle.jce.spec.ECNamedCurveSpec(
bcNamedSpec.getName(),
bcNamedSpec.getCurve(),
bcNamedSpec.getG(),
bcNamedSpec.getN(),
bcNamedSpec.getH(),
bcNamedSpec.getSeed());
}
}
return params;
}
来源:https://stackoverflow.com/questions/19673962/codes-to-generate-a-public-key-in-an-elliptic-curve-algorithm-using-a-given-priv