pdf - PKCS#7 中的消息消化过程(PDF 签名)

标签 pdf message signature digest pkcs#7

问题出现在PDF文件的签名校验中。标准中说:

The result of the message digest calculation process depends on whether the signedAttrs field is present. When the field is absent, the result is just the message digest of the content as described above. When the field is present, however, the result is the message digest of the complete DER encoding of the SignedAttrs value contained in the signedAttrs field.

我解析了签名并得到了signedAttrs:

[0](4 elem)
   SEQUENCE(2 elem)
      OBJECT IDENTIFIER1.2.840.113549.1.9.3            // ContentType
      SET(1 elem)
        OBJECT IDENTIFIER1.2.840.113549.1.7.1
   SEQUENCE(2 elem)
      OBJECT IDENTIFIER1.2.840.113549.1.9.5            // SigningTime
      SET(1 elem)
        UTCTime2014-04-13 02:58:41 UTC
   SEQUENCE(2 elem)
      OBJECT IDENTIFIER1.2.840.113549.1.9.4            // MessageDigest
      SET(1 elem)
        OCTET STRING(20 byte) 194E0BA9C4B9A53D5E9E5B7B94D7DB42BEA4C28F
   SEQUENCE(2 elem)
      OBJECT IDENTIFIER1.2.840.113549.1.9.15
      SET(1 elem)
        SEQUENCE(8 elem)
          SEQUENCE(1 elem)
            OBJECT IDENTIFIER2.16.840.1.101.3.4.1.42
          SEQUENCE(1 elem)
            OBJECT IDENTIFIER2.16.840.1.101.3.4.1.22
          SEQUENCE(1 elem)
            OBJECT IDENTIFIER2.16.840.1.101.3.4.1.2
          SEQUENCE(1 elem)
            OBJECT IDENTIFIER1.2.840.113549.3.7
          SEQUENCE(2 elem)
            OBJECT IDENTIFIER1.2.840.113549.3.2
            INTEGER128
          SEQUENCE(2 elem)
            OBJECT IDENTIFIER1.2.840.113549.3.2
            INTEGER64
          SEQUENCE(1 elem)
            OBJECT IDENTIFIER1.3.14.3.2.7
          SEQUENCE(2 elem)
            OBJECT IDENTIFIER1.2.840.113549.3.2
            INTEGER40

和DER编码:

A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3134303431333032353834315A302306092A864886F70D01090431160414194E0BA9C4B9A53D5E9E5B7B94D7DB42BEA4C28F307906092A864886F70D01090F316C306A300B060960864801650304012A300B0609608648016503040116300B0609608648016503040102300A06082A864886F70D0307300E06082A864886F70D030202020080300D06082A864886F70D0302020140300706052B0E030207300D06082A864886F70D0302020128

我计算了它的摘要,并与加密摘要的解密结果进行了比较。但它失败了。

我应该计算整个 signedAttrs 字段或某些属性或其他任何内容的摘要?

编辑: 这是 PDF file我要验证

最佳答案

I calculated its digest and compared to the result of decryption of encrypted digest. But it failed.

I should calculate digest on entire signedAttrs field or on some Attributes or on anything else?

你考虑过吗

the message digest of the complete DER encoding of the SignedAttrs value contained in the signedAttrs field

暗示它不是SignedAttrs 值 本身的散列,而是它的完整 DER 编码?不同之处在于,SignedAttrs 值 是隐含的 0 标记:

signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL

其完整的 DER 编码则不是。该标准甚至明确表示:

A separate encoding of the signedAttrs field is performed for message digest calculation. The IMPLICIT [0] tag in the signedAttrs is not used for the DER encoding, rather an EXPLICIT SET OF tag is used. That is, the DER encoding of the EXPLICIT SET OF tag, rather than of the IMPLICIT [0] tag, MUST be included in the message digest calculation along with the length and content octets of the SignedAttributes value.

(cf. section 5.4 of both RFC 3852 and RFC 5652)

因此,你必须替换你的前导 0xA0

A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70...

相应地在计算摘要之前。

您是否进一步考虑过加密摘要的解密结果(我希望您谈论的是老式的 RSA 签名,否则解密没有帮助)是不是裸摘要,而是包裹在 DigestInfo 结构中的摘要?

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

添加

即使在这些澄清之后仍然存在一些问题,cf.评论

I calculated digest on the complete DER encoding but it was different from digest after decrypted

