【问题标题】:Message-digesting process in PKCS#7 (signature in PDF)PKCS#7 中的消息消化过程(PDF 中的签名)
【发布时间】:2014-05-02 09:37:45
【问题描述】:

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

消息摘要计算过程的结果取决于 signedAttrs 字段是否存在。当该字段不存在时,结果只是如上所述的内容的消息摘要。但是,当该字段存在时,结果是包含在 signedAttrs 字段中的 SignedAttrs 值的完整 DER 编码的消息摘要。

我解析签名得到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 P>

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

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

编辑: 这是PDF file我要验证

【问题讨论】:

    标签: pdf message signature digest pkcs#7


    【解决方案1】:

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

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

    你考虑过吗

    signedAttrs 字段中包含的 SignedAttrs 值的完整 DER 编码的消息摘要

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

    signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL
    

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

    单独的编码 为消息摘要计算执行 signedAttrs 字段。 signedAttrs 中的隐式 [0] 标记不用于 DER 编码,而是使用 EXPLICIT SET OF 标签。也就是说,DER EXPLICIT SET OF 标签的编码,而不是 IMPLICIT [0] 标记,必须与消息摘要计算一起包含在消息摘要计算中 SignedAttributes 值的长度和内容八位字节。

    (参见RFC 3852RFC 5652 的第 5.4 节)

    因此,您必须替换前面的 0xA0

    A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70...

    因此在计算摘要之前。

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

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

    添加

    即使在进行了这些澄清之后,仍然存在一些问题,参见。评论

    我在完整的 DER 编码上计算了摘要,但它与解密后的摘要不同

    因此,这里有一些使用 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 的值是相同的。

    【讨论】:

    • 感谢您的回答。我不明白完整的 DER 编码是什么?可以举个例子吗?
    • 签名属性包含在带有IMPLICIT [0] 标签(编码为0xA0)的PKCS#7 容器中。这意味着此标记替换 SET OF 标记(编码为0x31),根据SignedAttributes 的定义,该标记将成为其外部初始标记。对于完整的 DER 编码,您必须恢复它,即将前导 0xA0 再次替换为 0x31。
    • 那么在这种情况下完整的DER编码是:3181d8301806092a864886f70d010903310b06092a864886f70d010701301c06092a864886f70d010905310f170d3134303431333032353834315a302306092a864886f70d01090431160414194e0ba9c4b9a53d5e9e5b7b94d7db42bea4c28f307906092a864886f70d01090f316c306a300b060960864801650304012a300b0609608648016503040116300b0609608648016503040102300a06082a864886f70d0307300e06082a864886f70d030202020080300d06082a864886f70d0302020140300706052b0e030207300d06082a864886f70d0302020128我会在上面计算摘要吗?
    • 你能成功验证它吗 - 是的,我可以,参考我的答案。
    • 因为我用十六进制散列值 - 这当然是错误的。我一直假设我们一直在使用十六进制写入,因为实际数据是二进制的。 您能否尝试在不使用 toHex() 的情况下打印此值? - 输出将难以阅读并且(如果粘贴在此处)不完整传输,因为在控制字符范围内有多个字节和一些更高的字节可能也没有字符表示。
    猜你喜欢
    • 2021-03-28
    • 1970-01-01
    • 2015-04-09
    • 1970-01-01
    • 2013-08-16
    • 2018-05-03
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    相关资源
    最近更新 更多