智能卡上的外部签名

External signature on a smart card

我正在使用智能卡对文档的 SHA-1 哈希进行签名,并计算 256 字节的数字签名。

我正在使用发布在这个问题上的代码 -

我的问题是出现错误:“应用签名后文档已被更改或损坏”。

我正在使用 GUI 创建哈希,然后将在卡上计算的带符号的 256 字节发送到签名函数。

这是我的代码:

文件路径 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, '[=11=]',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.
        }
    }
}

你的哈希创建函数

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,而是必须准备它以集成签名容器(添加签名字段,字段值有一些 space 为签名保留容器和字段可视化),然后散列除为签名容器保留的 space 之外的所有字节。

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

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

I am using the code posted on this question - .

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

更多详情

OP 在评论中说

The card I am working with expects a 20 bytes hash.

20 个字节对于 SHA1 或 RIPEMD-160 生成的裸散列来说是典型的。根据您的问题文本,我假设使用的是前一种算法。 (顺便说一句,这表明上下文不需要高安全级别,因为 SHA1 实际上已经被淘汰或正在被此类用例淘汰。)

What steps are needed to further create this hash After hashing the contents of the 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 卡相比,您的卡似乎需要一个裸散列值,这应该适合您。

Where can I find examples of creating the aformentioned integrated signature container?

在 iText 白皮书的示例中 Digital Signatures for PDF Documents

After the signature process, I have 256 bytes signed data, 3 .cer certificates exported from the card.

256 字节的签名数据听起来像是使用 2048 位密钥大小的 RSA 或 RSASSA-PSS 生成的裸签名。

也就是说,在 签名之前,您需要签名者证书:在大多数相关配置文件中,签名属性必须包含对签名者证书的引用。在您引用的问题代码中,此处处理了签名者证书

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);

特别是您必须在您的卡的这三个证书中识别正确的签名者证书returns;否则,您可能会遇到与引用问题中的 OP 相同的问题。

How do I create the Contents object when I have all of this data?

考虑到您所说的关于您的用例的内容,很有可能您真的只需要使用发布的问题代码 并稍作修改。