从 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 的实现 ECPrivateKey
和 ECPublicKey
确定。使用 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
) 中指出了 ECPublicKey
和 ECPrivateKey
的内置 Java 实现。这里私钥和public对应的方法分别是getS()
和getW()
。
在 x 或 y 小于 32 字节的情况下,此实现不会自动填充前导 0x00 值,因此必须手动完成。因此,BouncyCastle 方法对您来说可能更方便,也因为您已经使用了 BouncyCastle。
我正在使用 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 的实现 ECPrivateKey
和 ECPublicKey
确定。使用 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
) 中指出了 ECPublicKey
和 ECPrivateKey
的内置 Java 实现。这里私钥和public对应的方法分别是getS()
和getW()
。
在 x 或 y 小于 32 字节的情况下,此实现不会自动填充前导 0x00 值,因此必须手动完成。因此,BouncyCastle 方法对您来说可能更方便,也因为您已经使用了 BouncyCastle。