我正在尝试使用对 PDF 哈希进行签名的第三方 API 来对 PDF 文档进行签名。但是,当我使用签名验证工具测试签名的PDF时,遇到以下错误。
密钥大小为 256 的 RSA 算法对于签名创建来说太小了!
这里是该工具创建的详细错误报告。
在 Acrobat reader 中打开 PDF 时,我还可以在签名中看到未定义的错误。
这是我的流程概要:
这是内容签名者的代码,负责对内容进行签名:
private ContentSigner createContentSigner() {
return new ContentSigner() {
// This stream will be filled by the saveIncrementalForExternalSigning method. It holds the bytes of the PDF file.
private final ByteArrayOutputStream stream = new ByteArrayOutputStream();
@Override
public byte[] getSignature() {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Hash the bytes of the PDF file.
byte[] hashBytes = digest.digest(stream.toByteArray());
// The hash is encoded in Base64 as this is the format expected by the server.
String hash = Base64.getEncoder().encodeToString(hashBytes);
// Send the hash to the server and retrieve the signed hash.
// The response is Base64 encoded, so it needs to be decoded for the CMS signature.
return java.util.Base64.getDecoder().decode(webAPIService.getSignedHash(hash));
} catch (Exception e) {
throw new RuntimeException("Exception while signing", e);
}
}
@Override
public OutputStream getOutputStream() {
return stream;
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
// The algorithm identifier for SHA-256.
return new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.1.11"));
}
};
}
有没有一种方法可以在不向 API 维护者请求更大密钥大小的情况下签署该 PDF?
感谢您提供 PDF 示例。问题的原因是你的假设之一是错误的:
我将此哈希值发送到 API,API 使用 RSA 私钥对其进行签名。
不,API 使用 ECDSA 私钥对其进行签名!
因此,您在
ContentSigner
方法getAlgorithmIdentifier
中返回了错误的签名算法OID,因此您创建和嵌入的签名容器不一致,即标记为RSA签名的ECDSA签名。
eSig DSS 确定出现问题并报告“签名不完整!”
“密钥大小为 256 的 RSA 算法对于签名创建来说太小了!”消息是不同检查的输出,在当前情况下只是转移注意力。
如果您确实想要 RSA 签名,则必须与您的签名提供商联系并要求基于 RSA 密钥对的不同私钥和证书。
如果 ECDSA 也适合您,您只需从
getAlgorithmIdentifier
返回适当的 OID。
您可以验证该证书确实适用于 ECDSA 密钥对,只需在证书查看器(例如在 Adobe Acrobat 中)中检查它即可:
或者,您可以检查签名的 eSig DSS 诊断数据:
<Certificate Id=...>
...
<PublicKeySize>256</PublicKeySize>
<PublicKeyEncryptionAlgo>ECDSA</PublicKeyEncryptionAlgo>
PS:如果您想知道为什么 Adobe Acrobat 不报告错误但验证您的签名:Acrobat 的加密验证例程忽略
SignerInfo
中的签名算法 OID,它们根据 中的公钥确定要使用的算法证书和签名的其他详细信息。所以他们在这里将签名验证为 ECDSA 签名!
但遗憾的是,Acrobat 仍将
SignerInfo
中与签名算法 OID 关联的算法报告为签名算法:
因此,对 Acrobat 报告的加密结果要非常谨慎,它们仅部分可信。