【问题标题】:Digital signature in c# without using BouncyCastlec#中的数字签名而不使用BouncyCastle
【发布时间】:2018-08-01 00:09:02
【问题描述】:

不使用第 3 方 BouncyCastle 库,有没有办法读取自定义私钥并签署消息? (sha256 hash+使用私钥加密)

【问题讨论】:

    标签: c# rsa signature sha256 digital


    【解决方案1】:

    从技术上讲,是的。根据您拥有的密钥类型,答案会变得更加棘手。

    编辑(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 "BEGIN ENCRYPTED PRIVATE KEY")

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

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

    请参阅How is a private key encrypted in a pem certificate?,然后继续阅读下一节的艰难入门知识。不过,你要做的工作比它所说的要多得多。您需要读取文件,了解加密方案和参数,解密 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 (et al) 对象结构定义。
    • 对于 RSAPrivateKey,这主要是可选的,因为它使用的 SEQUENCE 没有太多细微差别,而且 INTEGER 非常简单。
    1. ITU.T-REC X.690-201508
    • 本文档描述了 ASN.1 的 BER(和 CER)和 DER 编码规则。
    • 这些密钥文件位于 DER 中。 (除非他们在 PEM 中,但我们会尽快解决)
    1. 适合您的对象类型的 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[] 键对象。
    1. 使用类型定义和 ITU 文档,为您的密钥文件格式编写解析器。
    2. 解析密钥。
    3. 将解析后的密钥转换为 RSAParameters 对象(或 DSAParameters 或 ECParameters,视情况而定)
    4. 调用 RSA.Create()(等)
    5. 通过 ImportParameters 方法加载密钥。
    6. 很好。

    对于第 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 都有自己的空间期望。

    进一步阅读

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

    【讨论】:

      【解决方案2】:

      Microsoft 提供了一个类 SignedXML 来对文件进行签名。想了解更多,请查看https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.signedxml(v=vs.110).aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-29
        • 1970-01-01
        • 1970-01-01
        • 2013-05-15
        相关资源
        最近更新 更多