IText 7使用GOST3410签PDF报ECGOST3410错误,能否自定义写入签名字节
问题解答
结论
完全可以,你不需要依赖iText 7内置的签名算法支持,通过自定义外部签名的方式即可把自己生成的GOST3410签名内容写入PDF预留的签名空间。
你遇到的报错本质是iText 7内置的PdfPKCS7类没有预置ECGOST3410算法对应的OID映射,只要绕开iText内置的PKCS7生成逻辑,完全用BouncyCastle生成符合规范的CMS签名包再写入PDF即可解决问题。
具体实现步骤
- 第一步:预分配签名空间,获取待签名的PDF字节
调用PdfSigner的相关接口提前预留足够的签名存储长度(建议预留16384字节,足够容纳CMS签名包+证书链),通过preClose方法获取待计算哈希的PDF原文字节范围。 - 第二步:自行完成哈希计算与签名生成
完全使用BouncyCastle的API对待签名的PDF字节计算GOST3411摘要,再用GOST3410私钥生成符合CMS规范的签名包,这一步完全不调用iText的签名生成逻辑,自然不会触发算法不支持的异常。 - 第三步:将签名写入PDF预留位置
把生成的CMS签名字节数组补位到你之前预留的长度(长度不足的部分补0即可),再调用PdfSigner的闭合方法完成签名写入。
简化示例代码
fun customSignGost( pdfByteArray: ByteArray, certificates: Array<java.security.cert.Certificate>, privateKey: PrivateKey, contentResolver: ContentResolver, outUri: Uri ) { val provider = BouncyCastleProvider() Security.removeProvider(provider.name) Security.addProvider(provider) val reader = PdfReader(ByteArrayInputStream(pdfByteArray)) val outputStream = contentResolver.openOutputStream(outUri) val signer = PdfSigner(reader, outputStream, false) // 配置签名外观 signer.signatureAppearance.apply { reason = "study" setReuseAppearance(false) } // 预留16KB签名空间 val signatureSize = 16384 signer.setSignatureSize(signatureSize) // 预关闭,获取待签名的字节流 signer.preClose(hashMapOf<PdfName, Any?>().apply { put(PdfName.Contents, PdfSignature(PdfDictionary())) }) val dataToSign = signer.rangeStream.readBytes() // ===== 以下完全用BouncyCastle生成GOST CMS签名,不用iText的签名逻辑 ===== // 1. 计算GOST3411摘要 val digest = MessageDigest.getInstance("GOST3411", provider) val hash = digest.digest(dataToSign) // 2. 生成CMS签名包(此处用BC的CMSSignedDataGenerator按GOST签名标准实现即可) val cmsSignatureBytes = generateGostCmsSignature(hash, privateKey, certificates, provider) // 补位到预留长度 val signedContent = ByteArray(signatureSize) System.arraycopy(cmsSignatureBytes, 0, signedContent, 0, min(cmsSignatureBytes.size, signatureSize)) // 写入签名关闭文档 signer.close(signedContent) }
内容的提问来源于stack exchange,提问作者DormantPanda
相关产品推荐
相关产品推荐

