Itext 智能卡上的外部签名

Itext 智能卡上的外部签名,itext,digital-signature,smartcard,Itext,Digital Signature,Smartcard,我使用的智能卡对文档的SHA-1哈希进行签名,并计算256字节的数字签名 我正在使用这个问题上发布的代码- 我的问题是,我得到了一个错误:“自从应用签名以来,文档已被修改或损坏” 我正在使用GUI创建哈希,然后将卡上计算的签名256字节发送给签名函数 这是我的密码: filepath pdf文档的哈希创建代码: 上面的代码用于其中一个GUI函数来创建文档的哈希 namespace EIDSmartCardSign { class PdfSignature { pr

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

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

我的问题是,我得到了一个错误:“自从应用签名以来,文档已被修改或损坏”

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

这是我的密码:

filepath pdf文档的哈希创建代码:

上面的代码用于其中一个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.
        }
    }
}

您的散列创建函数

SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
SHA256 sha2 = SHA256.Create(); 
//sha2.ComputeHash 
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath); 
byte[] hash = null; 
hash = sha1.ComputeHash(pdfBytes);
计算错误的哈希值

看一看关于信息安全栈交换的,特别是草图

显示要获得要签名的文档字节,您不需要原始PDF,而是必须为集成签名容器做好准备(添加签名字段、字段值以及为签名容器保留的一些空间和字段可视化)然后散列除为签名容器保留的空间之外的所有字节

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

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

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

特别地,那里的代码没有对整个文件的散列进行签名,而是使用
IExternalSignature
实现的
sign
方法接收的数据作为参数,该参数如上所述构造

更多细节 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白皮书的示例中

在签名过程之后,我有256字节的签名数据,3.cer证书从卡中导出

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);
特别是,您必须在您的卡返回的三个证书中确定正确的签名者证书;否则,您可能会遇到与引用问题中OP相同的问题

当我拥有所有这些数据时,如何创建Contents对象


考虑到您所说的用例,很有可能您真的只需要对问题的代码稍加修改即可。

您的哈希创建函数

SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
SHA256 sha2 = SHA256.Create(); 
//sha2.ComputeHash 
byte[] pdfBytes = System.IO.File.ReadAllBytes(filePath); 
byte[] hash = null; 
hash = sha1.ComputeHash(pdfBytes);
计算错误的哈希值

看一看关于信息安全栈交换的,特别是草图

显示要获得要签名的文档字节,您不需要原始PDF,而是必须为集成签名容器做好准备(添加签名字段、字段值以及为签名容器保留的一些空间和字段可视化)然后散列除为签名容器保留的空间之外的所有字节

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

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

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

特别地,那里的代码没有对整个文件的散列进行签名,而是使用
IExternalSignature
实现的
sign
方法接收的数据作为参数,该参数如上所述构造

更多细节 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的卡片,这应该适合你

在哪里可以找到创建上述整数的示例