无法在 java 中显示 public 键以匹配 Adobe 中的键
can't get public key display in java to match those in Adobe
我使用证书签署 pdf。在 java 中,我处理 pdf 并提取证书详细信息。我将输出与 Adobe 中显示的该文档的证书详细信息进行比较。对于 SerialNumber,我能够使它们看起来相同,但对于 public 键却不行。任何帮助表示赞赏!
我调试了代码,尝试使用 Hex.toHexString 进行转换,在 Whosebug 中进行了搜索。但是运气不好
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();
}
}
}
在 Adobe 中,public 键显示如下:
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
非常感谢!
问题
区别在于 Adobe 提供完整 SubjectPublicKeyInfo
对象的十六进制转储(public 键,包括算法信息和键值),而您的代码仅转储 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
: . }
解决方案
解决方案很明显,而不是仅转储 public 关键数据
System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));
转储整个 SubjectPublicKeyInfo
对象:
System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getEncoded()));
我使用证书签署 pdf。在 java 中,我处理 pdf 并提取证书详细信息。我将输出与 Adobe 中显示的该文档的证书详细信息进行比较。对于 SerialNumber,我能够使它们看起来相同,但对于 public 键却不行。任何帮助表示赞赏!
我调试了代码,尝试使用 Hex.toHexString 进行转换,在 Whosebug 中进行了搜索。但是运气不好
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();
}
}
}
在 Adobe 中,public 键显示如下:
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
非常感谢!
问题
区别在于 Adobe 提供完整 SubjectPublicKeyInfo
对象的十六进制转储(public 键,包括算法信息和键值),而您的代码仅转储 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
: . }
解决方案
解决方案很明显,而不是仅转储 public 关键数据
System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getPublicKeyData().getEncoded()));
转储整个 SubjectPublicKeyInfo
对象:
System.out.println(Hex.toHexString(certificateHolder.getSubjectPublicKeyInfo().getEncoded()));