使用 bouncy castle 将 ECDSA secp521r1 私钥转换为 PEM 格式

Convert ECDSA secp521r1 private key into PEM format using bouncy castle

我们正在以编程方式在 java 中生成 ECDSA private/public 密钥,如下所示:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"));
KeyPair keyPair = keyPairGenerator.generateKeyPair();

JGit 使用私钥连接到发布 public 密钥的 git 提供商。所以我们需要将私钥转换为 PEM 格式。这在使用基于 RSA 的 private/public 密钥时工作正常。然而,现在我们使用 ECDSA 生成密钥 运行 成为问题,而 JGit 连接到 github。以下代码用于转换 PEM 格式的私钥,该格式适用于基于 RSA 的密钥。

private String getPrivateKeyInPEM(KeyPair keyPair) throws IOException {

   StringWriter writer = new StringWriter();
   JcaPEMWriter privatePemWriter = new JcaPEMWriter(writer);
   privatePemWriter.writeObject(keyPair.getPrivate());
   privatePemWriter.close();
   String privateKey = writer.toString();
   writer.close();

   return privateKey;
}

现在我们在使用 ECDSA 生成密钥时从 Jsch 收到以下错误。

Caused by: com.jcraft.jsch.JSchException: invalid privatekey: 
        at com.jcraft.jsch.KeyPair.load(KeyPair.java:664)
        at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:46)
        at com.jcraft.jsch.JSch.addIdentity(JSch.java:441)

我们是否需要以不同的方式为基于 ECDSA 的密钥生成 PEM 格式的私钥? 我们正在使用 1.70 版本的充气城堡 和 Jsch verison 0.1.55

相关格式是来自标准文档“SEC 1:椭圆曲线密码术”的“C.4 椭圆曲线私钥语法”部分的 ECPrivateKey:

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

我们看到 SEQUENCE 的最后两个元素是可选的。不幸的是,Jsch 隐含地要求它们存在(请参阅 0.1.55 源代码中的 com.jcraft.jsch.KeyPairECDSA.parse)。当 运行 使用默认提供程序配置的示例代码时,我发现失败是由于缺少这些可选元素造成的。

幸运的是,如果您使用 BouncyCastle 提供程序实际生成 KeyPair,则您的示例有效,因为 BC 在对私钥进行编码时将这些组件添加到 ECPrivateKey 结构中。

例如

Security.addProvider(new BouncyCastleProvider());
...
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");