java - 无法在 Java 中显示公钥以匹配 Adobe 中的公钥
问题描述
我使用证书签署 pdf。在 java 中,我处理 pdf 并提取证书详细信息。我将输出与 Adobe 中显示的该文档的证书详细信息进行比较。对于序列号,我能够使它们看起来相同,但对于公钥则不行。任何帮助表示赞赏!
我调试了代码,尝试使用 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();
}
}
}
在 Adobe 中,公钥显示如下:
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
对象的十六进制转储(包括算法信息和密钥值的公钥),而您的代码仅转储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()));
推荐阅读
- python - 使用 Python 将大型 excel 文件导入 Mysql DB
- angular - Angular 8 Resolver - 如何从一个解析器获取数据作为其他解析器的输入?
- python - 对 hex 与 utf-8 编码感到困惑
- python - 使用请求从网页保存图像
- regex - 正则表达式删除第一个空行
- java - 无法使用 POSTMAN 删除(映射)我的数据库的对象
- amazon-web-services - “s3cmd get”仅用于更改的文件
- react-native - 执行 UI 块时引发异常:“parentNode”是必需的必需参数
- php - 我想在 jquery 克隆表行后清除字段
- android - 如何从片段内部调用父活动的方法