使用iText7批量签署PDF,避免多次输入智能卡PIN码
实现iText7单次输入PIN签署多个PDF文件
你当前的代码虽然手动配置了CSP参数,但因密钥上下文未被正确持久化,导致每次签名仍需重新验证PIN。核心解决思路是复用已通过PIN认证的证书私钥上下文,避免重复触发PIN验证。
修改后的代码
using namespace Org.BouncyCastle.Crypto using namespace Org.BouncyCastle.Pkcs using namespace Org.BouncyCastle.X509 using namespace System.Security.Cryptography.X509Certificates using namespace System.Security.Cryptography using namespace Org.BouncyCastle.Asn1 using namespace Org.BouncyCastle.Math using namespace System.Security.Cryptography.X509Certificates.RSACertificateExtensions using namespace System.Security.Cryptography.X509Certificates.DSACertificateExtensions using namespace System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions using namespace iText.Signatures using namespace iText.Signatures.IExternalSignature using namespace iText.Signatures.PdfSigner using namespace iText.Signatures.PdfSigner.CryptoStandard using namespace iText.Kernel.Pdf Import-Module "C:\Users\Dactal Sharp\Desktop\itext7module.1.0.34\IText7Module.psd1" # 获取文档签名证书 $certTemplate = Get-ChildItem Cert:\CurrentUser\My | Where-Object{$_.Extensions.EnhancedKeyUsages.FriendlyName -contains "Document Signing"} | Select-Object -First 1 # 输入PIN并创建带持久化私钥的证书实例 $pin = Read-Host -Prompt "Please Enter Smart Card PIN" -AsSecureString $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2( $certTemplate.RawData, $pin, [X509KeyStorageFlags]::PersistKeySet -bor [X509KeyStorageFlags]::Exportable ) # 转换为BouncyCastle格式证书链 $bccert = [Org.BouncyCastle.Security.DotNetUtilities]::FromX509Certificate($cert) [Org.BouncyCastle.X509.X509Certificate[]]$chain = $bccert # 创建复用私钥的签名实例 [IExternalSignature]$signature = [X509Certificate2Signature]::new($cert, [DigestAlgorithms]::SHA256) $stampingProperties = [StampingProperties]::new() $i = 0 foreach($file in Get-ChildItem "C:\Users\Dactal Sharp\Downloads\input test" | Where-Object{$_.BaseName -match "testunsig*"}){ $pdfReader = [PdfReader]::new($file.FullName) $outputPath = "C:\Users\Dactal Sharp\Downloads\test\test$i.pdf" $stream = [System.IO.FileStream]::new($outputPath, [System.IO.FileMode]::Create) $i++ $pdfSigner = [PdfSigner]::new($pdfReader, $stream, $stampingProperties.UseAppendMode()) [PdfSignatureAppearance]$appearance = $pdfSigner.GetSignatureAppearance() $appearance.SetRenderingMode([PdfSignatureAppearance+RenderingMode]::NAME_AND_DESCRIPTION) $appearance.SetCertificate($bccert) $appearance.setReasonCaption($null) $appearance.SetLocationCaption($null) $appearance.setReuseAppearance($true) $pdfSigner.SetFieldName("Signature2") $pdfSigner.SignDetached($signature, $chain, $null, $null, $null, 0, [iText.Signatures.PdfSigner+CryptoStandard]::CMS) # 清理资源 $stream.Close() $pdfReader.Close() }
关键改动说明
- 证书实例初始化:通过
X509Certificate2构造函数直接传入PIN,同时指定PersistKeySet标记,确保智能卡的密钥上下文被持久化到CSP中,后续签名无需重复验证PIN。 - 签名实例复用:使用
X509Certificate2Signature替代手动创建的AsymmetricAlgorithmSignature,该类会直接复用已加载的私钥上下文,避免每次签名重新初始化密钥对象。 - 资源清理:在循环中显式关闭文件流和PDF阅读器,避免资源泄漏。
补充提示
如果仍出现PIN弹窗,需检查智能卡驱动是否支持密钥上下文持久化,部分旧版本驱动可能强制每次操作验证PIN,此时需更新驱动或联系厂商确认配置。
内容的提问来源于stack exchange,提问作者JDactal
相关产品推荐
相关产品推荐

