本文介绍了不使用BouncyCastle的C#中的数字签名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

不使用第三方BouncyCastle库,是否可以读取自定义私钥并签名消息? (使用私钥进行sha256哈希+加密)

Without using 3rd party BouncyCastle library, is there a way to read a custom private key and sign the message ? (sha256 hash+encryption using private key)

推荐答案

从技术上讲,是的.根据答案的类型,您会变得更加棘手.

Technically, yes. Depending on what kind of key you have the answer gets more tricky.

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

Edit (2019-Oct): .NET Core 3.0 has built-in support for all of these formats, in their DER-encoded (vs PEM-encoded) forms. I'm adding the .NET Core 3.0+ answers after a sub-heading within each file format.

如果您具有这种类型的文件,并且您使用的是.NET 4.6或更高版本,则可以.您需要拥有DER编码(相对于PEM编码)的数据blob(如果是PEM,请参见下文).

If you have this type of file, and you're on .NET 4.6 or higher, then yes. You need to have the DER encoded (vs PEM encoded) data blob (see below if it's 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.

4.6 is required for for RSA, 4.6.1 for ECDSA, 4.6.2 for DSA.

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

The ImportPkcs8PrivateKey method is declared on AsymmetricAlgorithm, and all asymmetric built-in types (RSA, DSA, ECDsa, ECDiffieHellman) support it.

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

PKCS#8 EncryptedPrivateKeyInfo(PEM开始加密的私钥")

恭喜,您的私钥传输很强大.可悲的是,如果您想实际处理它,则需要编写最大数量的代码.您不想处理它.您真的很想要

PKCS#8 EncryptedPrivateKeyInfo (PEM "BEGIN ENCRYPTED PRIVATE KEY")

Congratulations, your private key transport is strong. Sadly, this requires the maximum amount of code to be written if you want to actually handle it. You don't want to handle it. You really, really, want to

  • 为密钥创建证书
  • 将证书和密钥放入PFX文件
  • 将PFX加载到X509Certificate2
  • 使用cert.GetRSAPrivateKey(),cert.GetDSAPrivateKey()或cert.GetECDsaPrivateKey()(视情况而定)

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

See How is a private key encrypted in a pem certificate?, and then continue to the next section for the primer on the hard way. You have a lot more work than it will talk about, though. You need to read the file, understand the encryption scheme and parameters, decrypt the blob, then use CNG for reading the PKCS#8, or just keep diving down the rabbit hole and enjoy your file parser.

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

The ImportEncryptedPkcs8PrivateKey method is declared on AsymmetricAlgorithm, and all asymmetric built-in types (RSA, DSA, ECDsa, ECDiffieHellman) support it.

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

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

PKCS#1 RSAPrivateKey (PEM "BEGIN RSA PRIVATE KEY")

You're at the unfortunate confluence of "relatively simple" and "relatively hard" that is known to math majors as "an exercise left to the reader".

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

Strongly consider doing the PFX approach from EncryptedPrivateKeyInfo. Alternatively, you can do this in custom code. Custom code? Okay, let's do this. The reference texts that you need at this point are

  1. ITU.T-REC X.680-201508 .
    • 这定义了ASN.1语言,它告诉您如何读取RSAPrivateKey(等)对象结构定义.
    • 对于RSAPrivateKey,这主要是可选的,因为它使用的SEQUENCE的细微差别不大,而INTEGER非常简单.
  1. ITU.T-REC X.680-201508.
    • This defines the ASN.1 language, which tells you how to read the RSAPrivateKey (et al) object structure definition.
    • For RSAPrivateKey this is mostly optional, since there aren't many nuances to SEQUENCE that it uses, and INTEGER is pretty straightforward.
  • 该文档描述了ASN.1的BER(和CER)和DER编码规则.
  • 这些密钥文件位于DER中. (除非它们处于PEM中,但我们会尽快修复)
  • RSAPrivateKey (RFC 3447)
  • EncryptedPrivateKeyInfo (RFC 5208)
  • PrivateKeyInfo (also RFC 5208)
  • Other formats are in other RFCs.

好的,让我们继续.

  1. 如果文件是PEM编码的("----- BEGIN RSA PRIVATE KEY -----"或"----- BEGIN PRIVATE KEY -----"等),则需要取消-PEM".
    • PEM格式为
      • (换行符或文件开头)
      • 5个连字符,BEGIN,空格,类型标识符,5个连字符,换行符
      • base64编码的有效负载(每72个文本字符后都有换行符)
      • 换行符(除非您以换行符结尾,因为您是72个文本字符的倍数)
      • 5个连字符,END,与以前相同的类型标识符,5个连字符
  1. If the file is PEM encoded ("-----BEGIN RSA PRIVATE KEY-----" or "-----BEGIN PRIVATE KEY-----", etc) you need to "un-PEM" it.
    • The PEM format is
      • (newline or beginning of file)
      • 5 hyphens, BEGIN, space, the type identifier, 5 hyphens, a newline
      • a base64-encoded payload (with newlines after every 72 text characters)
      • a newline (unless you ended with a newline because you were a multiple of 72 text characters)
      • 5 hyphens, END, the same type identifier as before, 5 hyphens

对于第4步,需要注意一些事项.具体来说,ASN.1/DER INTEGER组件具有RSAParameters不喜欢的两个规则.

For step 4, there are some things to be careful about. Specifically, the ASN.1/DER INTEGER components have two rules that RSAParameters does not like.

  • 所有开头的0x00值都将被删除.
  • 如果前导字节设置了高位(> = 0x80),但数字应该为正,则插入0x00.

.NET希望这些值成为具有以下关系的大端字节数组(与DER编码的字节顺序相同):

.NET wants the values as big-endian byte arrays (which is the same byte order as the DER encoding) with the following relationship:

  • 只要不以0x00开头,指数就等于需要的大小.
  • 只要不以0x00开头,模量就可以满足需要.
  • D的大小必须与模数相同(必要时插入0x00)
  • P必须是模数"大小的半舍入"((Modulus.Length + 1)/2),并根据需要插入0x00.
  • Q,DP,DQ和InverseQ必须具有与P相同的长度(必要时插入0x00).

ImportRSAPrivateKey方法是在RSA上声明的,并且由于它解析数据并调用ImportParameters,因此它适用于所有RSA派生类型(假设它们已经支持参数导入).

The ImportRSAPrivateKey method is declared on RSA, and since it parses data and calls ImportParameters it works for all RSA derived types (assuming they already supported parameter import).

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

某些其他格式

确定哪种RFC为您的密钥格式定义了ASN.1结构,然后牢记这一点并评估RSAPrivateKey部分.

Some other format

Determine what RFC defines the ASN.1 structure for your key format, then keep that in mind and evaluate the RSAPrivateKey section.

DSAParameters和ECParameters都有各自的空间期望.

DSAParameters and ECParameters each have their own spatial expectations.

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

Some of these include not-always-elegant, but frequently functioning code:

  • Export private/public keys from X509 certificate to PEM
  • How to parse(Convert to RSAParameters) X.509 private key in C#?
  • How to fix bad length error for DecodeRSAPrivateKey?
  • How to decrypt using rsa from PEM file

这篇关于不使用BouncyCastle的C#中的数字签名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-27 21:31