椭圆曲线私钥长度在Java中

huangapple go评论81阅读模式
英文:

Elliptic Curve Private Key Length in Java

问题

我使用"secp256r1"曲线创建了一个EC密钥对。这是一个256位的曲线,私钥应该是256位(32字节)。但我得到的是39字节的私钥。以下是我的代码:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); //提供者是SunEC版本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); // 期望长度为32,但实际为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字节的私钥?

英文:

I created a EC key pair using "secp256r1" curve. It is 256-bit curve and private key should be 256 bits (32 bytes). But what I'm getting is 39 bytes private key. Here is my code

 KeyPairGenerator kpg = KeyPairGenerator.getInstance(&quot;EC&quot;); //Provider is SunEC version 1.8
 ECGenParameterSpec ecSpec = new ECGenParameterSpec(&quot;secp256r1&quot;);
 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(&quot;PrivateKeyBytes.length: &quot; + privateKeyBytes.length); // Expected length is 32, but actual is 39 

I'm using JDK 1.8.0_144 and BouncyCastle library.
Here is pom.xml

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
         xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;com.example&lt;/groupId&gt;
    &lt;artifactId&gt;pki&lt;/artifactId&gt;
    &lt;version&gt;1.0-SNAPSHOT&lt;/version&gt;
    &lt;properties&gt;
        &lt;maven.compiler.target&gt;1.8&lt;/maven.compiler.target&gt;
        &lt;maven.compiler.source&gt;1.8&lt;/maven.compiler.source&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.bouncycastle&lt;/groupId&gt;
            &lt;artifactId&gt;bcprov-debug-jdk15on&lt;/artifactId&gt;
            &lt;version&gt;1.65&lt;/version&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/project&gt; 

How to get 32 bytes of private key?

答案1

得分: 6

以下是您要求的翻译内容:

PKCS8 的与算法相关部分,在序列的第二个元素位置,对于 EC 来说本身就是一个 DER 编码,其结构是 SEC1 中的 ECPrivateKey,也在 rfc5915 中有文档记录。对于 SunEC,这是一个 SEQUENCE,包含 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();

// 稍作重新组织
DEROctetString wrapped = (DEROctetString) DERSequence.getInstance(pkcs8).getObjectAt(2);
System.out.println(wrapped.getOctets().length);
// 新增部分
DEROctetString raw = (DEROctetString) DERSequence.getInstance(wrapped.getOctets()).getObjectAt(1);
System.out.println(raw.getOctets().length);

由于您使用的是 BouncyCastle,您可以使用 org.bouncycastle.asn1.pkcs.PrivateKeyInfo 这个 BouncyCastle 类来解析 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 值获取,然后转换为字节数组。尽管其长度是可变的,而不是传统的固定长度,因此您可能需要进行调整:

byte[] bytes = ((ECPrivateKey) privateKey).getS().toByteArray();
System.out.println(bytes.length);
// 可能需要进行左侧修剪或填充零
英文:

The algorithm-dependent part of PKCS8, at element #2 of the sequence, for EC is itself a DER encoding, of the SEC1 structure ECPrivateKey, also documented at rfc5915. For SunEC this is a SEQUENCE of INTEGER version and OCTETSTRING containing the actual privatekey bytes; the optional context-0 parameters and context-1 publickey are omitted. So you need to parse that:

	KeyPairGenerator kpg = KeyPairGenerator.getInstance(&quot;EC&quot;,args[0]);
	kpg.initialize(new ECGenParameterSpec(&quot;secp256r1&quot;), 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);

Since you are using BouncyCastle, rather than manually parse the PKCS8 you can use the 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);

and finally, rather than going through the encoding, you can get the privatekey value directly from the ECPrivateKey object as a BigInteger value, which can be converted to a byte array, although it is variable length instead of the fixed length conventionally used for EC privatekeys, so you may need to adjust it:

	byte[] bytes = ((ECPrivateKey)privateKey).getS().toByteArray();
	System.out.println(bytes.length);
	// may need left-trim or pad with zero(s)

huangapple
  • 本文由 发表于 2020年8月25日 04:55:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63568619.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定