当前位置: 首页 > 知识库问答 >
问题:

使用带智能卡的外部签名的iText签名PDF

董翰池
2023-03-14

我已经玩弄了一段时间的iTextSharp 5.5.7,找不到正确的方法从智能卡为PDF制作一个有效的数字签名-Adobe Reader总是说它的签名人和未知,并且不能解码签名的DER数据。

我查看了Makesignature.cs代码以供参考,以及is的功能:

        Stream data = signatureAppearance.GetRangeStream(); 
        // gets the first hash
        byte[] hash = DigestAlgorithms.Digest(data, hashAlgorithm);
        // gets the second hash or is it not a hash at all ?
        byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, ocsp, crlBytes, sigtype);

然后,根据iExternalSignature.cs中的“Sign”方法

“@param message要进行散列和签名的邮件”

        // looks like externalSignature.Sign() should make another hash out of "sh"
        // and use this hash to compute a signature
        byte[] extSignature = externalSignature.Sign(sh); 

所以我把签字的程序理解为:

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

        // Reader and stamper
        PdfReader pdfReader = new PdfReader("original.pdf");
        Stream signedPdf = new FileStream("signed.pdf", FileMode.Create);
        PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0', null, false);

        // Appearance
        PdfSignatureAppearance appearance = stamper.SignatureAppearance;
        appearance.SignatureCreator = "Me";
        appearance.Reason = "Testing iText";
        appearance.Location = "On my Laptop";
        appearance.SignatureGraphic = Image.GetInstance("img.png"); // visual image
        appearance.SetVisibleSignature(new Rectangle(50, 50, 250, 100), pdfReader.NumberOfPages, "Signature");
        appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;

        // Timestamp
        TSAClientBouncyCastle tsc = new TSAClientBouncyCastle("http://ts.cartaodecidadao.pt/tsa/server", "", "");

        // Digital signature
        IExternalSignature externalSignature = new MyExternalSignature2("SHA-1");
        MyMakeSignature.SignDetached(appearance, externalSignature, chain, null, null, tsc, 0, CryptoStandard.CADES);

        stamper.Close();
}

外部签名实现(类MyExternalSignature2):

    class MyExternalSignature2 : IExternalSignature
{
    private String hashAlgorithm;
    private String encryptionAlgorithm;

    public MyExternalSignature2(String hashAlgorithm)
    {
        this.encryptionAlgorithm = "RSA";
        this.hashAlgorithm = DigestAlgorithms.GetDigest(DigestAlgorithms.GetAllowedDigests(hashAlgorithm));
    }

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

    public virtual String GetHashAlgorithm() {
        return hashAlgorithm;
    }

    public virtual String GetEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }
}

共有1个答案

范霄
2023-03-14

OP提供了一些签名文档样本,通过分析它们,我的最初回答显然是基于一个误解。

OP提供了三个由他的代码签名的PDF,最初是这两个:

  • ex_signer.pdf(用sha-1和cryptostandard.cades签名)
  • ex_signed_2.pdf(用sha-1和cryptostandard.cades签名)

通过对它们的检查,使用SHA1的iText CAdES签名的一个特点变得显而易见:对于CryptoStandard.CAdES,iText甚至对于SHA1也使用SigningCertificateV2属性,但规范建议使用SigningCertificateV2属性。为了防止这种特性受到干扰,OP提供了第三个文件

  • ex_signed_3.pdf(使用sha-256和CryptoStandard.cms签名)

然而,事实证明,这一怪癖并不是OP观察到的原因,Adobe Reader仍然报告密码库错误。

因此,回到分析。

由于签名算法是SHA1withRSA/2048和SHA256withRSA/2048,因此可以简单地使用来自相应证书的公钥解密内部签名值。

ex_signed.pdf成功,但ex_signed_2.pdf或ex_signed_3.pdf失败。

因此,我尝试使用第一个文件中的证书来解码第二个和第三个文件中的签名值,确实,这起作用了!因此第二个和第三个文件声称由与该替代证书相关联的私钥签名,但实际上是使用与前一个证书相关联的私钥签名的。

