Java Ключ ES256, сгенерированный Bouncy Castle, не работает с JWT.io - PullRequest
1 голос
/ 08 мая 2020

Я генерирую пару ключей, как показано ниже:

 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-----

Ниже сгенерирован мой publi c ключ:

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

Когда я go обращаюсь к JWT.io и пытаюсь сгенерировать JWT, я выбираю алгоритм как ES256 и помещаю свой закрытый ключ, он ничего не дает. Но если я использую закрытый ключ, сгенерированный с помощью команд openssl, он дает мне JWT.

Не могли бы вы сказать мне, что не так с моими ключами, сгенерированными с использованием Java.

1 Ответ

2 голосов
/ 08 мая 2020

Независимо от того, какой код использует jwt.io, это необязательно fr agile.

При использовании PKCS8 для 'E C' (стиль X9.62, ECDSA и / или ECDH и / или связанный ) закрытый ключ, часть, зависящая от алгоритма, использует структуру, определенную приложением C .4 к SEC1 из https://secg.org:

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

Как видите, третье и четвертые элементы необязательны. Когда OpenSSL записывает эту структуру, он пропускает третий элемент (параметры), потому что он избыточен с AlgorithmIdentifier внешнего PKCS8, но включает четвертый элемент (publicKey), потому что, хотя технически избыточный, он может быть полезен.

BouncyCastle в Java включает оба, в то время как стандартный провайдер (Oracle / OpenJDK) SunE C не включает ни одного. Сравните https://crypto.stackexchange.com/questions/80275/converting-raw-ecc-private-key-into-asn-1-der-encoded-key/#80290 с моим комментарием. Похоже, что какой бы код ни был запущен jwt.io - он не говорит, и я не пытался выяснить - закодирован для анализа файлов закрытого ключа E C, предполагая, что OpenSSL использует только комбинацию и ничего больше, и, следовательно, не работает ни в формате Bouncy, ни в формате SunE C.

Преобразование формата SunE C в OpenSSL - это небольшая работа - вам действительно нужно выполнить скалярное умножение dG, хотя с Bouncy это не так уж сложно. OTOH, поскольку у вас есть Bouncy, преобразовать формат Bouncy в OpenSSL, просто исключив параметры из структуры SEC1, довольно просто:

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