【问题标题】:C# BouncyCastle EC Private Key Export Using PemWriter使用 PemWriter 导出 C# BouncyCastle EC 私钥
【发布时间】:2017-12-15 19:23:32
【问题描述】:

我正在 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();

上面 sn-p 的一个示例输出是:

-----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 和其他相关类的源代码并没有指出任何明显的错误)。

任何帮助将不胜感激。 谢谢。

【问题讨论】:

  • 使用 openssl 检查 BC 生成的私钥 PEM 文件时,openssl 正确报告了“Private-Key”、“ASN1 OID”和“NIST CURVE”字段,后两者的值与openssl 生成的 PEM 文件。然而,CertUtil 无法“转储”使用 BC 生成的私钥 PEM 创建的 P12 文件,而使用 openssl 生成的私钥 PEM 创建的 P12 则成功。
  • 他们可能使用了不同 asn.1 类型的编码。尝试在两个键上运行 openssl asn1parse -i -dump -i key.pem 来检查。
  • @mat 是的,我就是这么做的。似乎 BC PEM 文件缺少实际密钥? openssl PEM 文件的 ans1parse 输出有一个额外的结构,BC PEM 文件中缺少该结构。该结构看起来像:... 65:d=1 hl=2 l= 100 cont: cont [ 1 ] 67:d=2 hl=2 l= 98 prim: BIT STRING ...该结构位于 openssl PEM 文件的末尾,该结构之前的文件其余部分与 BC 文件中的相同。如何找到 PEM 文件的 asn.1 类型?
  • BC PEM 只包含私钥,openssl 版本也包含公钥。
  • @mat 谢谢。 RFC 5915 还确认 BC PEM 没有公钥,而 openssl PEM 有。而且似乎 CertUtil 想要 P12 中的公钥,而不是在丢失时计算它....

标签: c# cryptography bouncycastle pem key-pair


【解决方案1】:

晚了一点,你可以明确地写出私钥和公钥(也许最好使用单独的文件):

...
// 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) 已经将公钥写入(私钥)PEM 文件中。所以你不需要显式地写公钥。

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

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

【讨论】:

    【解决方案2】:

    事实证明,您可以使用私钥和公钥创建 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();
    ...
    

    【讨论】:

      猜你喜欢
      • 2012-03-13
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      • 2013-12-14
      • 1970-01-01
      • 2011-07-19
      • 1970-01-01
      • 2019-07-08
      相关资源
      最近更新 更多