【问题标题】:Codes to generate a public key in an elliptic curve algorithm using a given private key使用给定私钥在椭圆曲线算法中生成公钥的代码
【发布时间】:2013-11-09 12:53:34
【问题描述】:

我需要使用 jdk 1.7 实现 ECC(椭圆曲线密码术)算法。我尝试使用充气城堡、sunEC,但它们都给出了错误和错误。我的目标是用私钥生成一条椭圆曲线,我会交给系统。

因此,我需要使用 jdk1.7 获取使用给定私钥生成公钥的准确代码。我使用的 IDE 是 ecllipse。而且我需要知道,除了私钥之外,我还应该提供哪些其他参数?只提供一个曲线点和私钥就够了吗?

有人可以帮我从私钥生成公钥吗?我可以管理其余的实施。

谁知道用java实现椭圆曲线密码学的密钥,请告诉我这段代码是否正确?

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);

}

谢谢!

【问题讨论】:

  • 最近用 java 做 bouncycastle。 See my recent question's matched to your exception.。是的,有很多异常,一一解决。发布您遇到的异常。肯定有人会帮忙的。
  • 您自动生成了两个密钥。但我需要使用给定/特定的私钥生成公钥。
  • 从您的问题来看,您似乎不是密码学专家。所以你可能不应该做你正在尝试的事情。否则,您尝试实现哪种算法?从私钥中获取公钥在某些算法中只是椭圆曲线群中的乘法问题。
  • 请不要说不,我开始工作了,要继续我需要生成公钥。我不能使用充气城堡为我的私钥获得一个加工椭圆曲线吗?
  • Please please PLEASE don't try to roll your own crypto solution。这是非常危险的 - 我建议您先进行广泛的尝试来解决您在使用库时遇到的问题。

标签: java bouncycastle elliptic-curve


【解决方案1】:

我编写了一个示例程序,输出如下:

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$

