如何从Java Bouncy Castle库提取ECDSA原始公私钥适配C端原生格式
ECDSA secp256r1 原始密钥导出方案(适配C端32/64字节格式)
你之前的推测完全正确,默认JCE的PublicKey.getEncoded()输出为带元数据的X.509 SubjectPublicKeyInfo封装格式,PrivateKey.getEncoded()为带元数据的PKCS#8封装格式,需要提取原始椭圆曲线参数得到裸密钥,具体实现如下:
工具方法(处理BigInteger转固定长度字节数组)
解决BigInteger自带符号位、输出长度不固定的问题:
// 把BigInteger转换为指定长度的无符号大端字节数组,自动补前导0或裁剪多余符号位 private static byte[] toUnsignedFixedLengthByteArray(BigInteger bi, int length) { byte[] array = bi.toByteArray(); if (array.length == length) { return array; } // 去掉多余的符号位前缀0 if (array.length == length + 1 && array[0] == 0) { byte[] trimmed = new byte[length]; System.arraycopy(array, 1, trimmed, 0, length); return trimmed; } // 长度不足时补前导0 if (array.length < length) { byte[] padded = new byte[length]; System.arraycopy(array, 0, padded, length - array.length, array.length); return padded; } throw new IllegalArgumentException("BigInteger长度超出预期的" + length + "字节"); }
原始公钥导出方法
输出64字节原始公钥,结构为32字节X坐标 + 32字节Y坐标,完全匹配C端格式要求:
public static byte[] getRawECPublicKey(PublicKey publicKey) { ECPublicKey ecPublicKey = (ECPublicKey) publicKey; ECPoint point = ecPublicKey.getW(); byte[] x = toUnsignedFixedLengthByteArray(point.getAffineX(), 32); byte[] y = toUnsignedFixedLengthByteArray(point.getAffineY(), 32); byte[] rawPub = new byte[64]; System.arraycopy(x, 0, rawPub, 0, 32); System.arraycopy(y, 0, rawPub, 32, 32); return rawPub; }
原始私钥导出方法
输出32字节原始私钥,对应EC参数中的S值:
public static byte[] getRawECPrivateKey(PrivateKey privateKey) { ECPrivateKey ecPrivateKey = (ECPrivateKey) privateKey; return toUnsignedFixedLengthByteArray(ecPrivateKey.getS(), 32); }
使用示例
public static void main(String[] args) throws Exception { KeyPair vendorKeys = GenerateKeys(); byte[] rawPublicKey = getRawECPublicKey(vendorKeys.getPublic()); byte[] rawPrivateKey = getRawECPrivateKey(vendorKeys.getPrivate()); System.out.println("原始公钥长度:" + rawPublicKey.length); // 输出64 System.out.println("原始私钥长度:" + rawPrivateKey.length); // 输出32 }
内容的提问来源于stack exchange,提问作者Michał
相关产品推荐
相关产品推荐

