我正在使用签署文档的SHA-1哈希的智能卡,并计算256字节的数字签名。
我正在使用此问题上发布的代码 - iText signing PDF using external signature with smart card。
我的问题是我收到了错误:"自签名申请以来,该文件已被更改或损坏,并且#34;。
我使用GUI创建哈希,然后将在卡上计算的带符号256字节发送到签名函数。
这是我的代码:
哈希创建filepath pdf文档的代码:
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash= sha1.ComputeHash(pdfBytes);
上述代码用于其中一个GUI函数中,以创建文档的哈希值
namespace EIDSmartCardSign
{
class PdfSignature
{
private string outputPdfPath;
private string certPath;
byte[] messageDigest;
private string inputPdfPath;
public PdfSignature(byte[] messageDigest, string inputPdfPath,string outputPdfPath)
{
this.messageDigest = messageDigest;
this.outputPdfPath = outputPdfPath;
this.inputPdfPath = inputPdfPath;
}
public void setCertPath(string certPath)
{
this.certPath = certPath;
}
public void signPdf()
{
X509Certificate2 cert = new X509Certificate2();
cert.Import(certPath); // .cer file certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1] ;
chain[0] = certParse.ReadCertificate(cert.RawData);
X509Certificate2[] certs;
PdfReader reader = new PdfReader(inputPdfPath);
FileStream fout = new FileStream(outputPdfPath,FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, fout, '\0',null,true);
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.SignatureCreator = "Me";
appearance.Reason = "Testing iText";
appearance.Location = "On my Laptop";
iTextSharp.text.Rectangle rec = new iTextSharp.text.Rectangle(50, 50, 250, 100);
appearance.SetVisibleSignature(rec, 1, "Signature");
IExternalSignature extSignature= new MyExternalSignature("SHA-1",this.messageDigest);
MakeSignature.SignDetached(appearance, extSignature, chain, null, null, null, 0, CryptoStandard.CMS);
//MakeSignature.
}
}
}
答案 0 :(得分:2)
您的哈希创建功能
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
SHA256 sha2 = SHA256.Create();
//sha2.ComputeHash
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath);
byte[] hash = null;
hash = sha1.ComputeHash(pdfBytes);
计算错误的哈希值。
查看信息安全堆栈交换中的this answer,特别是草图
显示要获取文档字节以进行签名,您不需要使用原始PDF,而是必须准备它以集成签名容器(添加签名字段,字段值和为签名容器保留的一些空间,以及字段可视化)然后哈希除了为签名容器保留的空间之外的所有字节。
此外,即使这个裸哈希也不是要签名的数据。而是构建一组属性,其中一个包含如上计算的文档哈希,其他包含对签名者证书等的引用,并且这些属性将被签名。
因此,改为做你已声称要做的事情:
我正在使用此问题上发布的代码 - iText signing PDF using external signature with smart card。
特别是那里的代码没有签署整个文件的散列,而是使用Sign
实现的方法IExternalSignature
接收的数据作为构造的参数如上所述。
OP在评论中说
对于由SHA1或RIPEMD-160生成的裸散列,我正在使用的卡需要20个字节的哈希值。
20个字节。根据你的问题文本,我假设使用了前一种算法。 (顺便说一下,上下文表明上下文不需要很高的安全级别,因为SHA1已经被淘汰或者在逐步淘汰这些用例的过程中。)
进一步创建此哈希需要哪些步骤在对pdf的内容进行哈希处理后?
只需在您引用的问题的IExternalSignature
实现中执行操作:
public virtual byte[] Sign(byte[] message) {
byte[] hash = null;
using (SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
{
hash = sha1.ComputeHash(message);
}
byte[] sig = MySC.GetSignature(hash);
return sig;
}
(很明显,您的智能卡签名例程可能不会被称为MySC.GetSignature
,您必须相应地更换该呼叫...)
由于您的卡片似乎期望裸露的哈希值与引用问题的OP卡相反,这应该适合您。
在哪里可以找到创建上述集成签名容器的示例?
在iText白皮书Digital Signatures for PDF Documents的示例中。
签名过程结束后,我有256字节的签名数据,3张.cer证书从卡中导出。
256字节签名数据听起来像是使用RSA或RSASSA-PSS生成的裸签名,密钥大小为2048位。
话虽如此,您需要在签名之前签署签名证书:在大多数相关的配置文件中,签名的属性必须包含对签名者证书的引用。在您引用的问题中的代码中,签署了签名者证书
public void StartTest(){
X509Certificate2 cert = new X509Certificate2();
cert.Import("cert.cer"); // certificate obtained from smart card
X509CertificateParser certParse = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { certParse.ReadCertificate(cert.RawData) };
[...]
MyMakeSignature.SignDetached(appearance, externalSignature, chain, null, null, tsc, 0, CryptoStandard.CADES);
特别是你必须在你的卡返回的那三张证书中找出正确的签名者证书;否则你可能会在引用的问题中遇到与OP相同的问题。
如果我拥有所有这些数据,如何创建Contents对象?
考虑到您对用例所说的话,很有可能您只需要使用问题iText signing PDF using external signature with smart card发布的代码并进行少量调整。