因此,这里有一些使用 Bouncy CaSTLe 的 Java 代码(可能没有最佳使用,我更习惯使用专有的加密库)来计算已签名属性的哈希值并从 RSA 签名中提取哈希值:

    // The CMS container
    CMSSignedData cms = new CMSSignedData(bytes);

    // Calculating the digest of the signed attributes
    SignerInformation signerInformation = (SignerInformation) (cms.getSignerInfos().getSigners().iterator().next());
    byte[] derSignedAttributes = signerInformation.getEncodedSignedAttributes();
    MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
    byte[] derSignedAttributesHash = sha1.digest(derSignedAttributes);
    
    // Retrieving the public key from the (single) certificate in the container
    X509CertificateHolder cert = (X509CertificateHolder) cms.getCertificates().getMatches(new Selector() {
        public boolean match(Object arg0) { return true; }
        public Object clone()             { return this; }
    }).iterator().next();
    X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(cert.getSubjectPublicKeyInfo().getEncoded());
    KeyFactory keyFactory = KeyFactory.getInstance(publicKeySpec.getFormat());
    Key key = keyFactory.generatePublic(publicKeySpec);

    // Decrypting the DigestInfo from the RSA signature
    Cipher asymmetricCipher = Cipher.getInstance("RSA", "BC");
    asymmetricCipher.init(Cipher.DECRYPT_MODE, key);
    byte[] digestInfo = asymmetricCipher.doFinal(signerInformation.getSignature());
    DigestInfo digestInfoObject = new DigestInfo(ASN1Sequence.getInstance(digestInfo));

    System.out.println("Signed Attributes: " + toHex(derSignedAttributes));
    System.out.println("Signed Attributes Hash: " + toHex(derSignedAttributesHash));
    System.out.println("DigestInfo: " + toHex(digestInfo));
    System.out.println("DigestInfo Hash: " + toHex(digestInfoObject.getDigest()));

应用于提供的 PDF 文件 signed_1047_ctsv.pdf 中的签名,输出为:

Signed Attributes: 31 81 D8 30 18 06 09 2A 86 48 86 F7 0D 01 09 03 31 0B 06 09 2A 86 48 86 F7 0D 01 07 01 30 1C 06 09 2A 86 48 86 F7 0D 01 09 05 31 0F 17 0D 31 34 30 34 31 33 30 32 35 38 34 31 5A 30 23 06 09 2A 86 48 86 F7 0D 01 09 04 31 16 04 14 19 4E 0B A9 C4 B9 A5 3D 5E 9E 5B 7B 94 D7 DB 42 BE A4 C2 8F 30 79 06 09 2A 86 48 86 F7 0D 01 09 0F 31 6C 30 6A 30 0B 06 09 60 86 48 01 65 03 04 01 2A 30 0B 06 09 60 86 48 01 65 03 04 01 16 30 0B 06 09 60 86 48 01 65 03 04 01 02 30 0A 06 08 2A 86 48 86 F7 0D 03 07 30 0E 06 08 2A 86 48 86 F7 0D 03 02 02 02 00 80 30 0D 06 08 2A 86 48 86 F7 0D 03 02 02 01 40 30 07 06 05 2B 0E 03 02 07 30 0D 06 08 2A 86 48 86 F7 0D 03 02 02 01 28 
Signed Attributes Hash: 7A 2D D8 92 B0 F4 AC 5A 2C 93 03 6B 06 94 74 62 71 D0 06 17 
DigestInfo: 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 7A 2D D8 92 B0 F4 AC 5A 2C 93 03 6B 06 94 74 62 71 D0 06 17 
DigestInfo Hash: 7A 2D D8 92 B0 F4 AC 5A 2C 93 03 6B 06 94 74 62 71 D0 06 17 

如您所见,值 Signed Attributes HashDigestInfo Hash 是相同的。

关于pdf - PKCS#7 中的消息消化过程(PDF 签名),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23425030/

相关文章:

linux - openssl 签名校验失败 : "RSA_padding_check_PKCS1_type_1:block type is not 01"

java - doInBackground 不起作用

ios - UrbanAirship 在 IOS 上通过 URL 推送

cxf - 如何配置wss4j签名验证器

ios - Swift:第二次打开消息 Controller

rabbitmq - 在 RabbitMQ 中哪个更昂贵,每个交换多个队列,还是多个交换和每个交换更少的队列?

c++ - C++删除器的签名是什么?

c# - 使用 html5 将 byte[] 显示为 pdf

java - PdfBox 文本提取无法正常工作

c# - Azure 网站和辅助角色 html 到 pdf