Java Bouncy Castle generated ES256 key doesn't work with JWT.io

依然范特西╮ 提交于 2020-05-17 03:01:09

问题


I am generating a keypair like below:

 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();
}

Below is my private key generated:

-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgVBnFvRMRyO418Oeb
z1YI778gLVNZJn0YI+atgDhTsPagCgYIKoZIzj0DAQehRANCAAQxzPBfVxJfosNl
3tJc+pD0tpftsEy2hWmLc5EK7QbSAtXqqVL2/Zn6JxMbkueRpvIl1/Ag0NvBbnv+
OJfWY2ws
-----END PRIVATE KEY-----

Below is my public key generated:

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMczwX1cSX6LDZd7SXPqQ9LaX7bBM
toVpi3ORCu0G0gLV6qlS9v2Z+icTG5LnkabyJdfwINDbwW57/jiX1mNsLA==
-----END PUBLIC KEY-----

When I go to JWT.io, and try to generate a JWT, I select the algorithm as ES256, and put my private key, it doesn't give anything. But if I use a private key generated via openssl commands, it does give me a JWT.

Can you please tell me what is wrong with my keys generated using Java.


回答1:


Whatever code jwt.io is using is unnecessarily fragile.

When using PKCS8 for an 'EC' (X9.62-style, ECDSA and/or ECDH and/or related) private key, the algorithm-dependent part uses the structure defined by appendix C.4 of SEC1 from https://secg.org :

ECPrivateKey ::= SEQUENCE {
    version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
    privateKey OCTET STRING,
    parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
    publicKey [1] BIT STRING OPTIONAL
}

As you can see, the third and fourth elements are optional. When OpenSSL writes this structure, it omits the third element (parameters) because it's redundant with the AlgorithmIdentifier of the outer PKCS8, but includes the fourth element (publicKey) because although technically redundant it can be useful.

BouncyCastle in Java includes both, while the (Oracle/OpenJDK) standard provider SunEC includes neither. Compare https://crypto.stackexchange.com/questions/80275/converting-raw-ecc-private-key-into-asn-1-der-encoded-key/#80290 including my comment. It appears that whatever code jwt.io is running -- it doesn't say and I didn't try to figure out -- is coded to parse EC privatekey files assuming the combination OpenSSL uses only and nothing else, and thus doesn't work for either the Bouncy or SunEC format.

It's a little work to convert the SunEC format to the OpenSSL -- you need to actually do the scalar multiplication of dG, although with Bouncy this isn't too hard. OTOH since you have Bouncy, converting the Bouncy format to the OpenSSL, by simply omitting the parameters from the SEC1 structure, is fairly easy:

//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();
    }
}


来源:https://stackoverflow.com/questions/61676744/java-bouncy-castle-generated-es256-key-doesnt-work-with-jwt-io

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!