美文网首页
Java加载原始的64字节长的ECDSA公钥到ECPublicK

Java加载原始的64字节长的ECDSA公钥到ECPublicK

作者: 小蜗牛爬楼梯 | 来源:发表于2020-01-10 17:32 被阅读0次

先解释一下,HyperLedger 超级账本的公私钥组成,私钥随机生成,然后私钥通过secp256r1算法推导公钥。
java 8以后版本中,包含关于EC公钥的实现。
原始十六进制公钥是由 前缀 04 + public.x + public.y组成,大小是65,不加04是64字节。顺便提一下,私钥长度是32字节。
取得x 和y数组的办法如下:

  ECPublicKey ecPublicKey = (ECPublicKey) publicKey;

  // Get x coordinate
  byte[] x = ecPublicKey.getW().getAffineX().toByteArray();
  if (x[0] == 0)
    x = Arrays.copyOfRange(x, 1, x.length);
  // Get Y coordinate
  byte[] y = ecPublicKey.getW().getAffineY().toByteArray();
  if (y[0] == 0)
    y = Arrays.copyOfRange(y, 1, y.length);

Java 7 is required for the EC functionality and Java 8 for the Base 64 encoder / decoder, no additional libraries - just plain Java. Note that this will actually display the public key as a named curve when printed out, something most other solutions won't do. If you have an up-to-date runtime, this other answer is more clean.

This answer is going to be tough if we do this using ECPublicKeySpec. So lets cheat a bit and use X509EncodedKeySpec instead:

private static byte[] P256_HEAD = Base64.getDecoder().decode("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE");

/**
 * Converts an uncompressed secp256r1 / P-256 public point to the EC public key it is representing.
 * @param w a 64 byte uncompressed EC point consisting of just a 256-bit X and Y
 * @return an <code>ECPublicKey</code> that the point represents 
 */
public static ECPublicKey generateP256PublicKeyFromFlatW(byte[] w) throws InvalidKeySpecException {
    byte[] encodedKey = new byte[P256_HEAD.length + w.length];
    System.arraycopy(P256_HEAD, 0, encodedKey, 0, P256_HEAD.length);
    System.arraycopy(w, 0, encodedKey, P256_HEAD.length, w.length);
    KeyFactory eckf;
    try {
        eckf = KeyFactory.getInstance("EC");
    } catch (NoSuchAlgorithmException e) {
        throw new IllegalStateException("EC key factory not present in runtime");
    }
    X509EncodedKeySpec ecpks = new X509EncodedKeySpec(encodedKey);
    return (ECPublicKey) eckf.generatePublic(ecpks);
}

Usage:

ECPublicKey key = generateP256PublicKeyFromFlatW(w);
System.out.println(key);

The idea behind this is to create a temporary X509 encoded key, which happily ends with the public point w at the end. The bytes before that contain the ASN.1 DER encoding of the OID of the named curve and structural overhead, ending with byte 04 indicating an uncompressed point. Here is an example what the structure looks like, using value 1 and 2 for the 32-byte X and Y.

The 32-byte X and Y values of the uncompressed point values removed to create the header. This only works because the point is statically sized - it's location at the end is only determined by the size of the curve.

Now all that is required in the function generateP256PublicKeyFromFlatW is to add the received public point w to the header and run it through the decoder implemented for X509EncodedKeySpec.


The above code uses a raw, uncompressed public EC point - just a 32 byte X and Y - without the uncompressed point indicator with value 04. Of course it is easy to support 65 byte compressed points as well:

/**
 * Converts an uncompressed secp256r1 / P-256 public point to the EC public key it is representing.
 * @param w a 64 byte uncompressed EC point starting with <code>04</code>
 * @return an <code>ECPublicKey</code> that the point represents 
 */
public static ECPublicKey generateP256PublicKeyFromUncompressedW(byte[] w) throws InvalidKeySpecException {
    if (w[0] != 0x04) {
        throw new InvalidKeySpecException("w is not an uncompressed key");
    }
    return generateP256PublicKeyFromFlatW(Arrays.copyOfRange(w, 1, w.length));
}

Finally, I generated the constant P256_HEAD head value in base 64 using:

private static byte[] createHeadForNamedCurve(String name, int size)
        throws NoSuchAlgorithmException,
        InvalidAlgorithmParameterException, IOException {
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
    ECGenParameterSpec m = new ECGenParameterSpec(name);
    kpg.initialize(m);
    KeyPair kp = kpg.generateKeyPair();
    byte[] encoded = kp.getPublic().getEncoded();
    return Arrays.copyOf(encoded, encoded.length - 2 * (size / Byte.SIZE));
}

called by:

String name = "NIST P-256";
int size = 256;
byte[] head = createHeadForNamedCurve(name, size);
System.out.println(Base64.getEncoder().encodeToString(head));

相关文章

  • Java加载原始的64字节长的ECDSA公钥到ECPublicK

    先解释一下,HyperLedger 超级账本的公私钥组成,私钥随机生成,然后私钥通过secp256r1算法推导公钥...

  • ECC/SM2 公钥(点)压缩与还原

    ECC/SM2 公钥(点)压缩方法,64字节公钥压缩成33字节公钥。 一、C 二、Java Java基于bcpro...

  • https免费证书申请

    证书有两种,一种是 ECC 证书(内置公钥是 ECDSA 公钥),一种是 RSA 证书(内置 RSA 公钥)。简单...

  • 公钥-指纹(public key fingerprint)

    在公钥密码学中,公钥指纹(public key fingerprint)是一小段字节(bytes),用来是被一个长...

  • 地址

    非对称加密:公钥与私钥,比特币使用了ecdsa算法用来生成公钥和私钥 生成过程: 1,产生一个256byte的随机...

  • bip-0032 HD钱包

    原文地址 大概看了一下,产生了一个疑问: 公钥是由私钥经过ECDSA算法生成的, 在HD钱包中, 可以由父公钥生成...

  • [Knowledge]_[apk signature签名]

    signature significance签名的意义[2] 防篡改 公钥与私钥[1] 公钥加密使用公钥加密原始数...

  • 以太坊之账户

    一、外部账户 外部账户创建流程: 创建随机私钥(64位16进制字符/32字节): ecdsa.GenerateKe...

  • 加解密过程遇到的问题及解决方法

    私钥公钥格式 常见的加解密 导入jar包:javabase64-1.3.1.jar 生成base64编码后的公钥和...

  • Java并发机制的底层原理

    Java程序执行:Java代码→Java字节码→字节码被类加载器加载到JVM里,JVM执行字节码→转化为汇编指令在...

网友评论

      本文标题:Java加载原始的64字节长的ECDSA公钥到ECPublicK

      本文链接:https://www.haomeiwen.com/subject/ttrmactx.html