不使用BouncyCastle的c#数字签名

不使用BouncyCastle的c#数字签名,c#,rsa,signature,sha256,digital,C#,Rsa,Signature,Sha256,Digital,在不使用第三方BouncyCastle库的情况下,是否有方法读取自定义私钥并签名?(sha256哈希+使用私钥加密)Microsoft提供了一个类SignedXML来对文件进行签名。要了解更多信息,请在技术上签出,是的。取决于你有什么样的钥匙,答案会变得更加棘手 编辑(2019年10月):.NET Core 3.0以DER编码(vs PEM编码)形式内置了对所有这些格式的支持。我在每个文件格式的子标题后添加.NETCore3.0+答案 PKCS#8私钥信息(PEM“开始私钥”) 如果您有这种类型

在不使用第三方BouncyCastle库的情况下,是否有方法读取自定义私钥并签名?(sha256哈希+使用私钥加密)

Microsoft提供了一个类SignedXML来对文件进行签名。要了解更多信息,请在技术上签出,是的。取决于你有什么样的钥匙,答案会变得更加棘手

编辑(2019年10月):.NET Core 3.0以DER编码(vs PEM编码)形式内置了对所有这些格式的支持。我在每个文件格式的子标题后添加.NETCore3.0+答案

PKCS#8私钥信息(PEM“开始私钥”) 如果您有这种类型的文件,并且您使用的是.NET 4.6或更高版本,则选择“是”。您需要使用DER编码(vs PEM编码)数据blob(如果是PEM,请参见下文)

RSA需要4.6,ECDSA需要4.6.1,DSA需要4.6.2

.NET Core 3.0+PKCS#8 PrivateKeyInfo
ImportPkcs8PrivateKey
方法是在
asymermetricgorithm
上声明的,所有非对称内置类型(
RSA
DSA
ECDsa
ECDiffieHellman
)都支持该方法

using (RSA rsa = RSA.Create())
{
    rsa.ImportPkcs8PrivateKey(blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
using (RSA rsa = RSA.Create())
{
    rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
PKCS#8加密私钥信息(PEM“开始加密私钥”) 祝贺您,您的私钥传输功能强大。不幸的是,如果您想实际处理它,这需要编写最大数量的代码。你不想处理它。你真的,真的,想

  • 为密钥创建证书
  • 将证书和密钥放入PFX文件
  • 将PFX加载到X509E2中
  • 使用cert.GetRSAPrivateKey()、cert.GetDSAPrivateKey()或cert.GetECDsaPrivateKey()(视情况而定)
请参阅,然后继续下一节了解硬道上的底漆。不过,你的工作比它所说的要多得多。您需要读取文件,了解加密方案和参数,解密blob,然后使用CNG读取PKCS#8,或者继续潜入兔子洞,享受您的文件解析器

.NET Core 3.0+PKCS#8加密PrivateKeyInfo
ImportEncryptedPkcs8PrivateKey
方法在
非对称算法上声明,所有非对称内置类型(
RSA
DSA
ECDsa
ECDiffieHellman
)都支持该方法

using (RSA rsa = RSA.Create())
{
    rsa.ImportPkcs8PrivateKey(blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
using (RSA rsa = RSA.Create())
{
    rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
PKCS#1 RSA私钥(PEM“开始RSA私钥”) 你正处于“相对简单”和“相对困难”的不幸交汇点,数学专业称之为“留给读者的练习”

强烈地考虑从加密的私有密钥信息中执行PFX方法。或者,您可以在自定义代码中执行此操作。自定义代码?好的,我们开始吧。此时您需要的参考文本是

    • 这定义了ASN.1语言,它告诉您如何读取RSAPrivateKey(等)对象结构定义
    • 对于RSAPrivateKey,这主要是可选的,因为它使用的序列没有太多细微差别,INTEGER非常简单
    • 本文档描述ASN.1的BER(和CER)和DER编码规则
    • 这些关键文件在DER中。(除非他们在PEM,但我们很快就会解决)
  • 适合您的对象类型的RFC。
    • (RFC 3447)
    • (RFC 5208)
    • (另附RFC 5208)
    • 其他格式在其他RFC中
  • 好的,我们开始吧

  • 如果文件是PEM编码的(“----开始RSA私钥------”或“----开始私钥------”等),则需要“取消PEM”它。
    • PEM格式为
      • (换行符或文件开头)
      • 5个连字符,开始,空格,类型标识符,5个连字符,换行符
      • base64编码的有效负载(每72个文本字符后有换行符)
      • 换行符(除非您以换行符结尾,因为您是72个文本字符的倍数)
      • 5个连字符,结束,与前面相同的类型标识符,5个连字符
    • 我们想要的部分是有效载荷。通过Convert.FromBase64String运行它,现在我们有了密钥对象的DER编码的
      字节[]
  • 使用类型定义和ITU文档,为密钥文件格式编写解析器
  • 解析密钥
  • 将解析的密钥转换为RSAParameters对象(或DSAParameters或ECParameters,视情况而定)
  • 调用RSA.Create()(etc)
  • 通过ImportParameters方法加载密钥
  • 很好
  • 对于步骤4,有一些事情需要注意。具体来说,ASN.1/DER INTEGER组件有两个RSA参数不喜欢的规则

    • 删除所有前导0x00值
    • 如果前导字节设置了高位(>=0x80),但数字应该是正数,请插入0x00
    .NET希望将这些值作为具有以下关系的大端字节数组(与DER编码的字节顺序相同):

    • 只要指数不是以0x00开头,它就可以按需要大
    • 只要不是以0x00开头,模数就可以按需要大
    • D的大小必须与模数相同(必要时插入0x00)
    • P必须是模数((模数长度+1)/2)大小的“半舍入”,必要时插入0x00
    • Q、 DP、DQ和InverseQ的长度必须与P相同(必要时插入0x00)
    .NET Core 3.0+PKCS#1 RSAPrivateKey
    ImportRSAPrivateKey
    方法是在
    RSA
    上声明的,因为它解析数据并调用
    ImportParameters
    ,所以它适用于所有
    RSA
    派生类型(假设它们已经支持参数导入)

    其他格式 确定RFC为您的密钥格式定义了什么ASN.1结构,然后记住这一点并评估RSAPrivateKey部分

    数据空间参数和ECParameters都有自己的空间期望

    进一步阅读 其中包括