代码应该足够清晰,这样你就可以理解这里做了什么。请注意,您确实必须知道您的私钥是为哪条曲线生成的,否则无法生成匹配的公钥。示例代码使用了secp256r1曲线,比较常用。

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】:

    我使用此方法从 ECPrivateKey 中恢复 ECPublicKey。 最后,主要例程证明它有效。很简单 没有任何外部库的java。

    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));
    }
    

    }

    【讨论】:

    • FieldP._2 是什么?
    • FieldP._2 只不过是一个值为 2 的 BigInteger。
    【解决方案3】:

    对Generate ECPublicKey from ECPrivateKey 上的@markw 的答案进行了一些改进,并通过@bas-goossen 从这里扩展了曲线名称检测: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;
    }
    

    【讨论】:

      【解决方案4】:

      这是对@SkateScout 答案的改进。我在另一个上下文中使用了标量例程,在 SO (Derive EC public key from private key string in native Java for curve secp256k1) 上发布了它们,并得到了@President James Moveon Polk 的“错误”评论:

      "该代码不正确,您从中获取的代码也是如此。这一行 BigInteger k = kin.mod(p); 是错误的,错误的,错误的。标量倍数应该取 mod 的顺序该组,这不是定义该字段的素数。您没有被该错误咬伤的唯一原因是因为您从未使用> = p的亲属对其进行测试。这就是您不进行加密的原因手动。但无论如何,您的问题的答案是否定的。如果您只使用 Java 8(或者可能是 7),您可以找到一个内部 sun。 执行标量乘法的类和方法,但不能超出此范围。 * "

      我稍微修改了源代码,这是最终代码(完整示例):

      import org.bouncycastle.jce.ECNamedCurveTable;
      import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
      import java.math.BigInteger;
      import java.security.GeneralSecurityException;
      import java.security.KeyFactory;
      import java.security.PrivateKey;
      import java.security.interfaces.ECPrivateKey;
      import java.security.interfaces.ECPublicKey;
      import java.security.spec.*;
      
      public class DerivePublicKeyFromPrivateKeyCurveSecp256k1Final {
          // sourcecode available https://github.com/java-crypto/Stackoverflow/tree/master/DervicePublicKeyFromPrivateKeyCurveSecp256k1
          // get bouncycastle here: https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on/1.65
          // tested with version 15 1.65
          // java open jdk 11.0.5
          final static BigInteger FieldP_2 = BigInteger.TWO; // constant for scalar operations
          final static BigInteger FieldP_3 = BigInteger.valueOf(3); // constant for scalar operations
      
          public static void main(String[] args) throws GeneralSecurityException {
              System.out.println("Generate ECPublicKey from PrivateKey (String) for curve secp256k1 (final)");
              System.out.println("Check keys with https://gobittest.appspot.com/Address");
              // https://gobittest.appspot.com/Address
              String privateKey = "D12D2FACA9AD92828D89683778CB8DFCCDBD6C9E92F6AB7D6065E8AACC1FF6D6";
              String publicKeyExpected = "04661BA57FED0D115222E30FE7E9509325EE30E7E284D3641E6FB5E67368C2DB185ADA8EFC5DC43AF6BF474A41ED6237573DC4ED693D49102C42FFC88510500799";
              System.out.println("\nprivatekey given : " + privateKey);
              System.out.println("publicKeyExpected: " + publicKeyExpected);
              // routine with bouncy castle
              System.out.println("\nGenerate PublicKey from PrivateKey with BouncyCastle");
              ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256k1"); // this ec curve is used for bitcoin operations
              org.bouncycastle.math.ec.ECPoint pointQ = spec.getG().multiply(new BigInteger(1, hexStringToByteArray(privateKey)));
              byte[] publickKeyByte = pointQ.getEncoded(false);
              String publicKeyBc = byteArrayToHexString(publickKeyByte);
              System.out.println("publicKeyExpected: " + publicKeyExpected);
              System.out.println("publicKey BC     : " + publicKeyBc);
              System.out.println("publicKeys match : " + publicKeyBc.contentEquals(publicKeyExpected));
      
              // regeneration of ECPublicKey with java native starts here
              System.out.println("\nGenerate PublicKey from PrivateKey with Java native routines");
              // the preset "303E.." only works for elliptic curve secp256k1
              // see answer by user dave_thompson_085
              // https://stackoverflow.com/questions/48832170/generate-ec-public-key-from-byte-array-private-key-in-native-java-7
              String privateKeyFull = "303E020100301006072A8648CE3D020106052B8104000A042730250201010420" +
                      privateKey;
              byte[] privateKeyFullByte = hexStringToByteArray(privateKeyFull);
              System.out.println("privateKey full  : " + privateKeyFull);
              KeyFactory keyFactory = KeyFactory.getInstance("EC");
              PrivateKey privateKeyNative = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyFullByte));
              ECPrivateKey ecPrivateKeyNative = (ECPrivateKey) privateKeyNative;
              ECPublicKey ecPublicKeyNative = getPublicKey(ecPrivateKeyNative);
              byte[] ecPublicKeyNativeByte = ecPublicKeyNative.getEncoded();
              String publicKeyNativeFull = byteArrayToHexString(ecPublicKeyNativeByte);
              String publicKeyNativeHeader = publicKeyNativeFull.substring(0, 46);
              String publicKeyNativeKey = publicKeyNativeFull.substring(46, 176);
              System.out.println("ecPublicKeyFull  : " + publicKeyNativeFull);
              System.out.println("ecPublicKeyHeader: " + publicKeyNativeHeader);
              System.out.println("ecPublicKeyKey   : " + publicKeyNativeKey);
              System.out.println("publicKeyExpected: " + publicKeyExpected);
              System.out.println("publicKeys match : " + publicKeyNativeKey.contentEquals(publicKeyExpected));
          }
      
          private static String byteArrayToHexString(byte[] a) {
              StringBuilder sb = new StringBuilder(a.length * 2);
              for (byte b : a)
                  sb.append(String.format("%02X", b));
              return sb.toString();
          }
      
          public static byte[] hexStringToByteArray(String s) {
              int len = s.length();
              byte[] data = new byte[len / 2];
              for (int i = 0; i < len; i += 2) {
                  data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                          + Character.digit(s.charAt(i + 1), 16));
              }
              return data;
          }
      
          // scalar operations for native java
          // see https://stackoverflow.com/a/42797410/8166854
          // written by author: SkateScout
          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 scalmultNew(final ECParameterSpec params, final ECPoint g, final BigInteger kin) {
              EllipticCurve curve = params.getCurve();
              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;
              // value only valid for curve secp256k1, code taken from https://www.secg.org/sec2-v2.pdf,
              // see "Finally the order n of G and the cofactor are: n = "FF.."
              BigInteger SECP256K1_Q = params.getOrder();
              //BigInteger SECP256K1_Q = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16);
              BigInteger k = kin.mod(SECP256K1_Q); // uses this !
              // BigInteger k = kin.mod(p); // do not use this ! wrong as per comment from President James Moveon Polk
              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 ECPoint scalmultOrg(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;
              // value only valid for curve secp256k1, code taken from https://www.secg.org/sec2-v2.pdf,
              // see "Finally the order n of G and the cofactor are: n = "FF.."
              BigInteger SECP256K1_Q = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",16);
              BigInteger k = kin.mod(SECP256K1_Q); // uses this !
              // wrong as per comment from President James Moveon Polk
              // BigInteger k = kin.mod(p); // do not use this !
              System.out.println(" SECP256K1_Q: " + SECP256K1_Q);
              System.out.println("           p: " + p);
              System.out.println("curve: " + curve.toString());
              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 = scalmultNew(params, pk.getParams().getGenerator(), pk.getS());
              //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));
          }
      }
      

      享受吧!

      【讨论】:

        猜你喜欢
        • 2016-07-19
        • 2020-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-04
        • 2021-08-02
        • 2015-08-18
        • 2023-03-19
        相关资源
        最近更新 更多