如何加载椭圆曲线 PEM 编码的私钥?

How do I load an Elliptic Curve PEM encoded Private Key?

我使用 OpenSSL 生成了一个椭圆曲线 private/public 密钥对。私钥和 public 密钥是 PEM 编码的。由于 this.,我已经弄清楚如何加载 public 密钥但是,我不知道如何加载私钥,因为上面的消息以 InvalidKeySpecException: key spec 结束无法识别。

然后我找到了 this,但它也以 "encoded key spec not recognised" 结尾。如何加载我的私钥?

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 编码私钥所需的算法说明符。幸运的是,密钥本身在编码时始终具有相同的大小(它不使用任何 ASN.1 整数,据我所知,它们可能具有不同的大小)。

这意味着您可以简单地从另一个键连接 header:

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