从 Bouncy Castle 获取原始密钥 Java

Get raw keys from Bouncy Castle Java

我正在使用 ECDSA 的 C 和 Java 实现。 C 实现使用原始格式 - 32 字节私钥、64 字节 public 密钥、64 字节签名。

我正在使用 Bouncy Castle 在 Java 中创建密钥:

    public static KeyPair GenerateKeys() throws NoSuchAlgorithmException,
        NoSuchProviderException, InvalidAlgorithmParameterException {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
        KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");

        g.initialize(ecSpec, new SecureRandom());

        return g.generateKeyPair();
    }

并希望将它们存储为字节数组,因为稍后我需要将它们导出到我的 C 应用程序。我注意到:

        KeyPair vendorKeys = GenerateKeys();
        for (byte byt : vendorKeys.getPublic().getEncoded()) {
            System.out.println("byt: " +  byt);
        }

将 return 字节的 Public 密钥,但长度错误。我想这与 PublicKey 的 X.509 和 private 的 PKCS#8 格式有关。在寻求帮助时,我发现 Java 中有一些 类,例如 PKCS8EncodedKeySpec,这应该可以帮助我获得原始密钥,但无法弄清楚如何去做。

私钥或 public 密钥的 x 和 y 坐标可以通过 BouncyCastle 的实现 ECPrivateKeyECPublicKey 确定。使用 getD() 可以确定私有密钥,使用 getQ() 可以确定 public 密钥,例如:

import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
...
ECPublicKey publickKey = (ECPublicKey)vendorKeys.getPublic();
ECPrivateKey privateKey = (ECPrivateKey)vendorKeys.getPrivate();
byte[] rawPrivate = BigIntegers.asUnsignedByteArray(privateKey.getD());
byte[] x = publickKey.getQ().getAffineXCoord().getEncoded();
byte[] y = publickKey.getQ().getAffineYCoord().getEncoded();        
byte[] rawPublic = ByteBuffer.allocate(x.length + y.length).put(x).put(y).array();

System.out.println(Hex.toHexString(rawPrivate));
System.out.println(Hex.toHexString(rawPublic));

此处 secp256r1 的 public 密钥的长度始终为 64 字节。私钥大小为 32 字节,但也可以更小。


dave_thompson_085 在他的评论 (java.security.interfaces) 中指出了 ECPublicKeyECPrivateKey 的内置 Java 实现。这里私钥和public对应的方法分别是getS()getW()
在 x 或 y 小于 32 字节的情况下,此实现不会自动填充前导 0x00 值,因此必须手动完成。因此,BouncyCastle 方法对您来说可能更方便,也因为您已经使用了 BouncyCastle。