【问题标题】:Digital sign with sha256 with c#使用 c# 使用 sha256 进行数字签名
【发布时间】:2020-08-13 00:17:57
【问题描述】:

在意大利,我们需要对自 2019 年 1 月以来的所有发票进行数字签名。

我找到了一个与 sha-1 配合得很好的代码,但我需要使用 sha256 作为标准。 下面的代码,在成功检测到USB密钥后,向我询问要使用的证书尝试签署“NomeFile”文件后并在“NomeFile”.p7m中输出,当行

signedCms.ComputeSignature(signer,false);

运行,它发生了: 1-如果使用 sha-1,它会要求我输入 PIN 并且文档已成功创建。 2-如果使用 sha-256,请不要询问 PIN 并给我未知错误 -1073741275

我阅读了很多旧帖子(2011-2014)。其他人也有同样的问题,似乎微软使用 sha256 有一些错误。

现在我们在 2018 年底,我在 .net 4、4.6.1 和 4.7.2 中尝试了此代码,但错误是相同的。

有人可以告诉我微软是否纠正了 sha256 的问题,这个奇怪的错误可能是什么? (-1073741275) Error Stack

public String FirmaFile(String NomeFile, DateTime DataFirma, X509Certificate2 cert, out string RisFirma)
        {
            String NomeFirma = NomeFile + ".p7m";
            RisFirma = "";

            try
            {


                // content contiene il file da firmare
                ContentInfo content = new ContentInfo((File.ReadAllBytes(NomeFile)));
                // assegniamo content ad un oggetto di tipo SignedCms
                SignedCms signedCms = new SignedCms(SubjectIdentifierType.IssuerAndSerialNumber, content, false);

                // si instanzia un oggetto CmsSigner che espone i metodi di firma.
                CmsSigner signer = new CmsSigner(cert);
                signer.IncludeOption = X509IncludeOption.EndCertOnly;

                //signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
                signer.DigestAlgorithm = new Oid("SHA256");
                signer.SignedAttributes.Add(new Pkcs9SigningTime(DataFirma));
                try
                {
                    // Viene calcolata la firma del file (in formato PKCS7)
                    signedCms.ComputeSignature(signer,false);
                }
                catch (CryptographicException CEx)
                {
                    RisFirma = "Errore: " + CEx.Message + " Stack: " + CEx.StackTrace;
                    return RisFirma;
                }
                // si pone il file firmato in un array.
                byte[] signature = signedCms.Encode();
                File.WriteAllBytes(NomeFirma, signature);
                RisFirma = "true";
            }
            catch (Exception Ex)
            {
                RisFirma = "Errore in FirmaFile: " + Ex.Message + " Stack: " + Ex.StackTrace;
            }
            return RisFirma;
        }

注意:我尝试了 2 个版本的 OID 签名者.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); signer.DigestAlgorithm = new Oid("SHA256");

所有 2 都给出相同的错误。

我使用带有驱动程序 bit4id (https://www.bit4id.com/it/4identity/) 的 INFOCERT USB KEY,该驱动程序包含在 USB 驱动器中。

【问题讨论】:

  • 该代码看起来像 Java。如果这不正确,请自行编辑您的标签。
  • @Someprogrammerdude 感谢您的更正。
  • @MagoMaverick 你解决过这个问题吗?使用 SignedCms 和 ncipher HSM 时遇到非常相似的错误。

标签: c# sha256 sign


【解决方案1】:

错误和症状似乎表明正在执行签名操作的 CSP(加密服务提供商)不支持 SHA-2。如果它在 BouncyCastle 中工作,那么他们似乎正在导出私钥并将其重新导入他们的软件提供商。

在 .NET 4.7.2 中,您可以尝试以下操作:

...
try
{
    // Viene calcolata la firma del file (in formato PKCS7)
    signedCms.ComputeSignature(signer,false);
}
catch (CryptographicException CEx)
{
    try
    {
        // Try re-importing the private key into a better CSP:
        using (RSA tmpRsa = RSA.Create())
        {
            tmpRsa.ImportParameters(cert.GetRSAPrivateKey().ExportParameters(true));

            using (X509Certificate2 tmpCertNoKey = new X509Certificate2(cert.RawData))
            using (X509Certificate2 tmpCert = tmpCertNoKey.CopyWithPrivateKey(tmpRsa))
            {
                signer.Certificate = tmpCert;
                signedCms.ComputeSignature(signer,false);
            }
        }
    }
    catch (CryptographicException)
    {
        // This is the original exception, not the inner one.
        RisFirma = "Errore: " + CEx.Message + " Stack: " + CEx.StackTrace;
        return RisFirma;
    }
}

如果证书实际上是从 USB 设备上的 PFX 文件加载的,那么问题在于 PFX 指定使用早于 SHA-2 的旧软件 CSP。让 PFX 重新生成以使用最新的 RSA CSP 也可以解决问题。

【讨论】:

  • 谢谢@bartonjs,我下周试试。
  • 我从 .NET Core API 服务调用此代码,您的回答修复了引发的异常(指定了无效类型),但从 .NET 框架 API 服务调用它会引发(未知错误“-1073741275” )。库本身是 .NET Framework 4.7.2。但幸运的是,我使用的是.NET核心服务,所以谢谢你:)
