C# 带sha256和c的数字签名#
在意大利,自2019年1月起,我们需要对所有发票进行数字签名 我发现一个代码可以很好地与sha-1配合使用,但我需要使用sha256作为标准。 下面的代码,成功检测到USB密钥后,要求我使用证书尝试签名“NomeFile”文件后,输出在“NomeFile”.p7m,当行 签名CMS.计算签名(签名者,假) 运行时,会发生以下情况: 1-如果使用sha-1,它会要求我输入PIN,并成功创建文档。 2-如果使用sha-256,请不要询问PIN,并给出未知错误-1073741275 我读了很多老帖子(2011-2014)。其他人也有同样的问题,似乎微软在使用sha256时有一些缺陷 现在我们已经到了2018年底,我在.net 4、4.6.1和4.7.2中尝试了这段代码,但错误是一样的 有人可以告诉我微软是否纠正了sha256的问题,这个奇怪的错误是什么?(-1073741275) 注:我试了两个版本的OID signer.DigestAlgorithm=新Oid(“2.16.840.1.101.3.4.2.1”); signer.DigestAlgorithm=新Oid(“SHA256”) 所有2个都给出相同的错误 我使用USB驱动器中包含的带驱动程序bit4id()的INFOCERT USB密钥。使用此项:C# 带sha256和c的数字签名#,c#,sha256,sign,C#,Sha256,Sign,在意大利,自2019年1月起,我们需要对所有发票进行数字签名 我发现一个代码可以很好地与sha-1配合使用,但我需要使用sha256作为标准。 下面的代码,成功检测到USB密钥后,要求我使用证书尝试签名“NomeFile”文件后,输出在“NomeFile”.p7m,当行 签名CMS.计算签名(签名者,假) 运行时,会发生以下情况: 1-如果使用sha-1,它会要求我输入PIN,并成功创建文档。 2-如果使用sha-256,请不要询问PIN,并给出未知错误-1073741275 我读了很多老帖子(
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;
}
使用以下命令:
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;
}
我在互联网上找到了这个,我尝试了一下,难以置信的是它成功了! 无论如何,解决方案要复杂一点 您必须使用BouncyCastle()库。 但不是可用的版本,而是由其他论坛上的用户修改的版本 到bouncy castle库的链接已修改为: 您必须使用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。所以,在安全标准处于活动状态的情况下,一次创建多个文件是很好的。我在互联网上找到了这个方法,我尝试了一下,效果令人难以置信! 无论如何,解决方案要复杂一点 您必须使用BouncyCastle()库。 但不是可用的版本,而是由其他论坛上的用户修改的版本 到bouncy castle库的链接已修改为: 您必须使用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。因此,在安全标准处于活动状态的情况下,一次创建多个文件很好。致Grzegorz:
源文件是5k
正确的签名文件(IT01234567890_FPA01_2.xml.p7m)为8k
与例程一起保存的文件添加了
File.WriteAllBytes("c:\\temp\\IT01234567890_FPA01.xml.p7m", wynBin);
之后
仅1kb,未被堤坝识别。
致格泽戈兹:
源文件是5k
正确的签名文件(IT01234567890_FPA01_2.xml.p7m)为8k
与例程一起保存的文件添加了
File.WriteAllBytes("c:\\temp\\IT01234567890_FPA01.xml.p7m", wynBin);
之后
仅1kb,未被堤坝识别。
错误和症状似乎表明正在执行签名操作的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也可以解决问题。错误和症状似乎表明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也可以解决问题。该代码看起来像Java。如果不正确,请自己编辑标记。@Someprogrammerdude感谢您的更正。@Someprogrammerdude感谢您的更正。@MagoMaverick您解决过这个问题吗?使用
SignedCms
和ncipher HSM遇到了非常类似的错误。这些代码看起来像Java。如果不正确,请自己编辑您的标记。@Someprogrammerdude感谢您的更正。@MagoMaverick您解决过这个问题吗?Experience使用SignedCms
和一个ncipher-HSM检查非常类似的错误。csp=null
然后csp.SignHash
?什么?以及cert
的意义是什么?csp为null,所以行字节[]wynBin=csp。SignHash(…)给出错误。我丢失了csp=(RSACryptoServiceProvider)cert.PrivateKey;依我看,一个空的catch
块总是一个不好的建议。@GrzegorzJ我尝试了一下,它正确地询问了我PIN,完成签名后,wynBin的内容不是完整的已签名文件,而是少于1k的文件。可能需要做些什么来保存已签名的源文件。p7m格式csp=null
,然后csp.SignHash
?什么?证书的意义是什么?csp为空,因此行字节[]wynBin=csp。SignHash(…)给出错误。我丢失了csp=(RSACryptServiceProvider)cert.PrivateKey;依我看,一个空的catch
块总是一个不好的建议。@GrzegorzJ我试过了,它正确地询问了我PIN码,完成签名后,wynBin的内容不是完整的签名文件,但只有不到1k的文件。可能需要做些什么来保存已签名的源文件。p7m格式谢谢@bartonjs,我将在下一步中尝试我从.NETCoreAPI服务调用这段代码,您的回答修复了引发的异常(无效类型)