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

基于PDFBox跨服务器生成PDF数字签名,Adobe验证失败求助

问题描述

我对数字签名概念不太熟悉,目前遇到以下问题:
我有两台服务器:

  • Server A:接收上传的PDF文档,通过MessageDigest接口使用SHA-256算法生成文档哈希值,将该哈希值传给Server B生成数字签名,之后使用PDFBox将Server B返回的签名加盖到PDF文档上。
    详细流程:上传文档传入Server A的PDFBox代码,添加PDSignature,重写SignatureInterface的sign()方法,对方法传入的内容参数进行SHA-256哈希,将哈希值传给Server B生成签名,再将签名以byte[]形式返回至sign()方法,由PDFBox完成签名加盖。
  • Server B:通过BouncyCastleFipsProvider,使用SHA256WithRSA算法生成数字签名。

预期签名能在Adobe中被验证为有效,但打开生成的文档时,Adobe提示“文档已被更改或修改”。

要求流程必须为:Server A生成哈希值,Server B生成签名,Server A将签名加盖到PDF文档上。补充说明:曾尝试直接将PDFBox的内容字节传给Server B,生成的签名加盖后验证有效,但需求严格要求仅传递哈希值而非内容字节。

问题分析与解决方案

核心错误原因

你的处理方式存在关键错误:对PDFBox的sign()方法传入的待签内容做了重复哈希。

PDFBox的sign()方法传入的内容,已经是符合PDF签名规范的待签数据。而SHA256WithRSA算法本身包含「对输入数据做SHA-256哈希→用RSA私钥签名」的完整流程。你在Server A先对sign()的内容做一次SHA-256,再传给Server B用SHA256WithRSA签名,相当于对数据做了两次SHA-256哈希,导致最终签名的哈希值与Adobe验证时计算的哈希值不匹配,因此提示文档被修改。

修正方案(符合仅传哈希的需求)

1. Server A端处理

在sign()方法中,直接获取传入的待签内容字节数组,对其做一次SHA-256哈希(得到32字节的哈希值),然后将该哈希值传给Server B。

关键代码示例:

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] contentHash = digest.digest(content); // content为sign()方法传入的待签字节数组
// 将contentHash传给Server B

2. Server B端处理

不要使用SHA256WithRSA算法,而是直接用RSA私钥对传入的哈希值做裸签名(仅执行RSA加密,不预先做哈希),同时必须使用符合PDF规范的填充方式(推荐PKCS1Padding)。

关键代码示例(BouncyCastle FIPS环境):

// 假设已初始化RSA私钥对象RSAPrivateKey privateKey
Signature signature = Signature.getInstance("NONEwithRSA", "BCFIPS");
signature.initSign(privateKey);
signature.update(contentHash);
byte[] signedHash = signature.sign();
// 将signedHash返回给Server A

3. Server A端签名封装

将Server B返回的签名字节数组返回给sign()方法,同时确保创建PDSignature时正确设置签名算法属性:

PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setSignDate(Calendar.getInstance());
// 设置签名算法为SHA256WithRSA,确保Adobe验证时使用正确的逻辑
signature.setName("SHA256WithRSA");

方案可行性说明

PDF签名规范中,SHA256WithRSA的本质逻辑是:待签数据→SHA256哈希→RSA私钥加密(PKCS#1 v1.5填充)。修正后的流程完全匹配这一逻辑:Server A负责生成待签数据的SHA256哈希,Server B负责对哈希做RSA加密签名,最终Adobe验证时会重新计算待签数据的SHA256哈希,与解密签名得到的哈希值比对,匹配则验证通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 13:35:17