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

iText 8.0.X版本.NET环境PDF数字签名代码适配问题求助

适配iText8的.NET PDF数字签名代码修正方案

问题背景

我们过去数年一直使用iText7 7.X的.NET版本进行PDF数字签名,方案运行良好且目前仍可正常使用。但iText推出版本8后,现有代码与其不兼容,且找不到适配iText8的PDF签名示例,出现了两个编译错误。

原代码

public class PdfSigner
{
    IExternalSignature _privateSignature;
    X509Certificate[] _signChain;

    public PdfSigner(Stream privateKeyStream, string keyPassword)
    {
        var pks = new Pkcs12Store(privateKeyStream, keyPassword.ToCharArray());
        string alias = null;
        foreach (string tAlias in pks.Aliases)
        {
            if (pks.IsKeyEntry(tAlias))
            {
                alias = tAlias;
                break;
            }
        }
        var pk = pks.GetKey(alias).Key;
        var ce = pks.GetCertificateChain(alias);
        _signChain = new X509Certificate[ce.Length];
        for (int k = 0; k < ce.Length; ++k)
            _signChain[k] = ce[k].Certificate;
        _privateSignature = new PrivateKeySignature(pk, "SHA-512");
    }

    public void SignPDF(Stream input, Stream output, PDFSignParameters p)
    {
        PdfReader reader = new PdfReader(input);
        StampingProperties properties = new StampingProperties();
        var signer = new iText.Signatures.PdfSigner(reader, output, properties);

        PdfSignatureAppearance sap = signer.GetSignatureAppearance().SetReason(p.Reason).SetLocation(p.Location);
        if (p.Image != null)
        {                
            var img = iText.IO.Image.ImageDataFactory.Create(new BinaryReader(p.Image.Data).ReadBytes((int)p.Image.Data.Length));
            sap.SetSignatureGraphic(img);
            sap.SetLayer2Text(string.Empty);
            sap.SetPageRect(new iText.Kernel.Geom.Rectangle(p.Image.X, p.Image.Y, img.GetWidth() / p.Image.WidthRatio, img.GetHeight() / p.Image.HeigthRatio));
            sap.SetImage(img);
        }

        signer.SignDetached(_privateSignature, _signChain, null, null, null, 0, iText.Signatures.PdfSigner.CryptoStandard.CMS);
    }
}

编译错误

  • 错误1:构造函数最后一行_privateSignature = new PrivateKeySignature(pk, "SHA-512");

    cannot convert from 'Org.BouncyCastle.Crypto.AsymmetricKeyParameter' to 'iText.Commons.Bouncycastle.Crypto.IPrivateKey'

  • 错误2:SignPDF方法最后一行signer.SignDetached(_privateSignature, _signChain, null, null, null, 0, iText.Signatures.PdfSigner.CryptoStandard.CMS);

    cannot convert from 'Org.BouncyCastle.X509.X509Certificate[]' to 'iText.Commons.Bouncycastle.Cert.IX509Certificate[]'

解决方案

iText8核心变化是引入了BouncyCastle抽象层,不再直接依赖Org.BouncyCastle的原生类型,需要通过iText提供的适配器类转换类型。以下是修正后的完整代码:

using iText.Commons.Bouncycastle.Cert;
using iText.Commons.Bouncycastle.Crypto;
using iText.Signatures;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;
using iText.Commons.Bouncycastle;

public class PdfSigner
{
    IExternalSignature _privateSignature;
    IX509Certificate[] _signChain;

    public PdfSigner(Stream privateKeyStream, string keyPassword)
    {
        var pks = new Pkcs12Store(privateKeyStream, keyPassword.ToCharArray());
        string alias = null;
        foreach (string tAlias in pks.Aliases)
        {
            if (pks.IsKeyEntry(tAlias))
            {
                alias = tAlias;
                break;
            }
        }
        var pk = pks.GetKey(alias).Key;
        var ce = pks.GetCertificateChain(alias);
        
        // 转换证书链为iText抽象层类型
        _signChain = new IX509Certificate[ce.Length];
        for (int k = 0; k < ce.Length; ++k)
        {
            _signChain[k] = BouncyCastleFactoryCreator.GetFactory().CreateX509Certificate(ce[k].Certificate);
        }
        
        // 转换私钥为iText抽象层类型并创建签名实例
        var bcPrivateKey = BouncyCastleFactoryCreator.GetFactory().CreatePrivateKey(pk);
        _privateSignature = new PrivateKeySignature(bcPrivateKey, "SHA-512");
    }

    public void SignPDF(Stream input, Stream output, PDFSignParameters p)
    {
        PdfReader reader = new PdfReader(input);
        StampingProperties properties = new StampingProperties();
        var signer = new PdfSigner(reader, output, properties);

        PdfSignatureAppearance sap = signer.GetSignatureAppearance().SetReason(p.Reason).SetLocation(p.Location);
        if (p.Image != null)
        {                
            var img = iText.IO.Image.ImageDataFactory.Create(new BinaryReader(p.Image.Data).ReadBytes((int)p.Image.Data.Length));
            sap.SetSignatureGraphic(img);
            sap.SetLayer2Text(string.Empty);
            sap.SetPageRect(new iText.Kernel.Geom.Rectangle(p.Image.X, p.Image.Y, img.GetWidth() / p.Image.WidthRatio, img.GetHeight() / p.Image.HeigthRatio));
            sap.SetImage(img);
        }

        // 使用转换后的抽象层类型调用SignDetached
        signer.SignDetached(_privateSignature, _signChain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
    }
}

关键修正点

  1. 类型转换工具类:使用BouncyCastleFactoryCreator.GetFactory()获取iText的BouncyCastle抽象工厂,通过它将原生BouncyCastle类型转换为iText对应的抽象接口:
    • 私钥:CreatePrivateKey()将Org.BouncyCastle.Crypto.AsymmetricKeyParameter转为IPrivateKey
    • 证书:CreateX509Certificate()将Org.BouncyCastle.X509.X509Certificate转为IX509Certificate
  2. 字段类型更新:把X509Certificate[] _signChain改为IX509Certificate[] _signChain,匹配iText8的参数要求
  3. 命名空间简化:iText.Signatures.PdfSigner可以直接简化为PdfSigner(已引入对应命名空间)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:37:12