Java 中的椭圆曲线私钥长度
Elliptic Curve Private Key Length in Java
我使用“secp256r1”曲线创建了一个 EC 密钥对。它是 256 位的曲线,私钥应该是 256 位(32 字节)。但我得到的是 39 字节的私钥。这是我的代码
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); //Provider is SunEC version 1.8
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecSpec, new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
ASN1Sequence sequence = DERSequence.getInstance(privateKey.getEncoded());
DEROctetString subjectPrivateKey = (DEROctetString) sequence.getObjectAt(2);
byte[] privateKeyBytes = subjectPrivateKey.getOctets();
System.out.println("PrivateKeyBytes.length: " + privateKeyBytes.length); // Expected length is 32, but actual is 39
我正在使用 JDK 1.8.0_144 和 BouncyCastle 库。
这里是pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>pki</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-debug-jdk15on</artifactId>
<version>1.65</version>
</dependency>
</dependencies>
</project>
如何获取32字节的私钥?
PKCS8 的 algorithm-dependent 部分,位于序列的元素 #2,因为 EC 本身是 SEC1 structure ECPrivateKey, also documented at rfc5915 的 DER 编码。对于 SunEC,这是一个包含实际私钥字节的 INTEGER 版本和 OCTETSTRING 的序列;省略了可选的 context-0 参数和 context-1 公钥。所以你需要解析:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC",args[0]);
kpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
byte[] pkcs8 = privateKey.getEncoded();
// slightly reorganized
DEROctetString wrapped = (DEROctetString) DERSequence.getInstance(pkcs8).getObjectAt(2);
System.out.println (wrapped.getOctets().length);
// added
DEROctetString raw = (DEROctetString) DERSequence.getInstance( wrapped.getOctets() ).getObjectAt(1);
System.out.println (raw.getOctets().length);
由于您使用的是 BouncyCastle,因此您可以使用 BouncyCastle class for org.bouncycastle.asn1.pkcs.PrivateKeyInfo
:
而不是手动解析 PKCS8
PrivateKeyInfo info = PrivateKeyInfo.getInstance (DERSequence.getInstance(pkcs8));
DEROctetString raw2 = (DEROctetString)( DERSequence.getInstance(info.parsePrivateKey()) ).getObjectAt(1);
System.out.println (raw2.getOctets().length);
最后,您可以直接从 ECPrivateKey
对象中获取私钥值作为 BigInteger
值,而不是通过编码,它可以转换为字节数组,尽管它是可变长度而不是通常用于 EC 私钥的固定长度,因此您可能需要调整它:
byte[] bytes = ((ECPrivateKey)privateKey).getS().toByteArray();
System.out.println(bytes.length);
// may need left-trim or pad with zero(s)
我使用“secp256r1”曲线创建了一个 EC 密钥对。它是 256 位的曲线,私钥应该是 256 位(32 字节)。但我得到的是 39 字节的私钥。这是我的代码
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); //Provider is SunEC version 1.8
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
kpg.initialize(ecSpec, new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
ASN1Sequence sequence = DERSequence.getInstance(privateKey.getEncoded());
DEROctetString subjectPrivateKey = (DEROctetString) sequence.getObjectAt(2);
byte[] privateKeyBytes = subjectPrivateKey.getOctets();
System.out.println("PrivateKeyBytes.length: " + privateKeyBytes.length); // Expected length is 32, but actual is 39
我正在使用 JDK 1.8.0_144 和 BouncyCastle 库。 这里是pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>pki</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-debug-jdk15on</artifactId>
<version>1.65</version>
</dependency>
</dependencies>
</project>
如何获取32字节的私钥?
PKCS8 的 algorithm-dependent 部分,位于序列的元素 #2,因为 EC 本身是 SEC1 structure ECPrivateKey, also documented at rfc5915 的 DER 编码。对于 SunEC,这是一个包含实际私钥字节的 INTEGER 版本和 OCTETSTRING 的序列;省略了可选的 context-0 参数和 context-1 公钥。所以你需要解析:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC",args[0]);
kpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
KeyPair ecKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = ecKeyPair.getPrivate();
byte[] pkcs8 = privateKey.getEncoded();
// slightly reorganized
DEROctetString wrapped = (DEROctetString) DERSequence.getInstance(pkcs8).getObjectAt(2);
System.out.println (wrapped.getOctets().length);
// added
DEROctetString raw = (DEROctetString) DERSequence.getInstance( wrapped.getOctets() ).getObjectAt(1);
System.out.println (raw.getOctets().length);
由于您使用的是 BouncyCastle,因此您可以使用 BouncyCastle class for org.bouncycastle.asn1.pkcs.PrivateKeyInfo
:
PrivateKeyInfo info = PrivateKeyInfo.getInstance (DERSequence.getInstance(pkcs8));
DEROctetString raw2 = (DEROctetString)( DERSequence.getInstance(info.parsePrivateKey()) ).getObjectAt(1);
System.out.println (raw2.getOctets().length);
最后,您可以直接从 ECPrivateKey
对象中获取私钥值作为 BigInteger
值,而不是通过编码,它可以转换为字节数组,尽管它是可变长度而不是通常用于 EC 私钥的固定长度,因此您可能需要调整它:
byte[] bytes = ((ECPrivateKey)privateKey).getS().toByteArray();
System.out.println(bytes.length);
// may need left-trim or pad with zero(s)