【问题标题】:How do I load an Elliptic Curve PEM encoded Private Key? [duplicate]如何加载椭圆曲线 PEM 编码的私钥? [复制]
【发布时间】:2017-06-15 03:14:49
【问题描述】:

我使用 OpenSSL 生成了一个椭圆曲线私钥/公钥对。私钥和公钥是 PEM 编码的。感谢this.,我已经知道如何加载公钥但是,我不知道如何加载私钥,因为上面的消息只是以 InvalidKeySpecException: key spec notrecognized 结束。

然后我找到了this,但它也以“无法识别的编码密钥规范”告终。如何加载我的私钥?

private PrivateKey loadPrivateKey(String location) {
    try {
        // Strip the guarding strings
        byte[] bytes = stripGuardLines(location);

        return KeyFactory.getInstance("ECDH").generatePrivate(new PKCS8EncodedKeySpec(bytes));
    } catch (FileNotFoundException e) {
        LoggerFactory.getLogger("Nectar").error("Failed to find Private KEY: " + location);
        System.exit(1);
    } catch (IOException e) {
        LoggerFactory.getLogger("Nectar").error("IOException while loading Private Key!");
        e.printStackTrace();
        System.exit(1);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        e.printStackTrace();
        System.exit(1);
    }

    return null;
}

private byte[] stripGuardLines(String location) throws IOException {
    BufferedReader r = new BufferedReader(new FileReader(location));

    String line;
    StringBuilder sb = new StringBuilder();
    while((line = r.readLine()) != null) {
        if(line.contains("EC PRIVATE KEY")) { //Check if guard line
            continue;
        }
        sb.append(line);
    }
    // Guard lines stripped, now decode base64

    return Base64.getDecoder().decode(sb.toString());
}

这是私钥文件:

-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDD2MFRv6BpJU6/zDI2yBfVbe0oeU1nFAoYMedDGtcdwHyWNJSeiYRBA
pVNzMxPSBLWgBwYFK4EEACKhZANiAAQBttEp/qUGnDlmL+o6KZnVs+RoBnEBEGho
PxSUu1Xfj77QQqfuqHOCRzWXseQA1aZB/h6VQEiFovugtG1G3HaMxxrqLLxb10g2
BMaRcAfZyeqc3O0Ui8XXb1esn0gOrCU=
-----END EC PRIVATE KEY-----

【问题讨论】:

  • 认为您刚刚获得了最少的编码,而不是符合 PKCS#8 的结构。从 Java 创建您自己的 PKCS#8 并与在线 ASN.1 解码器进行比较(首先编码为 base 64)。
  • 是的,刚刚确认,这是 PKCS#8 结构中的 X9.62 结构。
  • @dave_thompson_085 你可以直接link to your answer点击下方的分享按钮。或以重复的形式关闭问题(调用双重金徽章权力,当心)。
  • @MaartenBodewes:我没有特别链接我的答案,因为它不是(现在)唯一的好答案,也可能不是最好的。我个人使用'openssl to pkcs8 then JCE'或者在证书'openssl to pkcs12'的情况下。我回答关于 BC 只是因为 Q 中的那一点没有得到解决。 :-)

标签: java cryptography bouncycastle private-key elliptic-curve


【解决方案1】:

您的代码仅输出密钥本身。它缺少 PKCS#8 编码私钥所需的算法说明符。幸运的是,密钥本身在编码时始终具有相同的大小(它不使用任何 ASN.1 整数,据我所知,它可能具有不同的大小)。

这意味着您可以简单地连接来自另一个键的标题:

// static header you can put in front
byte[] header = Hex.decode("30 81bf 020100 301006072a8648ce3d020106052b81040022 0481a7");
// your key from the PEM above
byte[] fromPEM = Base64.decode("MIGkAgEBBDD2MFRv6BpJU6/zDI2yBfVbe0oeU1nFAoYMedDGtcdwHyWNJSeiYRBApVNzMxPSBLWgBwYFK4EEACKhZANiAAQBttEp/qUGnDlmL+o6KZnVs+RoBnEBEGhoPxSUu1Xfj77QQqfuqHOCRzWXseQA1aZB/h6VQEiFovugtG1G3HaMxxrqLLxb10g2BMaRcAfZyeqc3O0Ui8XXb1esn0gOrCU=");
byte[] bytes = Arrays.concatenate(header, fromPEM);
PrivateKey ecPrivate = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(bytes));

此代码既与 Bouncy Castle 兼容,又与 Oracle 的 Java JRE 中的默认实现兼容。


请注意,您也可以使用与 Oracle 兼容的代码来创建您的密钥对:

KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC");
kpGen.initialize(new ECGenParameterSpec("secp384r1"));
KeyPair ecKP = kpGen.generateKeyPair();

【讨论】:

  • 有点明显,但由于标头包含长度编码和命名曲线的 OID,这仅适用于 secp384r1(或 P-384,同样的东西)曲线。
  • @dave_thompson_085 这样可能更好,会投票赞成答案。我的选择更多是解决这个问题(没有时间在工作中与openssl 混在一起:P)。
  • (ninja) 或者让 OpenSSL 转换 PEM:openssl pkey <raw >pkcs8(或者特别是在 0.9.8 或更低版本的openssl pkcs8 -topk8 -nocrypt <raw >pkcs8)然后剥离和 base64 解码。或者同时使用 openssl pkcs8 -topk8 -nocrypt -outform der <raw.pem >pkcs8.der 转换为 DER 并直接使用它 - 但 not pkey -outform der 输出 legacy/raw!
  • 谢谢,我最终使用 openssl pkey -in [old] -out [new] 将 .PEM 从“旧格式”转换为“新格式”
猜你喜欢
  • 1970-01-01
  • 2020-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多