PKCS#7中的消息摘要过程(PDF格式的签名)

xua*_*266 2 pdf message signature digest pkcs#7

验证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
Run Code Online (Sandbox Code Playgroud)

和DER编码:

A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70D010905310F170D3134303431333032353834315A302306092A864886F70D01090431160414194E0BA9C4B9A53D5E9E5B7B94D7DB42BEA4C28F307906092A864886F70D01090F316C306A300B060960864801650304012A300B0609608648016503040116300B0609608648016503040102300A06082A864886F70D0307300E06082A864886F70D030202020080300D06082A864886F70D0302020140300706052B0E030207300D06082A864886F70D0302020128

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

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

编辑:这是我要验证的PDF文件

mkl*_*mkl 5

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

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

你考虑过那个吗?

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

意味着它不是SignedAttrs值本身的散列,而是它的完整DER编码?不同之处在于SignedAttrs值隐式为0标记:

signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL
Run Code Online (Sandbox Code Playgroud)

其完整的DER编码则不然.该标准甚至明确说明了这一点:

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

(参见RFC 3852RFC 5652的 5.4节)

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

A081D8301806092A864886F70D010903310B06092A864886F70D010701301C06092A864886F70 ...

因此在计算摘要之前.

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

DigestInfo ::= SEQUENCE {
  digestAlgorithm DigestAlgorithmIdentifier,
  digest Digest }
Run Code Online (Sandbox Code Playgroud)

加成

即使在这些澄清之后也存在一些问题,参见 评论

我在完整的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()));
Run Code Online (Sandbox Code Playgroud)

应用于提供的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 
Run Code Online (Sandbox Code Playgroud)

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

  • 已签名的属性包含在带有“IMPLICIT [0]”标签(编码为 0xA0)的 PKCS#7 容器中。这意味着这个标签*替换*了`SET OF`标签(编码为0x31),根据`SignedAttributes`的定义,它是它的外部初始标签。对于*完整的 DER 编码*,您必须将其还原,即将前导 0xA0 再次替换为 0x31。 (2认同)