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

旧iText 2.1.7使用GOST-3411-2015-512等算法签名PDF无效求助

旧版iText 2.1.7搭配KalkanProvider实现GOST算法PDF签名无效问题排查

我在遗留项目中使用旧版iText 2.1.7,搭配KalkanProvider和BouncyCastle执行加密操作,需要使用GOST-3411-2015-512和ECGOST3411-2015-512算法签名PDF,但签名始终显示无效。

核心签名处理代码

def postProcessPdf(pdf: Array[Byte], os: OutputStream): Unit = {
    val reader = new PdfReader(pdf)
    val stamper = PdfStamper.createSignature(reader, os, '\u0000')          
    val appearance = stamper.getSignatureAppearance
    val signDate = Calendar.getInstance
    val pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
    pdfSignature.setDate(new PdfDate(signDate))
    pdfSignature.setCert(CryptUtils.cert.getEncoded)
    appearance.setCryptoDictionary(pdfSignature)
    appearance.setCrypto(null, CryptUtils.chain, null, PdfSignatureAppearance.WINCER_SIGNED)
    appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED)
    val estimatedSize = 8192
    val exc = new HashMap[PdfName, Int]()
    exc.put(PdfName.CONTENTS, estimatedSize * 2 + 2)
    appearance.preClose(exc)
    val data = appearance.getRangeStream()
    val digest = MessageDigest.getInstance("GOST-3411-2015-512","KALKAN")
    val dataBytes = IOUtils.toByteArray(data)
    digest.update(dataBytes)
    val appeareanceHash = digest.digest()
    val signature = Signature.getInstance("GOST3411-2015withECGOST3410-2015-512","KALKAN")
    signature.initSign(CryptUtils.privateKey)
    signature.update(appeareanceHash)
    val signedHash = signature.sign()
    val encodedPKCS7 = createCMS(signedHash, CryptUtils.cert,CryptUtils.privateKey)
    val paddedSig = new Array[Byte](estimatedSize)
    System.arraycopy(encodedPKCS7, 0, paddedSig, 0, encodedPKCS7.length)
    val dic = new PdfDictionary()
    dic.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true))
    appearance.close(dic)
}

已尝试的解决动作

  1. 已知旧版iText不支持目标算法,尝试修改PdfPKCS7.class,但问题未解决。
  2. 自定义CMS生成方法,通过Kalkan类实现签名封装,但签名依旧无效:
def createCMS(data: Array[Byte], cert: X509Certificate, key: PrivateKey): Array[Byte] = {
    val generator = new CMSSignedDataGenerator
    generator.addSigner(key, cert,"1.2.398.3.10.1.3.3")
    val chainStore = CertStore.getInstance("Collection",
    new CollectionCertStoreParameters(CryptUtils.chain.toSeq.asJava),
    KalkanProvider.PROVIDER_NAME)
    generator.addCertificatesAndCRLs(chainStore)
    val content = new CMSProcessableByteArray(data)
    val signedData = generator.generate(content, false, KalkanProvider.PROVIDER_NAME)
    signedData.getEncoded
}

问题分析与解决思路

1. 重复摘要导致哈希不匹配

你在签名流程中先对PDF签名范围数据做了GOST-3411-2015-512摘要,再将该摘要传给createCMS生成签名。但CMSSignedDataGenerator在生成签名时会自动对传入内容做摘要处理,相当于做了两次哈希运算,导致验证时哈希值不匹配。

修正方案:直接将原始签名范围数据传给createCMS,去掉手动摘要步骤:

// 替换原摘要+签名逻辑
val dataBytes = IOUtils.toByteArray(data)
val encodedPKCS7 = createCMS(dataBytes, CryptUtils.cert,CryptUtils.privateKey)

2. 签名算法OID不匹配

createCMS中指定的算法OID1.2.398.3.10.1.3.3需确认是否与GOST3411-2015withECGOST3410-2015-512对应。OID错误会导致验证工具无法识别签名算法,判定无效。

修正方案:直接使用算法名称而非OID,或确认KalkanProvider对应的正确OID:

generator.addSigner(key, cert, "GOST3411-2015withECGOST3410-2015-512")

3. iText签名字典参数缺失

旧版iText可能未自动填充GOST算法对应的签名字典属性,需手动补充关键参数:

// 确保SubFilter正确,添加摘要算法OID
pdfSignature.put(PdfName.SUBFILTER, PdfName.ADBE_PKCS7_DETACHED)
pdfSignature.put(new PdfName("DigestAlgorithm"), new PdfName("1.2.398.3.10.1.3.2")) // GOST-3411-2015-512的标准OID

4. 加密提供者兼容性问题

确保KalkanProvider与BouncyCastle版本兼容,并在代码中显式注册提供者:

Security.addProvider(new KalkanProvider())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:30:14