繁体   English   中英

不使用BouncyCastle的C#中的数字签名

[英]Digital signature in c# without using BouncyCastle

在不使用第三方BouncyCastle库的情况下,有没有办法读取自定义私钥并对消息签名? (使用私钥进行sha256哈希+加密)

从技术上讲,是的。 根据您拥有哪种键,答案会变得更加棘手。

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

PKCS#8 PrivateKeyInfo(PEM“ BEGIN PRIVATE KEY”)

如果您拥有这种类型的文件,并且您使用的是.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 PrivateKeyInfo

ImportPkcs8PrivateKey方法在AsymmetricAlgorithm上声明,并且所有非对称内置类型( RSADSAECDsaECDiffieHellman )都支持该方法。

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()

请参阅如何在pem证书中加密私钥? ,然后继续进行下一部分的入门。 但是,您要做的工作比谈论的要多得多。 您需要阅读文件,了解加密方案和参数,解密Blob,然后使用CNG读取PKCS#8,或者只是继续钻探兔子洞并享受文件解析器的乐趣。

.NET Core 3.0+ PKCS#8 EncryptedPrivateKeyInfo

ImportEncryptedPkcs8PrivateKey方法在AsymmetricAlgorithm上声明,并且所有非对称内置类型( RSADSAECDsaECDiffieHellman )都支持该方法。

using (RSA rsa = RSA.Create())
{
    rsa.ImportEncryptedPkcs8PrivateKey(password, blob, out _);
    return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

PKCS#1 RSAPrivateKey(PEM“ BEGIN RSA PRIVATE KEY”)

不幸的是,“相对简单”和“相对困难”的融合被数学专业的学生称为“留给读者的练习”。

强烈考虑使用EncryptedPrivateKeyInfo的PFX方法。 或者,您可以在自定义代码中执行此操作。 自定义代码? 好吧,让我们这样做。 此时您需要的参考文本是

  1. ITU.T-REC X.680-201508
    • 这定义了ASN.1语言,它告诉您如何读取RSAPrivateKey(等)对象结构定义。
    • 对于RSAPrivateKey,这几乎是可选的,因为它使用的SEQUENCE的细微差别不大,并且INTEGER非常简单。
  2. ITU.T-REC X.690-201508
    • 本文档介绍了ASN.1的BER(和CER)和DER编码规则。
    • 这些密钥文件位于DER中。 (除非它们处于PEM中,但是我们会尽快修复)
  3. 适用于您的对象类型的RFC。

好吧,让我们继续。

  1. 如果文件是PEM编码的(“ ----- BEGIN RSA PRIVATE KEY -----”或“ ----- BEGIN PRIVATE KEY -----”等),则需要“ un-PEM”它。
    • PEM格式为
      • (换行符或文件开头)
      • 5个连字符,BEGIN,空格,类型标识符,5个连字符,换行符
      • base64编码的有效负载(每72个文本字符后带有换行符)
      • 换行符(除非您以换行符结尾,因为您是72个文本字符的倍数)
      • 5个连字符,END,类型标识符与以前相同,5个连字符
    • 我们想要的部分是有效载荷。 通过Convert.FromBase64String运行它,现在我们有了DER编码的byte[]作为键对象。
  2. 使用类型定义和ITU文档,为您的密钥文件格式编写一个解析器。
  3. 解析密钥。
  4. 将已解析的密钥转换为RSAParameters对象(或DSAParameters或ECParameters,视情况而定)
  5. 呼叫RSA.Create()(等)
  6. 通过ImportParameters方法加载密钥。
  7. 好去。

对于步骤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

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每个都有自己的空间期望。

进一步阅读

其中一些包括并非总是优雅但经常运行的代码:

Microsoft提供了一个SignedXML类来对文件进行签名。 要了解更多信息,请检出https://msdn.microsoft.com/zh-cn/library/system.security.cryptography.xml.signedxml(v=vs.110).aspx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM