首页 > 解决方案 > 无法在 Java 中显示公钥以匹配 Adob​​e 中的公钥

问题描述

我使用证书签署 pdf。在 java 中,我处理 pdf 并提取证书详细信息。我将输出与 Adob​​e 中显示的该文档的证书详细信息进行比较。对于序列号,我能够使它们看起来相同,但对于公钥则不行。任何帮助表示赞赏!

我调试了代码,尝试使用 Hex.toHexString 进行转换,在 stackoverflow 中搜索。但没有运气

System.out.println("signed? " + pdAcroForm.isSignaturesExist());
if (pdAcroForm.isSignaturesExist()) {
    PDSignatureField signatureField = (PDSignatureField) pdAcroForm.getField("signatureField");
    System.out.println("Name: " + signatureField.getSignature().getName());
    System.out.println("Name: " + signatureField.getSignature().getContactInfo());

    Security.addProvider(new BouncyCastleProvider());
    List<PDSignature> signatureDictionaries = document.getSignatureDictionaries();
    X509Certificate cert;
    Collection<X509Certificate> result = new HashSet<X509Certificate>();
    // Then we validate signatures one at the time.
    for (PDSignature signatureDictionary : signatureDictionaries) {
        // NOTE that this code currently supports only "adbe.pkcs7.detached", the most common signature /SubFilter anyway.
        byte[] signatureContent = signatureDictionary.getContents(new FileInputStream(signedFile));
        byte[] signedContent = signatureDictionary.getSignedContent(new FileInputStream(signedFile));
        // Now we construct a PKCS #7 or CMS.
        CMSProcessable cmsProcessableInputStream = new CMSProcessableByteArray(signedContent);
        try {
            CMSSignedData cmsSignedData = new CMSSignedData(cmsProcessableInputStream, signatureContent);
            Store<?> certStore = cmsSignedData.getCertificates();
            SignerInformationStore signers = cmsSignedData.getSignerInfos();
            Iterator<?> it = signers.getSigners().iterator();
            while (it.hasNext()) {
                SignerInformation signer = (SignerInformation) it.next();
                Collection<?> certCollection = certStore.getMatches(signer.getSID());
                Iterator<?> certIt = certCollection.iterator();
                while (certIt.hasNext()) {
                    X509CertificateHolder certificateHolder = (X509CertificateHolder) certIt.next();
                    System.out.println(certificateHolder.getSubjectPublicKeyInfo());
                    System.out.println(certificateHolder.getSubject());
                    System.out.println(certificateHolder.getIssuer());
                    System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));
                    // SerialNumber isi BigInteger in java and hex value in Windows/Mac/Adobe
                    System.out.println(certificateHolder.getSerialNumber().toString(16));

                    //result.add(new JcaX509CertificateConverter().getCertificate(certificateHolder));

                    /*PublicKey pkey = cert.getPublicKey();
                    System.out.println(pkey.toString());
                    System.out.println(cert.getNotBefore());
                    System.out.println(cert.getNotAfter());
                    System.out.println(cert.getSerialNumber());
                    System.out.println("issuer: " + cert.getIssuerDN());
                    System.out.println("subject:" + cert.getSubjectDN());
                    System.out.println("subject:" + cert.getSubjectDN());
                    System.out.println(cert.getSigAlgName());
                    */
                }
            }
        } catch (CMSException cmse) {
            cmse.printStackTrace();
        }
    }
}

在 Adob​​e 中,公钥显示如下:

30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 81 8D 00 30 81 89 02 81 81 00 A8 D1 52 E7 2F 58 E8 AE 62 F6 C5 77 2F 78 FA 21 46 51 B5 EF A3 A4 4C E2 EE BD A0 80 46 B6 1D 66 37 01 82 3F 65 5D 3B 0B E7 11 08 05 94 40 CF F2 EF CC BF D9 1A F6 6F 5B 0E 16 5F 85 C1 F3 D7 9D C8 C6 EF 41 09 7C A4 C3 D5 CA 1C F0 80 E6 3F BA D8 69 8F 67 67 70 FC EB 28 48 59 B3 4F F4 6B 38 E7 3B 94 0F 7C EF 2C 02 41 8A 35 A8 72 DE DE 78 DD ED 90 AD 5E 25 A3 71 DD 59 95 1C 57 24 C8 B5 02 03 01 00 01

在java中,使用

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));

SerialNumber 在 java 中是 BigInteger,在 Windows/Mac/Adobe 中是十六进制值,如下所示:

03818d0030818902818100a8d152e72f58e8ae62f6c5772f78fa214651b5efa3a44ce2eebda08046b61d663701823f655d3b0be71108059440cff2efccbfd91af66f5b0e165f85c1f3d79dc8c6ef41097ca4c3d5ca1cf080e63fbad8698f676770fceb284859b34ff46b38e73b940f7cef2c02418a35a872dede78dded90ad5e25a371dd59951c5724c8b50203010001