因此:问题1:文件2和3中的签名是用错误的私钥/智能卡上错误的应用程序签名的。

为了进一步分析该问题,我查看了使用身份验证证书成功解码的签名值:

2a8945abe450b2c1cd232249b8f811d352ad0d29
cc24acc848002df63733941e34437f8aef1c746c

ex_signed_3.pdf

45f8e451f8b9f39f0c1f59eea8b6308fba22176ac62ebd14bbf07e5407aed7e8

因此,对于SHA1有20个字节,对于SHA-256有32个字节。这正是散列值的大小,所以很可能这些只是裸散列值。

这是错误的,不过,XXXwithRSA签名应该包含一个加密的结构,该结构包含散列算法的OID和散列,用ASN.1表示法:

DigestInfo ::= SEQUENCE {
  digestAlgorithm DigestAlgorithmIdentifier, 
  digest Digest
  }

DigestAlgorithmIdentifier ::= AlgorithmIdentifier

Digest ::= OCTET STRING

第一个错误被描述为“BER译码错误”,

验证器试图将裸散列解释为使用BER编码的ASN.1序列,这显然是失败的。

因此:问题2:智能卡加密裸散列值,但必须加密封装该散列的digestinfo对象。

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

通过类似的东西

public virtual byte[] Sign(byte[] message)
{
    byte[] sig = MySC.GetSignature(message);

    return sig;
}
 类似资料:
  • 首先,虽然我关注StackOverflow已经有相当一段时间了,但这是我第一次发布一些东西,所以如果我做错了或者不按规则做的话,请随时为我指出正确的方向。 我正在开发一个PDF数字签名应用程序,使用iText5,它依赖于一个外部服务,在我准备好PDF签名后提供一个签名哈希。 如iText文档中所述,在第一阶段,我准备了PDF(在最终实现中,所有PDF都可能是多签名的,因此我使用追加模式),如下所示

  • 第一个选项是不可行的,因为PDF的签名没有时间戳(这是一个非常重要的必要条件),所以选择了第二个选项。 这是我们的代码,首先,我们得到签名外观,并计算散列: 在这一点上,我们有了文档的哈希代码。然后我们将散列发送到webservice,我们得到签名的散列代码。 按照mkl的建议,我遵循了这本书的4.3.3部分PDF文档的数字签名,现在我的代码如下: 第一部分,当我们计算散列时: 在第二部分,我们得

  • 签署修改的问题。 Iam使用DSC令牌传递文档哈希和签名哈希(外部签名)。 Iam收到错误,例如:“文档自签名以来已被更改或损坏”获取文档哈希:- 外部签名代码:- 签名附加代码:- 此签名附加后,但在打开签名的PDF时会出现如下图所示的错误。 PDF文件链接:https://drive.google.com/file/d/1qRT2CVgET8Ds1fu0b5psii3j8ytPKaLH/vie

  • Client=My application,Server=MSSP(移动签名服务提供商) 服务器仅对哈希值进行签名。 要签名数据: *Base64编码的SHA-384待签名数据摘要。(64个字符) *Base64编码的SHA-512待签名数据摘要。(88个字符) *要签名的Base64编码的DER编码的PKCS#1摘要信息。 注意:我使用MSSP(移动签名服务提供商)架构。对于SHA256算法,D

  • 我正在尝试使用iText(sharp,5.5.13版)创建自定义数字签名,用户可以从四个位置(顶部、底部、左侧和右侧)设置图像位置,如下所示: 刚度: 左: 顶部: 底部: 到目前为止,我试着处理签名的第0层,但我认为我做得不对,因为签名细节是在第2层设置的。 然而,这只是设置图像位置的初始草图。在下面的代码中,我加载图像并将其放入一个块中(想法取自此示例) 结果或多或少是预期的,但有两个问题:签

  • 作为我对客户机/服务器pdf签名研究的一部分,我测试了itext pdf延迟签名示例。不幸的是,我得到的合并空签名pdf和哈希值的pdf ie输出显示无效签名。 下面是我的代码片段 我正在使用pkcss11 usb令牌进行签名