You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java提取PDF证书公钥与Adobe显示不一致问题求助

解决PDF签名公钥与Adobe显示不一致的问题

我帮你定位到问题啦!你遇到的公钥不匹配,本质是获取的公钥数据范围不一样,而序列号的差异是十六进制字符串的格式问题,下面给你具体的解决方案:

1. 公钥不匹配的原因与修复

Adobe显示的是完整的SubjectPublicKeyInfo结构,它包含两部分:

  • 算法标识符(开头的30 81 9F 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00,对应RSA算法的OID)
  • 实际的公钥密钥数据(你当前代码输出的内容)

而你现在的代码只提取了PublicKeyData(也就是第二部分),所以少了前面的算法标识符部分。

修改代码:

把你当前输出公钥的代码行:

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

替换为直接获取整个SubjectPublicKeyInfo的编码:

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

修改后输出的十六进制字符串就会和Adobe显示的完整公钥完全一致了。

2. 序列号前导零的问题修复

Java的BigInteger.toString(16)会自动省略开头的0,而Adobe显示的是证书序列号的原始字节序列的十六进制表示,所以会保留前导零。

两种修复方式:

方式一:用BouncyCastle直接获取序列号字节数组

System.out.println(Hex.toHexString(certificateHolder.getSerialNumber().toByteArray()));

这样输出的就是和Adobe一致的00b27f048515c4f8e4(大小写可以自己调整)。

方式二:用格式化补前导零

// 计算序列号的字节长度,转成十六进制字符串的长度(每个字节2位)
int hexLength = (certificateHolder.getSerialNumber().bitLength() + 7) / 8 * 2;
String serialHex = String.format("%0" + hexLength + "X", certificateHolder.getSerialNumber());
System.out.println(serialHex);

输出结果会是大写的00B27F048515C4F8E4,和Adobe的格式完全匹配。

验证修改效果

修改后再运行代码,你会发现:

  • 公钥的十六进制字符串和Adobe显示的完全一致
  • 序列号也会包含前导零,和Adobe的显示对齐

内容的提问来源于stack exchange,提问作者J S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:07:03