对于 SerialNumber 它工作正常。Java代码:

System.out.println(certificateHolder.getSerialNumber().toString(16));

Java 输出:

b27f048515c4f8e4

Adobe 输出:

00 B2 7F 04 85 15 C4 F8 E4

提前谢谢了!

标签: javapdfkeypublic

解决方案


问题

不同之处在于 Adob​​e 提供完整SubjectPublicKeyInfo对象的十六进制转储(包括算法信息和密钥值的公钥),而您的代码仅转储RSAPublicKey(密钥本身)。

通过查看相关对象的 ASN.1 定义和两个数组的 ASN.1 转储,您可以更清楚地看到这一点:

SubjectPublicKeyInfo

   SubjectPublicKeyInfo  ::=  SEQUENCE  {
        algorithm            AlgorithmIdentifier,
        subjectPublicKey     BIT STRING  }

Adobe的转储SubjectPublicKeyInfo

    <30 81 9F>
  0 159: SEQUENCE {
    <30 0D>
  3  13: . SEQUENCE {
    <06 09>
  5   9: . . OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
       : . . . (PKCS #1)
    <05 00>
 16   0: . . NULL
       : . . }
    <03 81 8D>
 18 141: . BIT STRING, encapsulates {
    <30 81 89>
 22 137: . . SEQUENCE {
    <02 81 81>
 25 129: . . . INTEGER    
       : . . . . 00 A8 D1 52 E7 2F 58 E8    ...R./X.
       : . . . . AE 62 F6 C5 77 2F 78 FA    .b..w/x.
       : . . . . 21 46 51 B5 EF A3 A4 4C    !FQ....L
       : . . . . E2 EE BD A0 80 46 B6 1D    .....F..
       : . . . . 66 37 01 82 3F 65 5D 3B    f7..?e];
       : . . . . 0B E7 11 08 05 94 40 CF    ......@.
       : . . . . F2 EF CC BF D9 1A F6 6F    .......o
       : . . . . 5B 0E 16 5F 85 C1 F3 D7    [.._....
       : . . . . 9D C8 C6 EF 41 09 7C A4    ....A.|.
       : . . . . C3 D5 CA 1C F0 80 E6 3F    .......?
       : . . . . BA D8 69 8F 67 67 70 FC    ..i.ggp.
       : . . . . EB 28 48 59 B3 4F F4 6B    .(HY.O.k
       : . . . . 38 E7 3B 94 0F 7C EF 2C    8.;..|.,
       : . . . . 02 41 8A 35 A8 72 DE DE    .A.5.r..
       : . . . . 78 DD ED 90 AD 5E 25 A3    x....^%.
       : . . . . 71 DD 59 95 1C 57 24 C8    q.Y..W$.
       : . . . . B5                         .
    <02 03>
157   3: . . . INTEGER 65537
       : . . . }
       : . . }
       : . }

RSAPublicKey

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}

你的转储RSAPublicKey

    <30 81 89>
  0 137: SEQUENCE {
    <02 81 81>
  3 129: . INTEGER    
       : . . 00 A8 D1 52 E7 2F 58 E8    ...R./X.
       : . . AE 62 F6 C5 77 2F 78 FA    .b..w/x.
       : . . 21 46 51 B5 EF A3 A4 4C    !FQ....L
       : . . E2 EE BD A0 80 46 B6 1D    .....F..
       : . . 66 37 01 82 3F 65 5D 3B    f7..?e];
       : . . 0B E7 11 08 05 94 40 CF    ......@.
       : . . F2 EF CC BF D9 1A F6 6F    .......o
       : . . 5B 0E 16 5F 85 C1 F3 D7    [.._....
       : . . 9D C8 C6 EF 41 09 7C A4    ....A.|.
       : . . C3 D5 CA 1C F0 80 E6 3F    .......?
       : . . BA D8 69 8F 67 67 70 FC    ..i.ggp.
       : . . EB 28 48 59 B3 4F F4 6B    .(HY.O.k
       : . . 38 E7 3B 94 0F 7C EF 2C    8.;..|.,
       : . . 02 41 8A 35 A8 72 DE DE    .A.5.r..
       : . . 78 DD ED 90 AD 5E 25 A3    x....^%.
       : . . 71 DD 59 95 1C 57 24 C8    q.Y..W$.
       : . . B5                         .
    <02 03>
135   3: . INTEGER 65537
       : . }

解决方案

解决方案很明显,而不是只转储公钥数据

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));

转储整个SubjectPublicKeyInfo对象:

System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getEncoded()));

推荐阅读