【解决方案2】:

使用这个:

private string podpisz(X509Certificate2 cert, string toSign)
{
    string output = "";

    try
    {
        RSACryptoServiceProvider csp = null;
        csp = (RSACryptoServiceProvider)cert.PrivateKey;

        // Hash the data
        SHA256Managed sha256 = new SHA256Managed();
        UnicodeEncoding encoding = new UnicodeEncoding();
        byte[] data = Encoding.Default.GetBytes(toSign);
        byte[] hash = sha256.ComputeHash(data);

        // Sign the hash
        byte[] wynBin = csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
        output = Convert.ToBase64String(wynBin);

    }
    catch (Exception)
    {

    }

    return output;
}

【讨论】:

  • csp = null 然后csp.SignHash?什么? cert 的意义何在?
  • csp 为空,因此 byte[] wynBin = csp.SignHash(...) 行给出错误。
  • 我丢失了 csp = (RSACryptoServiceProvider)cert.PrivateKey;
  • IMO,一个空的 catch总是是个坏建议。
  • @GrzegorzJ 我试了一下,它正确地询问了我的 PIN 码,完成 SignHash 后,wynBin 的内容不是整个文件签名,而是只有不到 1k 的文件。可能需要做一些事情来保存以 .p7m 格式签名的源文件
【解决方案3】:

我在互联网上找到了这个,我试了一下,非常有效! 无论如何,解决方案有点复杂。

您必须使用 BouncyCastle (https://www.bouncycastle.org/) 库。 但不是可用的版本,而是由另一个论坛上的用户修改的版本。

修改后的充气城堡库链接为: http://www.mediafire.com/download/uc63d1hepqyuhee/bccrypto-net-1.7-src-ext_with_CADES-BES.zip

您必须使用 bin\release 中的 crypto.dll 库并在您的项目中引用它。

这些都是我现在使用的,可能不是所有这些都需要这个特定的案例:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Xml;
using System.IO;
using System.Collections;
using CryptoUpgNet.NonExportablePK;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Ess;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;

这是函数:

public byte[] FirmaFileBouncy(String NomeFile, X509Certificate2 cert, ref string RisFirma)
        {
            String NomeFirma = NomeFile + ".p7m";

            try
            {
                SHA256Managed hashSha256 = new SHA256Managed();
                byte[] certHash = hashSha256.ComputeHash(cert.RawData);

                EssCertIDv2 essCert1 = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier("2.16.840.1.101.3.4.2.1"), certHash);
                SigningCertificateV2 scv2 = new SigningCertificateV2(new EssCertIDv2[] { essCert1 });

                Org.BouncyCastle.Asn1.Cms.Attribute CertHAttribute = new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificateV2, new DerSet(scv2));
                Asn1EncodableVector v = new Asn1EncodableVector();
                v.Add(CertHAttribute);

                Org.BouncyCastle.Asn1.Cms.AttributeTable AT = new Org.BouncyCastle.Asn1.Cms.AttributeTable(v);
                CmsSignedDataGenWithRsaCsp cms = new CmsSignedDataGenWithRsaCsp();

                dynamic rsa = (RSACryptoServiceProvider)cert.PrivateKey;
                Org.BouncyCastle.X509.X509Certificate certCopy = DotNetUtilities.FromX509Certificate(cert);
                cms.MyAddSigner( rsa, certCopy,  "1.2.840.113549.1.1.1", "2.16.840.1.101.3.4.2.1", AT, null);

                ArrayList certList = new ArrayList();
                certList.Add(certCopy);

                Org.BouncyCastle.X509.Store.X509CollectionStoreParameters PP = new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(certList);
                Org.BouncyCastle.X509.Store.IX509Store st1 = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/COLLECTION", PP);

                cms.AddCertificates(st1);

                //mi ricavo il file da firmare
                FileInfo File__1 = new FileInfo(NomeFile);
                CmsProcessableFile file__2 = new CmsProcessableFile(File__1);
                CmsSignedData Firmato = cms.Generate(file__2, true);
                byte[] Encoded = Firmato.GetEncoded();

                File.WriteAllBytes(NomeFirma, Encoded);

                RisFirma = "true";

                return Encoded;

            } catch (Exception ex)  {

                RisFirma = ex.ToString();
                return null;
            }

        }

编辑:重复使用相同的证书,它只在第一次询问 PIN。因此,在启用安全标准的情况下一次制作多个文件是件好事。

【讨论】:

    【解决方案4】:

    致格热戈日:

    源文件为5k 正确的签名文件(IT01234567890_FPA01_2.xml.p7m 是 8k 与您的例程一起保存的文件添加了

    File.WriteAllBytes("c:\\temp\\IT01234567890_FPA01.xml.p7m", wynBin);
    

    之后

    byte[] wynBin = csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
    

    只有 1kb,Dike 不承认。 Sign not reckognized

    Difference between files

    【讨论】:

      猜你喜欢
      • 2012-05-27
      • 2020-07-11
      • 1970-01-01
      • 2020-08-22
      • 2015-08-20
      • 2023-03-10
      • 2023-03-08
      • 2019-02-14
      • 1970-01-01
      相关资源
      最近更新 更多