我正在生成如下所示的密钥对:
public static void main(String args[]) throws Exception{
StringWriter pemStrWriter = new StringWriter();
JcaPEMWriter pemWriter = new JcaPEMWriter(pemStrWriter);
Security.addProvider(new BouncyCastleProvider());
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
ECGenParameterSpec spec = new ECGenParameterSpec("secp256r1");
g.initialize(spec);
KeyPair keyPair = g.generateKeyPair();
pemWriter.writeObject(new JcaPKCS8Generator(keyPair.getPrivate(), null));
pemWriter.close();
BufferedWriter writer = new BufferedWriter(new FileWriter("privatekeyjca.pem"));
writer.write(pemStrWriter.toString());
writer.close();
BufferedWriter writer2 = new BufferedWriter(new FileWriter("publickeyjca.pem"));
StringWriter pemStrWriter2 = new StringWriter();
JcaPEMWriter pemWriter2 = new JcaPEMWriter(pemStrWriter2);
pemWriter2.writeObject(keyPair.getPublic());
pemWriter2.close();
writer2.write(pemStrWriter2.toString());
writer2.close();
}
以下是我的私钥生成:
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgVBnFvRMRyO418Oeb
z1YI778gLVNZJn0YI+atgDhTsPagCgYIKoZIzj0DAQehRANCAAQxzPBfVxJfosNl
3tJc+pD0tpftsEy2hWmLc5EK7QbSAtXqqVL2/Zn6JxMbkueRpvIl1/Ag0NvBbnv+
OJfWY2ws
-----END PRIVATE KEY-----
下面是我的公钥生成:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMczwX1cSX6LDZd7SXPqQ9LaX7bBM
toVpi3ORCu0G0gLV6qlS9v2Z+icTG5LnkabyJdfwINDbwW57/jiX1mNsLA==
-----END PUBLIC KEY-----
[当我去JWT.io并尝试生成JWT时,我选择算法为ES256,并放入我的私钥,但它没有任何作用。但是,如果我使用通过openssl命令生成的私钥,它确实会给我一个JWT。
您能告诉我使用Java生成的密钥有什么问题吗?
jwt.io使用的任何代码都是不必要的脆弱。
[当将PKCS8用于“ EC”(X9.62样式,ECDSA和/或ECDH和/或相关)私钥时,算法相关部分将使用https://secg.org中SEC1附录C.4定义的结构。 :
ECPrivateKey ::= SEQUENCE {
version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
privateKey OCTET STRING,
parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
publicKey [1] BIT STRING OPTIONAL
}
如您所见,第三个和第四个元素是可选的。当OpenSSL编写此结构时,它省略了第三个元素(参数),因为它与外部PKCS8的AlgorithmIdentifier冗余,但包括了第四个元素(publicKey),因为尽管从技术上来说它可能是有用的。]
Java中的BouncyCastle包括两者,而(Oracle / OpenJDK)标准提供者SunEC都不包括。比较https://crypto.stackexchange.com/questions/80275/converting-raw-ecc-private-key-into-asn-1-der-encoded-key/#80290和我的评论。似乎正在运行的任何代码jwt.io -都没有说,我也没有想出-假设OpenSSL仅使用组合,而没有使用,则编码为解析EC私钥文件适用于Bouncy或SunEC格式。
将SunEC格式转换为OpenSSL的工作量很小-您实际上需要进行dG的标量乘法,尽管使用Bouncy并不难。 OTOH,因为您有Bouncy,只需简单地从SEC1结构中省略参数就可以将Bouncy格式转换为OpenSSL:
//nopackage
import java.io.OutputStreamWriter;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.sec.ECPrivateKey;
import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.util.io.pem.PemObject;
public class SO61676744ECKeyNoParam {
public static void main (String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
JcaPEMWriter wr = new JcaPEMWriter(new OutputStreamWriter(System.out));
KeyPairGenerator gen = KeyPairGenerator.getInstance("EC","BC");
gen.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair key = gen.generateKeyPair();
PrivateKeyInfo badp8 = PrivateKeyInfo.getInstance(key.getPrivate().getEncoded());
ECPrivateKey badsec = ECPrivateKey.getInstance(badp8.parsePrivateKey());
ECPrivateKey goodsec = new ECPrivateKey(256, badsec.getKey(), badsec.getPublicKey(), null);
PrivateKeyInfo goodp8 = new PrivateKeyInfo(badp8.getPrivateKeyAlgorithm(), goodsec);
wr.writeObject(new PemObject("PRIVATE KEY", goodp8.getEncoded()));
wr.writeObject(key.getPublic());
wr.close();
}
}