智能卡上的外部签名

时间:2017-05-15 08:13:29

标签: itext digital-signature smartcard

我正在使用签署文档的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.
        }
    }
}

1 个答案:

答案 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,特别是草图

sketch of how PDF signatures are integrated

显示要获取文档字节以进行签名,您不需要使用原始PDF,而是必须准备它以集成签名容器(添加签名字段,字段值和为签名容器保留的一些空间,以及字段可视化)然后哈希除了为签名容器保留的空间之外的所有字节。

此外,即使这个裸哈希也不是要签名的数据。而是构建一组属性,其中一个包含如上计算的文档哈希,其他包含对签名者证书等的引用,并且这些属性将被签名。

因此,改为做你已声称要做的事情:

  

我正在使用此问题上发布的代码 - iText signing PDF using external signature with smart card

特别是那里的代码没有签署整个文件的散列,而是使用Sign实现的方法IExternalSignature接收的数据作为构造的参数如上所述。

更多详情

OP在评论中说

  

我正在使用的卡需要20个字节的哈希值。

对于由SHA1或RIPEMD-160生成的裸散列,

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发布的代码并进行少量调整。