从技术上来说,是的。根据您拥有的密钥类型,答案会变得更加棘手。
编辑(2019 年 10 月):.NET Core 3.0 以 DER 编码(与 PEM 编码)形式内置支持所有这些格式。我在每个文件格式的子标题后添加 .NET Core 3.0+ 答案。
PKCS#8 PrivateKeyInfo(PEM“开始私钥”)
如果您有这种类型的文件,并且您使用的是 .NET 4.6 或更高版本,那么可以。您需要具有 DER 编码(与 PEM 编码)数据 blob(如果是 PEM,请参见下文)。
using (CngKey key = CngKey.Import(blob, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSA rsa = new RSACng(key))
{
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
RSA 需要 4.6,ECDSA 需要 4.6.1,DSA 需要 4.6.2。
.NET Core 3.0+ PKCS#8 私钥信息
The ImportPkcs8PrivateKey
方法声明于AsymmetricAlgorithm
,以及所有不对称内置类型(RSA
, DSA
, ECDsa
, ECDiffieHellman
)支持。
using (RSA rsa = RSA.Create())
{
rsa.ImportPkcs8PrivateKey(blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
PKCS#8 EncryptedPrivateKeyInfo(PEM“开始加密的私钥”)
恭喜,您的私钥传输能力很强。遗憾的是,如果您想实际处理它,则需要编写最大数量的代码。你不想处理它。你真的真的想要
- 为密钥创建证书
- 将证书和密钥放入 PFX 文件中
- 将 PFX 加载到 X509Certificate2
- 使用 cert.GetRSAPrivateKey()、cert.GetDSAPrivateKey() 或 cert.GetECDsaPrivateKey()(根据需要)
See pem 证书中的私钥是如何加密的? https://stackoverflow.com/q/43674870/6535399,然后继续下一节,了解艰难之路上的入门知识。不过,你的工作比它所谈论的要多得多。您需要读取文件,了解加密方案和参数,解密 blob,然后使用 CNG 读取 PKCS#8,或者继续深入兔子洞并享受您的文件解析器。
.NET Core 3.0+ PKCS#8 加密的PrivateKeyInfo
The ImportEncryptedPkcs8PrivateKey
方法声明于AsymmetricAlgorithm
,以及所有不对称内置类型(RSA
, DSA
, ECDsa
, ECDiffieHellman
)支持。
using (RSA rsa = RSA.Create())
{
rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
PKCS#1 RSAPrivateKey(PEM“开始 RSA 私钥”)
不幸的是,你正处于“相对简单”和“相对困难”的交汇点,这被数学专业人士称为“留给读者的练习”。
强烈考虑使用 EncryptedPrivateKeyInfo 的 PFX 方法。或者,您可以在自定义代码中执行此操作。自定义代码?好吧,我们就这样做吧。此时您需要的参考文本是
-
.
- 这定义了 ASN.1 语言,它告诉您如何读取 RSAPrivateKey(等)对象结构定义。
- 对于 RSAPrivateKey 这主要是可选的,因为它使用的 SEQUENCE 没有太多细微差别,而且 INTEGER 非常简单。
- 本文档描述了 ASN.1 的 BER(和 CER)和 DER 编码规则。
- 这些关键文件位于 DER 中。 (除非它们在 PEM 中,但我们很快就会解决这个问题)
- 适合您的对象类型的 RFC。
-
RSA私钥 https://www.rfc-editor.org/rfc/rfc3447#appendix-A.1.2(RFC 3447)
-
加密私钥信息 https://www.rfc-editor.org/rfc/rfc5208#section-6(RFC 5208)
-
私钥信息 https://www.rfc-editor.org/rfc/rfc5208#section-5(也是 RFC 5208)
- 其他格式在其他 RFC 中。
好吧,我们继续吧。
- 如果文件是 PEM 编码的(“-----BEGIN RSA PRIVATE KEY-----”或“-----BEGIN PRIVATE KEY-----”等),则需要“un-PEM”它。
- The PEM format is
- (换行符或文件开头)
- 5 个连字符、BEGIN、空格、类型标识符、5 个连字符、换行符
- Base64 编码的有效负载(每 72 个文本字符后有换行符)
- 换行符(除非您以换行符结尾,因为您是 72 个文本字符的倍数)
- 5 个连字符,END,与之前相同的类型标识符,5 个连字符
- 我们想要的部分是有效负载。通过 Convert.FromBase64String 运行它,现在我们有了 DER 编码的
byte[]
为关键对象。
- 使用类型定义和 ITU 文档,为您的密钥文件格式编写解析器。
- 解析密钥。
- 将解析后的密钥转换为 RSAParameters 对象(或 DSAParameters 或 ECParameters,视情况而定)
- 调用 RSA.Create() (等)
- 通过 ImportParameters 方法加载密钥。
- 很好,可以走了。
对于第4步,有一些事情需要注意。具体来说,ASN.1/DER INTEGER 组件有两条 RSAParameters 不喜欢的规则。
- 所有前导 0x00 值均被删除。
- 如果前导字节设置为高位 (>=0x80),但数字应该为正数,则插入 0x00。
.NET 希望这些值作为大端字节数组(与 DER 编码的字节顺序相同),具有以下关系:
- 指数需要多大就多大,只要它不以 0x00 开头即可。
- 模数需要多大就多大,只要它不以 0x00 开头即可。
- D 的大小必须与模数相同(根据需要插入 0x00)
- P 必须是模数 ((Modulus.Length + 1) / 2) 大小的“半舍入”,根据需要插入 0x00。
- Q、DP、DQ 和 InverseQ 的长度必须与 P 相同。(根据需要插入 0x00)。
.NET Core 3.0+ PKCS#1 RSAPrivateKey
The ImportRSAPrivateKey
方法声明于RSA
,并且由于它解析数据并调用ImportParameters
它适用于所有人RSA
派生类型(假设它们已经支持参数导入)。
using (RSA rsa = RSA.Create())
{
rsa.ImportRSAPrivateKey(blob, out _);
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
其他一些格式
确定 RFC 为您的密钥格式定义的 ASN.1 结构,然后记住这一点并评估 RSAPrivateKey 部分。
DSAParameters 和 ECParameters 各自有自己的空间期望。
进一步阅读
其中一些包括并不总是优雅但经常运行的代码:
- 将私钥/公钥从 X509 证书导出到 PEM https://stackoverflow.com/q/43928064/6535399
- 如何在C#中解析(转换为RSA参数)X.509私钥? https://stackoverflow.com/q/44106066/6535399
- 如何修复 DecodeRSAPrivateKey 的错误长度错误? https://stackoverflow.com/q/46968514/6535399
- 如何使用 rsa 从 PEM 文件解密 https://stackoverflow.com/q/46948083/6535399