C# BouncyCastle 使用 PemWriter 导出 EC 私钥

C# BouncyCastle EC Private Key Export Using PemWriter

我在 C# BouncyCastle 中生成一个 EC 密钥对,并尝试使用 PemWriter 将私钥导出到 PEM 文件中。这样做的代码如下:

var ecKeyPairGenerator = new ECKeyPairGenerator();
CKeyGenerationParameters ecKeyGenParams = new ECKeyGenerationParameters(SecObjectIdentifiers.SecP384r1, new SecureRandom());
ecKeyPairGenerator.Init(ecKeyGenParams);
AsymmetricCipherKeyPair pair = ecKeyPairGenerator.GenerateKeyPair();

string path = @"c:\tmp\test\myprivkey.pem";
TextWriter textWriter = new StreamWriter(path);
PemWriter pemWriter = new PemWriter(textWriter);
// passing pair results in the private key being written out
pemWriter.WriteObject(pair);
pemWriter.Writer.Flush();
pemWriter.Writer.Close();

上面代码片段的示例输出是:

-----BEGIN EC PRIVATE KEY-----
MD4CAQEEMJvNXtTUd7A/fY/9/LSXM+Xb/6QS7GydeART/OieN3zh23Uuy0tgiS1D
rohXMgiPvqAHBgUrgQQAIg==
-----END EC PRIVATE KEY-----

然而,当使用 'openssl' 和相同的 EC 曲线 (secp384r1) 做同样的事情时,生成的 PEM 文件是完全不同的,例如:

openssl ecparam -name secp384r1 -genkey -out mykey2.pem -noout

-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDBqCE9+AWL56cvR2/tRNdyaTIlJnfr6TbhCG+Q48w6yyKR+hE0jkeOV
7yh1t8NwqT6gBwYFK4EEACKhZANiAAS2uLv7KG6RRBZBOecaxBz8FsMobnxgZkbQ
8cKdL1DRym1lUDwgfX8AxOC6qkuD1k0UekpHcwiy1mSghy4640qBAKcR3mVghMVF
77Nm8x6nwNijWZroeqhjrw268PPPuAw=
-----END EC PRIVATE KEY-----

如您所见,密钥长度非常不同,我用前者创建的 P12 文件没有导入到 Windows 证书存储区。我一定是用 C# BouncyCastle 做错了什么,但看不到什么(查看 PemWriter 和其他相关的源代码 类 没有指出任何明显的错误)。

如有任何帮助,我们将不胜感激。 谢谢

事实证明,您可以使用私钥和 public 密钥创建一个 ECPrivateKeyStructure 实例,并将对象的 Base64 编码字符串保存到文件中,例如:

...
int orderBitLength = privKeyParam.Parameters.N.BitLength;
X962Parameters x962 = new X962Parameters(privKeyParam.PublicKeyParamSet);
ECPrivateKeyStructure privKeyStruct = 
                    new ECPrivateKeyStructure(orderBitLength, privKeyParam.D, pubKeyInfo.PublicKeyData, x962);

string header = @"-----BEGIN EC PRIVATE KEY-----";
string privKeyStr = Convert.ToBase64String(privKeyStruct.GetDerEncoded(), 
                    Base64FormattingOptions.InsertLineBreaks);
string tail = @"-----END EC PRIVATE KEY-----";

string path = @"c:\tmp\myprivkey.pem";
TextWriter textWriter = new StreamWriter(path);
textWriter.WriteLine(header);
textWriter.WriteLine(privKeyStr);
textWriter.WriteLine(tail);
textWriter.Flush();
textWriter.Close();
...

晚会有点晚了,你可以明确地写下私钥和 public 密钥(也许最好使用单独的文件):

...
// passing pair results in the private key being written out
pemWriter.WriteObject(pair.Private);
pemWriter.WriteObject(pair.Public);
pemWriter.Writer.Flush();
pemWriter.Writer.Close();

但是,当前版本的 Bouncy Castle (1.8.5) 已经将 public 密钥写入(私钥)PEM 文件。所以你不需要明确地写 public 键。

另外,下面两行基本相同:

 pemWriter.WriteObject(pair);
 pemWriter.WriteObject(pair.Private);

源码中可以看到:

# .../BouncyCastle/.../MiscPemGenerator.cs
private static PemObject CreatePemObject(...)
{
  ...
  if (obj is AsymmetricCipherKeyPair)
    return MiscPemGenerator.CreatePemObject((object)
      ((AsymmetricCipherKeyPair) obj).Private,
      algorithm, password, random);
  ...
}