C#iText7对PDF进行签章

本文介绍了C#利用iText7库进行PDF电子签章的方法,包括RSA和SM2算法。针对签章过程中遇到的问题,如Adobe验章无效和签章追加,提供了解决方案,涉及签章图片透明处理、可追加签名属性及认证级别的设置。
摘要由CSDN通过智能技术生成

前言

本章主要说明C#如何使用iText7扩展外部签名,对PDF进行签章,支持RSA和SM2电子签章。
我是用USBKey加密设备生成的签名,相关核心Util也是不方便透漏,需要自己实现。非核心Util可以放出来供大家参考使用,不懂的可以问我。

实现目标

RSA的签章需要让Adobe认可,并且能够验证签章。
SM2的签章,需要Adobe认可,无需验证签章,验章可调用验章接口进行验章(Adobe不认SM2算法)。

代码

根据之前的文章《C# 使用iText7对PDF进行签章》我们需要重写IExternalSignatureContainer这个类。相关说明我建议参考iText7的源码说明。

using DZQZ.CryptBase;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DZQZ.SignBase
{
    class DZQZIExternalSignatureContainer : IExternalSignatureContainer
    {
        public string pwd = "";
        public Boolean flag = false; //是否签章成功 false:未签章 true:已制作签章
        private byte[] dzqz = null;
        public static int dzqzLen = 0;
        private static IntPtr hProv = new IntPtr(0);
        public static Boolean quitFlag = false; //退出KEY标识
        public static int userKeyType = 0; //2020年5月18日22:36:00 沈雪冰 add USBKEY标识
        public void ModifySigningDictionary(PdfDictionary signDic)
        {
            //if(!flag)
            {
                if(userKeyType == 2) //SM2
                {

                    //signDic.Put(PdfName.Type, new PdfName("Sig"));
                    signDic.Put(PdfName.Filter, new PdfName("GM.PKILite"));
                    signDic.Put(PdfName.SubFilter, new PdfName("GM.sm2pkcs7.detached"));
                    //signDic.Put(PdfName.Adbe_pkcs7_detached,new PdfName("Adbe_pkcs7_detached"));
                    //signDic.Put(PdfName.ad);
                    //signDic.Put(PdfName.Contents, (new PdfString(signBytes).setHexWriting(true)));
                }
                else //RSA 必须设置
                {
                    PdfName filter = PdfName.Adobe_PPKLite;
                    PdfName subFilter = PdfName.Adbe_pkcs7_detached;
                    signDic.Put(PdfName.Filter, filter);
                    signDic.Put(PdfName.SubFilter, subFilter);
                }
                
                
                //throw new NotImplementedException();
            }
        }
        //2020年5月14日11:47:26 沈雪冰 add 提高效率,不重复打开
        public static void CloseDev()
        {
            //关闭密码设备
            CryptoUtils.Crypt_Logout(hProv);
            CryptoUtils.Crypt_CloseDevice(hProv);
            //unsafe
            //{
            //    void* h = hProv.ToPointer();
            //}
            hProv = new IntPtr(0); //2020年6月2日15:06:59 沈雪冰 重新赋值
            quitFlag = true;
        }

        /**
			* 在外部准备好待签名数据TbsData,如果太大可考虑通过临时文件方式传递
			* */
        public byte[] Sign(Stream data)
        {
            if (!flag)
            {
                const int MAX_BUF = 4096;
                const int ERR_LEN = 1024;
                int ret = 0;
                int errLen = 0;
                if (data.CanRead && data.Length > 0)
                {
                    byte[] readBuffer = new byte[data.Length];
                    int count = data.Read(readBuffer, 0, readBuffer.Length);
                    //-------------1 对原文做SM3 hash---------------------------------------------------------------
                    // SM3 hash
                    byte[] hashSrc = new byte[64];
                    int hashSrcLen = 64;                 
                    byte[] pSignedData = new byte[MAX_BUF * 20];
                    int nSignedLen = MAX_BUF * 20;
                    StringBuilder err = new StringBuilder("", ERR_LEN);
                    int keyCertLen = MAX_BUF;
                    byte[] keyCert = new byte[MAX_BUF];

                    //打开密码设备--客户端

                    //IntPtr hProv = new IntPtr();
                    //StringBuilder container = new StringBuilder("", ERR_LEN);
                    try
                    {
                        //StringBuilder container = new StringBuilder(SaveValue.container,SaveValue.container.Length);
                        string container = SaveValue.container;
                        string provider = SaveValue.provider;  //"USK217_GM.dll";//"USK218_GM.dll";//"USK217_GM.dll";//"GM425SKF.dll"; //为空时,自动从注册表中查找遍历
                        uint dwProvType = SaveValue.dwProvType;           // in 加密设备的类型 0x802是国密 0是CSP
                        uint dwFlags = 0;
                        if (hProv.ToInt32() == 0 || quitFlag == true)
                        {
                            DZQZPdfUtil.log.Info("开始Crypt_OpenDevice...");
                            DZQZPdfUtil.log.Debug("container:" + container + " provider:" + provider + " dwProvType:" + dwProvType);

                            ret = CryptoUtils.Crypt_OpenDevice(ref hProv, container, provider, dwProvType, dwFlags);
                            quitFlag = false;
                            err.Clear();
                            CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);

                            if (ret != 0)
                            {
                                //Console.WriteLine("密码设备打开失败(客户端)--" + err.ToString());
                                Form1.curForm.listBoxResult.Items.Add("\t密码设备打开失败(客户端)--" + err.ToString());
                                CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                                throw new MyException("密码设备打开失败(客户端)--" + err.ToString());
                            }
                            //Console.WriteLine("打开密码设备(客户端)--" + err.ToString() + "    container=" + container.ToString() + ",  provider=" + provider);
                            Form1.curForm.listBoxResult.Items.Add("\t打开密码设备(客户端)--" + err.ToString() + "    container=" + container.ToString() + ",  provider=" + provider);
                            DZQZPdfUtil.log.Info("结束Crypt_OpenDevice...");
                            // string password = Form1.pwd;
                            string password = SaveValue.pwd;//"88888888";
                           
                            ret = CryptoUtils.Crypt_Login(hProv, password);//???????这个口令可考虑通过缓存来传递
                            err.Clear(); CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);

                            if (ret != 0)
                            {
                                //Console.WriteLine("验证口令--" + err.ToString());
                                Form1.curForm.listBoxResult.Items.Add("\t验证口令--" + err.ToString());
                                CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                                throw new MyException("验证口令--" + err.ToString());
                            }
                        }
                        DZQZPdfUtil.log.Info("开始对原文Crypt_Hash...");
                        //2020年5月18日11:26:20 沈雪冰 add 改用Crypt_api进行摘要
                        ret =CryptBase.CryptoUtils.Crypt_Hash(hProv, readBuffer, readBuffer.Length, CryptoUtils.CRYPT_ALGID_GB_SM3, hashSrc, ref hashSrcLen);
                        if(ret!=0)
                        {
                            err.Clear();
                            CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("对原数据Hash失败--" + err.ToString());
                        }
                        DZQZPdfUtil.log.Info("结束对原文Crypt_Hash...");

                        //RSA  签章
                        if (dwProvType==1) //2020年5月14日14:53:10 沈雪冰 add RSA签章
                        {
                            DZQZPdfUtil.log.Info("开始RSA签章...");
                            nSignedLen = readBuffer.Length + MAX_BUF * 4;
                            pSignedData = new byte[nSignedLen];
                            //ret = CryptoUtils.Crypt_Sign(hProv, readBuffer, readBuffer.Length, CryptoUtils.CRYPT_ALGID_SHA1_RSA_PKCS, 2, pSignedData, ref nSignedLen);
                            string signTime = "";
                            //ret = CryptoUtils.Crypt_SignData(hProv, readBuffer, readBuffer.Length, CryptoUtils.CRYPT_ALGID_SHA1_RSA_PKCS, signTime, 2, pSignedData, ref nSignedLen);
                            //2020年5月18日20:39:43 沈雪冰update 改为hash签名
                            byte[] sha1hashSrc = new byte[64];
                            int sha1hashSrcLen = 64;
                            ret = CryptBase.CryptoUtils.Crypt_Hash(hProv, readBuffer, readBuffer.Length, CryptoUtils.CRYPT_ALGID_GB_SHA1, sha1hashSrc, ref sha1hashSrcLen);
                            if (ret != 0)
                            {
                                err.Clear();
                                CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                                CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                                throw new MyException("对原数据Hash(sha1)失败--" + err.ToString());
                            }
                            ret = CryptoUtils.Crypt_SignData(hProv, sha1hashSrc, sha1hashSrcLen, CryptoUtils.CRYPT_ALGID_SHA1_RSA_PKCS, signTime, 0x13, pSignedData, ref nSignedLen);
                            err.Clear();
                            errLen = 0;
                            CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                            if (ret != 0)
                            {
                                //Console.WriteLine("验证口令--" + err.ToString());
                                //Form1.curForm.listBoxResult.Items.Add("\t签名失败!" + err.ToString());
                                CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                                throw new MyException("UsbKey签名失败![ " + ret.ToString() + " ]" + err.ToString());
                            }
                            //FileStream signFile = new FileStream("signFile", FileMode.Create);
                            //signFile.Write(pSignedData, 0, nSignedLen);
                            //signFile.Close();
                            //RSA签章成功
                            DZQZPdfUtil.log.Info("结束RSA签章...");
                            flag = true;
                            //dzqz = pSignedData;  
                            //dzqzLen = dzqz.Length;
                            dzqz = new byte[nSignedLen];  //2020年6月3日14:36:46  沈雪冰 修改 dzqz = pSignedData;这种方式不是复制,后边一堆0 导致文件很大
                            Array.Copy(pSignedData, dzqz, nSignedLen);
                            dzqzLen = nSignedLen;
                            return dzqz;
                        }
                        //-------------2 读取证书---------------------------------------------------------------
                        //从usbkey中读取签名者证书。
                        ret = CryptoUtils.Crypt_ReadCert(hProv, 2, keyCert, ref keyCertLen);
                        err.Clear(); CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                        //Console.WriteLine("读取USBKEY证书:" + err.ToString());
                        if (ret != 0)
                        {
                            //Console.WriteLine("读取USBKEY证书失败:" + err.ToString());
                            Form1.curForm.listBoxResult.Items.Add("\t读取USBKEY证书失败:" + err.ToString());
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("读取USBKEY证书失败:" + err.ToString());
                        }
                        err.Clear();
                        CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                        Form1.curForm.listBoxResult.Items.Add("\t读取USBKEY证书(长度):" + keyCertLen.ToString());

                        /*
                        //-------------3 获取电子印章结构体---------------------------------------------------------------
                        pSignedData = SaveValue.sealData;
                        nSignedLen = SaveValue.sealDataLen;
                        if (nSignedLen == SaveValue.SEAL_LEN)
                        {
                            ret = CryptoUtils.Crypt_EPS_ReadESealData(hProv, CryptoUtils.EPST_SKEKY_IDX_EDK, CryptoUtils.SGD_SM4_ECB, pSignedData, ref nSignedLen);
                            err.Clear();
                            CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                            if (ret != 0)
                            {
                                throw new MyException("获取usbkey中电子印章错误! [ " + ret.ToString() + " ] " + err.ToString());
                            }
                            SaveValue.sealData = pSignedData;
                            SaveValue.sealDataLen = nSignedLen;
                        }*/
                        /*
                        byte[] esData = new byte[MAX_BUF * 20];      // , 输入 / 输出 电子印章。如果置为NULL,表示只获取该电子印章的字节数。如果不为NULL, 需分配足够的空间长度存储电子印章。
                        int esData_len = MAX_BUF * 20; //   输入 / 输出 输入空间长度,该长度需要确保能存储返回结果。输出电子印章的字节数。如果没有附加的电子印章,返回0。

                        {// 需要解析公安加密信息文件获取电子印章结构体
                         //-----------7 拆分公安下发加密文件,如果有附加在后的电子印章,同时输出该电子印章。-----------------------------------------------------------------
                         // byte[]   *efFromGA,                输入 公安下发加密文件与附加在后的电子印章(可能没有电子印章)
                         // int             efFromGA_len,             输入 公安下发加密文件字节数与附加在后的电子印章字节数(可能为0)的和
                            byte[] deviceCode = new byte[256];        // , 输出 设备编码
                            int deviceCode_len = 256;   // , 输出 设备编码长度
                            byte[] yzmc = new byte[256];              // , 输出 印章名称
                            int yzmc_len = 256;         // , 输出 印章名称长度
                            byte[] yzbm = new byte[256];              // , 输出 印章编码
                            int yzbm_len = 256;         // , 输出 印章编码长度
                            byte[] yzzzdwbm = new byte[256];          // , 输出 印章制作单位编码
                            int yzzzdwbm_len = 256;     // , 输出 印章制作单位编码长度
                            byte[] yzlxdm = new byte[256];            // , 输出 印章类型代码
                            int yzlxdm_len = 256;       // , 输出 印章类型代码长度
                            byte[] jbr_xm = new byte[256];            // , 输出 经办人姓名
                            int jbr_xm_len = 256;       // , 输出 经办人姓名长度
                            byte[] jbr_zjlx = new byte[256];          // , 输出 经办人证件类型
                            int jbr_zjlx_len = 256;     // , 输出 经办人证件类型长度
                            byte[] jbr_zjhm = new byte[256];          // , 输出 经办人证件号码
                            int jbr_zjhm_len = 256;     // , 输出 经办人证件号码长度
                            byte[] zzrq = new byte[256];              // , 输出 制作日期
                            int zzrq_len = 256;         // , 输出 制作日期长度
                            byte[] yzsydw_dwmc = new byte[256];       // , 输出 印章使用单位_单位名称
                            int yzsydw_dwmc_len = 256;  // , 输出 印章使用单位_单位名称长度
                            byte[] yzsydw_dwssmzwzmc = new byte[256]; // , 输出 印章使用单位_单位少数民族文字名称
                            int yzsydw_dwssmzwzmc_len = 256;// , 输出 印章使用单位_单位少数民族文字名称长度
                            byte[] yzsydw_dwywmc = new byte[256];     // , 输出 印章使用单位_单位英文名称
                            int yzsydw_dwywmc_len = 256;// , 输出 印章使用单位_单位英文名称长度
                            byte[] yzzzdw_dwmc = new byte[256];       // , 输出 印章制作单位_单位名称
                            int yzzzdw_dwmc_len = 256;  // , 输出 印章制作单位_单位名称长度
                            byte[] yzzzdw_dwssmzwzmc = new byte[256]; // , 输出 印章制作单位_单位少数民族文字名称
                            int yzzzdw_dwssmzwzmc_len = 256;// , 输出 印章制作单位_单位少数民族文字名称长度
                            byte[] yzzzdw_dwywmc = new byte[256];     // , 输出 印章制作单位_单位英文名称
                            int yzzzdw_dwywmc_len = 256;// , 输出 印章制作单位_单位英文名称长度
                            byte[] yzsydw_tyshxydm = new byte[256];   // , 输出 印章使用单位_统一社会信用代码
                            int yzsydw_tyshxydm_len = 256;// , 输出 印章使用单位_统一社会信用代码长度


                            ret = DZQZCltUtil.EncFilesplit(pSignedData, nSignedLen, deviceCode, ref deviceCode_len, yzmc, ref yzmc_len, yzbm, ref yzbm_len, yzzzdwbm, ref yzzzdwbm_len, yzlxdm, ref yzlxdm_len, jbr_xm, ref jbr_xm_len, jbr_zjlx, ref jbr_zjlx_len, jbr_zjhm, ref jbr_zjhm_len, zzrq, ref zzrq_len, yzsydw_dwmc, ref yzsydw_dwmc_len, yzsydw_dwssmzwzmc, ref yzsydw_dwssmzwzmc_len, yzsydw_dwywmc, ref yzsydw_dwywmc_len, yzzzdw_dwmc, ref yzzzdw_dwmc_len, yzzzdw_dwssmzwzmc, ref yzzzdw_dwssmzwzmc_len, yzzzdw_dwywmc, ref yzzzdw_dwywmc_len, yzsydw_tyshxydm, ref yzsydw_tyshxydm_len, esData, ref esData_len);

                            if (ret == 0)
                            {
                                err.Clear(); CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                                Form1.curForm.listBoxResult.Items.Add("\t解析信息文件,获取电子印章测试成功!" + err.ToString());
                                //cout << " 解析文件,获取印章结构体 " << "--" << Err2Str(ret, err, ERR_LEN) << endl;
                                //FileStream fileStream = new FileStream("D://PDF//WindowsFormsiText7//WindowsFormsiText7//bin//x86//Debug//解析File取得印章结构体.dat",FileMode.OpenOrCreate);
                                //fileStream.Write(esData, 0, esData_len);
                                //fileStream.Close();
                                /*							sealStruct = new byte[esData_len];
														sealStruct = esData.Take<byte>(esData_len).ToArray();
														sealStructLen = esData_len;* /
                            }
                            else
                            {
                                err.Clear();
                                CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                                Form1.curForm.listBoxResult.Items.Add("\t解析信息文件,获取电子印章测试失败![ " + ret.ToString() + " ]" + err.ToString());
                                //sealStructLen = 0;
                                throw new MyException("UsbKey中无法获取电子印章![ " + ret.ToString() + " ]" + err.ToString());
                            }
                        }*/

                        //-------------------解析印章结构体比较证书列表,查看证书盖章用户证书是否在列表中---------------
                        int cipher_choice1 = 0;
                        int format_choice1 = 0;
                        byte[] rootCert1 = new byte[MAX_BUF];
                        int rootCertLen1 = MAX_BUF;
                        byte[] head_ID1 = new byte[32];
                        int head_IDLen1 = 32;
                        int head_version1 = 0;
                        byte[] head_Vid1 = new byte[512];
                        int head_VidLen1 = 512;
                        byte[] out_esID1 = new byte[32];
                        int out_esIDLen1 = 32;
                        int pro_type1 = MAX_BUF;
                        byte[] pro_name1 = new byte[512];
                        int pro_nameLen1 = 512;
                        int pro_certListType1 = MAX_BUF;
                        byte[] pro_certList1 = new byte[MAX_BUF*4];
                        int pro_certListLen1 = MAX_BUF*4;
                        byte[] pro_createDate1 = new byte[32];
                        int pro_createDateLen1 = 32;
                        byte[] pro_validStart1 = new byte[32];
                        int pro_validStartLen1 = 32;
                        byte[] pro_validEnd1 = new byte[32];
                        int pro_validEndLen1 = 32;
                        byte[] pic_type1 = new byte[32];
                        int pic_typeLen1 = 32;
                        byte[] pic_data1 = new byte[MAX_BUF * 8];
                        int pic_dataLen1 = MAX_BUF * 8;
                        int pic_width1 = 512;
                        int pic_height1 = 512;
                        byte[] cust_smuInfo1 = new byte[512];
                        int cust_smuInfoLen1 = 512;
                        int cust_smuInfoFF1 = 32;
                        byte[] cust_shuEthnicMinoritiesName1 = new byte[512];
                        int cust_shuEthnicMinoritiesNameLen1 = 512;
                        int cust_shuEthnicMinoritiesNameFF1 = 32;
                        byte[] cust_shuEnglishName1 = new byte[512];
                        int cust_shuEnglishNameLen1 = 32;
                        int cust_shuEnglishNameFF1 = 32;

                        /*ret = DZQZCltUtil.yzParseEx(esData, esData_len, ref cipher_choice1, ref format_choice1, rootCert1, ref rootCertLen1, head_ID1, ref head_IDLen1, ref head_version1, head_Vid1, ref head_VidLen1, out_esID1, ref out_esIDLen1,
                                ref pro_type1, pro_name1, ref pro_nameLen1, ref pro_certListType1, pro_certList1,
                                ref pro_certListLen1, pro_createDate1, ref pro_createDateLen1, pro_validStart1, ref pro_validStartLen1, pro_validEnd1, ref pro_validEndLen1, pic_type1, ref pic_typeLen1, pic_data1, ref pic_dataLen1, ref pic_width1, ref pic_height1, cust_smuInfo1, ref cust_smuInfoLen1,
                                ref cust_smuInfoFF1, cust_shuEthnicMinoritiesName1, ref cust_shuEthnicMinoritiesNameLen1, ref cust_shuEthnicMinoritiesNameFF1, cust_shuEnglishName1, ref cust_shuEnglishNameLen1, ref cust_shuEnglishNameFF1
                                );*/
                        ret = DZQZCltUtil.yzParseEx(SaveValue.exSealData, SaveValue.exSealData.Length, ref cipher_choice1, ref format_choice1, rootCert1, ref rootCertLen1, head_ID1, ref head_IDLen1, ref head_version1, head_Vid1, ref head_VidLen1, out_esID1, ref out_esIDLen1,
                                ref pro_type1, pro_name1, ref pro_nameLen1, ref pro_certListType1, pro_certList1,
                                ref pro_certListLen1, pro_createDate1, ref pro_createDateLen1, pro_validStart1, ref pro_validStartLen1, pro_validEnd1, ref pro_validEndLen1, pic_type1, ref pic_typeLen1, pic_data1, ref pic_dataLen1, ref pic_width1, ref pic_height1, cust_smuInfo1, ref cust_smuInfoLen1,
                                ref cust_smuInfoFF1, cust_shuEthnicMinoritiesName1, ref cust_shuEthnicMinoritiesNameLen1, ref cust_shuEthnicMinoritiesNameFF1, cust_shuEnglishName1, ref cust_shuEnglishNameLen1, ref cust_shuEnglishNameFF1
                                );
                        if (ret == 0)
                        {
                            //Form1.curForm.listBoxResult.Items.Add("\t解析印章结构体成功!  ret = " + ret.ToString());
                        }
                        else
                        {
                            //Form1.curForm.listBoxResult.Items.Add("\t验证电子印章结构错误!返回值 = " + ret.ToString());
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("验证电子印章结构错误![ " + ret.ToString() + "]" + err.ToString());
                            //return false;
                        }
                     
                        //2020年6月15日09:45:31 沈雪冰 add base64 那样还是有BUG,换成比较16进制字符串是不会有问题的
                        string keyCertHexStr = StringUtil.ByteToHexStr(keyCert,keyCertLen);
                        string pro_certList1HexStr = StringUtil.ByteToHexStr(pro_certList1,pro_certListLen1);

                        //----------------------------判断是否在列表中
                        if (!pro_certList1HexStr.Contains(keyCertHexStr))
                        {
                            DZQZPdfUtil.log.Info("pro_certList1Base64:"+ pro_certList1HexStr);
                            DZQZPdfUtil.log.Info("keyCertbase64:"+ keyCertHexStr);
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("当前Usbkey不能盖章!");
                        }

                        //-------------4 制作待签章数据---------------------------------------------------------------

                        int version = 4;                        // , 输入 签章数据格式版本号,数值为4,代表当前版本为v4;
                        string GeneralizedTime = "";               // , 输入 电子签章对应的时间,类型为GeneralizedTime;
                        GeneralizedTime = DateTime.Now.ToString("u").Replace("-", "").Replace(":", "").Replace(" ", "").Replace("Z", "");// "20190701023030";
                        int GeneralizedTimeLen = GeneralizedTime.Length;            // , 输入 电子签章对应的时间的字节数,必须为14,格式为 YYYYMMDDHHMMSS
                        byte[] propertyInfo = new byte[] { 80, 68, 70 }; //PDF                // , 输入 原文数据的属性,如文档ID、日期、段落、原文内容的字节数、知识信息、签名保护范围等,具体结构可自行定义;
                        int propertyInfoLen = propertyInfo.Length;                // , 输入 原文数据的属性的字节数;

                        byte[] extDatas = new byte[32];             // , 输入 厂商自定义数据,当前无数据,无数据时置值NULL;
                        int extDatasLen = 0;                    // , 输入 厂商自定义数据的字节数,当前无数据,无数据时置值0;
                        byte[] tbsData = new byte[1024 * 50];                   // , 输出 制作成功的待电子签章数据;
                        int tbsDataLen = 1024 * 50;                //   输入 / 输出 输入out空间长度,该长度需要确保能存储返回结果。输出制作成功的待电子签章数据的字节数。

                        //ret = qzMakeTbsData(version, pro_certList, pro_certListLen, GeneralizedTime, GeneralizedTimeLen, (byte[]*)strResult, lenResult, propertyInfo, propertyInfoLen,NULL, 0, outS, ref outS_len);
                        //ret = DZQZCltUtil.QzMakeTbsData(version, esData, esData_len, GeneralizedTime, GeneralizedTimeLen, hashSrc, hashSrcLen, propertyInfo, propertyInfoLen, extDatas, extDatasLen, tbsData, ref tbsDataLen);
                        ret = DZQZCltUtil.QzMakeTbsData(version, SaveValue.exSealData, SaveValue.exSealData.Length, GeneralizedTime, GeneralizedTimeLen, hashSrc, hashSrcLen, propertyInfo, propertyInfoLen, extDatas, extDatasLen, tbsData, ref tbsDataLen);
                        if (ret != 0)
                        {
                            //Console.WriteLine("验证口令--" + err.ToString());
                            //Form1.curForm.listBoxResult.Items.Add("\t制作待签章数据失败!" + err.ToString());
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("制作待签章数据失败![ " + ret.ToString() + " ]" + err.ToString());
                        }

                        //-------------4 对待签数据签名---------------------------------------------------------------
                        ret = CryptoUtils.Crypt_Sign(hProv, tbsData, tbsDataLen, CryptoUtils.CRYPT_ALGID_SM2_SM3, 2, pSignedData, ref nSignedLen);
                        err.Clear();
                        errLen = 0;
                        CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                        if (ret != 0)
                        {
                            //Console.WriteLine("验证口令--" + err.ToString());
                            //Form1.curForm.listBoxResult.Items.Add("\t签名失败!" + err.ToString());
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("UsbKey签名失败![ " + ret.ToString() + " ]" + err.ToString());
                        }

                        //-------------4	制作电子签章---------------------------------------------------------------
                        int format_choice2 = 0x10;         // , 输入 格式选择,默认使用SM2算法国密标准格式对算法和签名数据进行编码,对应的默认值为0,0x10为国办标准;
                        int signalgid = 27;                    // , 输入 签名算法标识,目前只支持SM2搭配SM3,对应值为十进制整数27;
                        byte[] timeStamp = new byte[MAX_BUF];       // , 输入 对签名值的时间戳,无数据时置值NULL;
                        int timeStamplen = 0;                  // , 输入 时间戳的字节数,无数据时置值0;//无时间戳
                        byte[] out2 = new byte[MAX_BUF * 40];  // , 输出 制作成功的电子签章
                        int outlen = MAX_BUF * 40;             //   输入 / 输出 输入out空间长度,该长度需要确保能存储返回结果。输出制作成功的电子签章字节数。

                        //strcpy((char*)timeStamp, NULL);

                        ret = DZQZCltUtil.QzMake(format_choice2, tbsData, tbsDataLen, keyCert, keyCertLen, signalgid, pSignedData, nSignedLen, timeStamp, timeStamplen, out2, ref outlen);
                        //printf("制作签章结构体 qzMake  outlen = %d", outlen);
                        //err.Clear();
                        //CryptoUtils.Crypt_GetErrorMsg(ret, err, ref errLen);
                        //Form1.curForm.listBoxResult.Items.Add("\t制作签章结构体 [ " + ret.ToString() + " ] 长度 = " + outlen.ToString());
                        if (ret != 0)
                        {
                            //Console.WriteLine("验证口令--" + err.ToString());
                            //Form1.curForm.listBoxResult.Items.Add("\t签章失败!" + err.ToString());
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                            throw new MyException("签章失败![ " + ret.ToString() + " ]" + err.ToString());
                        }
                        dzqz = out2.Take<byte>(outlen).ToArray(); //将签章结果保存
                        dzqzLen = outlen;
                        flag = true;
                        //return out2.Take<byte>(outlen).ToArray();
                        return dzqz;
                    }
                    catch (Exception e)
                    {
                        CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                        throw new MyException(e.Message.ToString());
                    }
                    finally
                    {
                        if (quitFlag == true) //2020年6月2日14:59:06 沈雪冰 update
                        {
                            //关闭密码设备
                            //CryptoUtils.Crypt_Logout(hProv);
                            //CryptoUtils.Crypt_CloseDevice(hProv);
                            CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                        }
                    }
                }
                else
                {
                    CloseDev(); //2020年6月2日14:56:23 沈雪冰 add
                    throw new MyException("签名数据不可用!");
                    //return null;
                }
            }
            else //已制作签章,直接将签章结果返回即可
            {
                return dzqz;
            }
        }
    }
}

PDF本地文件签章

class iText7SignUtil
    {
        public static int size = 0;
        public static Boolean isAddSize = false;
        //FileStream outFileStream = null;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="inFilePath"></param>
        /// <param name="outFilePath"></param>
        /// <param name="imgFileData"></param>
        /// <param name="estSize"></param>
        /// <param name="resMsg">返回的错误信息</param>
        /// <returns></returns>
        public Boolean sign(String inFilePath, String outFilePath, byte[] imgFileData, out string resMsg)
        {
            //是否签名成功标志
            Boolean success = false;
            //预估大小
            int estimatedSize = 100;//28845; //200000;//
            //int pageNum = SaveValue.pageNum;
            //通过调整预估大小直到签名成功
            IExternalSignatureContainer externalP7DetachSignatureContainer = new DZQZIExternalSignatureContainer();
            int icount = 0;         
            DZQZPdfUtil.log.Info("开始用iText签章...");
            DZQZPdfUtil.log.Debug("imgFileDataLen:"+ imgFileData.Length);
            //while (!success)
            {
                try
                {
                    
                    if (isAddSize)
                    {
                        estimatedSize = size;
                    }
                    PdfReader pdfReader = new PdfReader(inFilePath);
                    PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write), new StampingProperties().UseAppendMode());
                                      
                    PdfSignatureAppearance appearance = pdfSigner.GetSignatureAppearance();
                    appearance.SetLocation("税务局") //2020年5月18日21:36:33 沈雪冰 注释
                              .SetReason("监制章")
                              .SetContact("国家税务总局");
                    // 如果文档中已经创建地命名的签名域,则可以通过下面的代码设置在指定 name的签名域上盖章.
                    //.SetFieldName(name);

                    /*
                     * // 创建签名域
                        PdfFormField field = PdfFormField.CreateSignature(pdfDoc,new Rectangle(72, 632, 200, 100));
                        field.SetFieldName(SIGNAME);
                        field.SetPage(1); 
                     */
                    ImageData imageData = ImageDataFactory.Create(imgFileData);
                    int x = SaveValue.x;
                    int y = SaveValue.y;
                    //ImageData imageData = ImageDataFactory.Create(imageData1.GetHeight() * 72 / 600, imageData1.GetHeight() * 72 / 600,false ,122 , imgFileData, itransparency);
                    float imgHeight = imageData.GetHeight() * 72 / 600; //换算成用户单位 磅
                    float imgWidth = imageData.GetWidth() * 72 / 600;
                    int[] transparency = new int[] { 0x0, 0x0, 0xff, 0xff, 0xff, 0xff };
                    //imageData.SetTransparency(transparency);
                    imageData.SetColorTransform(0xff0000);
                    //imgWidth = SaveValue.width;
                    //imgHeight = SaveValue.height;
                    Rectangle rectangle = new Rectangle(x, y, imgWidth, imgHeight);
                    appearance.SetPageRect(rectangle)
                        .SetPageNumber(SaveValue.pageNum)
                        .SetSignatureGraphic(imageData)
                        .SetRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

                    /*PdfFormXObject n2 = appearance.GetLayer2();
                    Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
                    PdfCanvas canvas = new PdfCanvas(n2, pdfSigner.GetDocument());
                    canvas.AddImage(imageData,rectangle,true);
                    PdfExtGState pdfExtGState = new PdfExtGState();
                    pdfExtGState.SetFillOpacity(0.8f);
                    canvas.SetExtGState(pdfExtGState);*/
                                       pdfSigner.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);//及其重要的属性

                    // }
                    //estimatedSize=pdfSigner.SignExternalContainerEx(externalP7DetachSignatureContainer, estimatedSize);
                    pdfSigner.SignExternalContainer(externalP7DetachSignatureContainer, estimatedSize);
                    //pdfSigner.SignDetached();pdf的标准盖章方法,可传入IExternalSinature IExternalDigest 
                    //盖章
                    //doImageStamp(pdfSigner, imgFileData, PageSize.A4.GetWidth() / 2, 286.0f, imgWidth, imgHeight,pageNum);
                    success = true;
                    //resMsg = "签章成功";
                    DZQZPdfUtil.log.Error("iText7签章成功");
                    //成功后清除当前状态,不然连续签章的时候文档内容变了
                    isAddSize = false;
                    size = 0;

                    //break;
                }
                catch (IOException ioe)
                {
                    if (ioe.Message.Contains("enough space"))
                    {
                        //estimatedSize += 100;//逐渐增加保存签名结果空间,直到能够容纳
                        estimatedSize += (DZQZIExternalSignatureContainer.dzqzLen - estimatedSize);
                        size = estimatedSize;
                        icount++;
                        isAddSize = true;   //增加大小标识符                      
                        DZQZPdfUtil.log.Error(ioe.Message);
                        resMsg = ioe.Message;
                        return false;
                    }
                    else
                    {
                        resMsg = "Exception:  " + ioe.Message;
                        DZQZPdfUtil.log.Error(resMsg);
                        return false;
                    }
                }
                catch (MyException mye)
                {
                    resMsg = "Exception:  " + mye.Message;
                    success = true;
                    DZQZPdfUtil.log.Error(resMsg);
                    return false;
                }
                //if (null != outputfile) { outputfile.Close(); outputfile = null; }
                //if (null != pdfReader) pdfReader.Close();
            }
            resMsg = "签章成功";
            return success;
        }
 public Boolean sign(byte[] signFile, String outFilePath, byte[] imgFileData, out string resMsg)
        {
            //是否签名成功标志
            Boolean success = false;
            //预估大小
            int estimatedSize = 100;//28845; //200000;//
            //int pageNum = SaveValue.pageNum;
            //通过调整预估大小直到签名成功
            IExternalSignatureContainer externalP7DetachSignatureContainer = new DZQZIExternalSignatureContainer();
            int icount = 0;
            //PdfReader pdfReader = null;//new PdfReader(inFilePath);
            //FileStream outputfile = null;// new FileStream(outFilePath, FileMode.Create);
            //PdfSigner pdfSigner = null;// new PdfSigner(pdfReader, outputfile, new StampingProperties());
            //Stream data = PdfSignature.GetRangeStream();
            //byte[] encodedSig = externalP7DetachSignatureContainer.Sign(data);
            DZQZPdfUtil.log.Info("开始用iText签章...");
            
            if(SaveValue.dwProvType==1) //2020年5月18日22:37:42 沈雪冰 add 为了支持不同算法签章,设置的PdfDictionary signDic不同
            {
                DZQZIExternalSignatureContainer.userKeyType = 1;
            }
            else
            {
                DZQZIExternalSignatureContainer.userKeyType = 2;
            }
            DZQZPdfUtil.log.Debug("imgFileDataLen:" + imgFileData.Length);
            Stream outStream = new MemoryStream();
            //while (!success)
            {
                try
                {
                    if (isAddSize)
                    {
                        estimatedSize = size;
                    }
                    Stream st = new MemoryStream(signFile);
                    PdfReader pdfReader = new PdfReader(st);
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write), new StampingProperties().UseAppendMode());
                   // PdfSigner pdfSigner = new PdfSigner(pdfReader, outStream, new StampingProperties());
                    MemoryStream baos = new MemoryStream();
                    PdfSigner pdfSigner = new PdfSigner(pdfReader, baos, new StampingProperties().UseAppendMode()) ; //2020年5月14日10:52:53 沈雪冰 add 此文件可追加签名
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, baos, true);
                    //externalP7DetachSignatureContainer = new MyExtendSigner();
                    //if (!isAddSize) //此处必须屏蔽,因为pdfReader和pdfSigner都是新的对象,需要重新赋值
                    //{
                    //PdfReader pdfReader = new PdfReader(new ByteArrayInputStream(inFilePath));
                    //PdfReader pdfReader = new PdfReader(inFilePath);
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath,FileMode.OpenOrCreate), new StampingProperties());
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.Create), "d:\\PDF\\temp\\tempfile.pdf", new StampingProperties());
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.Create), System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), new StampingProperties().UseAppendMode());
                    //outputfile = new FileStream(outFilePath, FileMode.Create);
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, outputfile, new StampingProperties().UseAppendMode());
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.Create), false);
                    //PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.Create), new StampingProperties());

                    PdfSignatureAppearance appearance = pdfSigner.GetSignatureAppearance();
                    appearance//.SetLocation("税务局")
                              .SetReason("文档校验")//.SetReason("监制章")
                              .SetContact("国家税务总局");
                    string fieldName= pdfSigner.GetFieldName();
                    // 如果文档中已经创建地命名的签名域,则可以通过下面的代码设置在指定 name的签名域上盖章.
                    //.SetFieldName(name);
                    //PdfFormField field;
                    
                    // 创建签名域
                    //PdfFormField field = PdfFormField.CreateSignature(pdfDoc, new Rectangle(72, 632, 200, 100));
                    //pdfStamper
                    //field.SetFieldName(SIGNAME);
                    //field.SetPage(1);
                    
                    ImageData imageData = ImageDataFactory.Create(imgFileData);
                    int x = SaveValue.x;
                    int y = SaveValue.y;
                    //ImageData imageData = ImageDataFactory.Create(imageData1.GetHeight() * 72 / 600, imageData1.GetHeight() * 72 / 600,false ,122 , imgFileData, itransparency);
                    float imgHeight = imageData.GetHeight(); //;* 72 / 600; //换算成用户单位 磅//2020年5月8日20:22:49 shen update 不换算成磅,不然图片超级小
                    float imgWidth = imageData.GetWidth(); //;* 72 / 600;

                    int imgDpiX=imageData.GetDpiX();
                    int imgDpiY = imageData.GetDpiY();
                    
                    //imageData.SetDpi(72,72);  //pdf标准72dpi
                    imgHeight = imageData.GetHeight();
                    imgWidth = imageData.GetWidth();
                    imgHeight = 4 * 28.346f;
                    imgWidth = 4 * 28.345f;
                    int[] transparency = new int[] { 0x0, 0x0, 0xff, 0xff, 0xff, 0xff };
                    //imageData.SetTransparency(transparency);
                    imageData.SetColorTransform(0xff0000);
                    //imgWidth = SaveValue.width;
                    //imgHeight = SaveValue.height;
                    Rectangle rectangle = new Rectangle(x, y, imgWidth, imgHeight);??????????需要通过参数传过来
                    appearance.SetPageRect(rectangle)
                        .SetPageNumber(SaveValue.pageNum)
                        .SetSignatureGraphic(imageData)
                        .SetRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);

                    /*PdfFormXObject n2 = appearance.GetLayer2();
                    Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
                    PdfCanvas canvas = new PdfCanvas(n2, pdfSigner.GetDocument());
                    canvas.AddImage(imageData,rectangle,true);
                    PdfExtGState pdfExtGState = new PdfExtGState();
                    pdfExtGState.SetFillOpacity(0.8f);
                    canvas.SetExtGState(pdfExtGState);*/

                    /*
                     *设置签名域的外观,
                     * // Get the background layer and draw a gray rectangle as a background.
                        PdfFormXObject n0 = appearance.GetLayer0();
                        float x = n0.GetBBox().ToRectangle().GetLeft();
                        float y = n0.GetBBox().ToRectangle().GetBottom();
                        float width = n0.GetBBox().ToRectangle().GetWidth();
                        float height = n0.GetBBox().ToRectangle().GetHeight();
                        PdfCanvas canvas = new PdfCanvas(n0, signer.GetDocument());
                        canvas.SetFillColor(ColorConstants.LIGHT_GRAY);
                        canvas.Rectangle(x, y, width, height);
                        canvas.Fill();

                        // Set the signature information on layer 2
                        PdfFormXObject n2 = appearance.GetLayer2();
                        Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
                        new Canvas(n2, signer.GetDocument()).Add(p);
                        // Set the custom text and a custom font
                        appearance.SetLayer2Text("This document was signed by Bruno Specimen");
                        appearance.SetLayer2Font(PdfFontFactory.CreateFont(StandardFonts.TIMES_ROMAN));
                     */

                    //pdfSigner.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);// 2020年6月3日17:29:32 沈雪冰 注释 设置了这个属性,连续对一个pdf进行签章,导致adobe软件验证前边的签章无效

                    // }
                    //estimatedSize=pdfSigner.SignExternalContainerEx(externalP7DetachSignatureContainer, estimatedSize);
                    DZQZPdfUtil.log.Debug("签章预留空间estimatedSize:" + estimatedSize);
                    pdfSigner.SignExternalContainer(externalP7DetachSignatureContainer, estimatedSize);
                    //pdfSigner.SignDetached();pdf的标准盖章方法,可传入IExternalSinature IExternalDigest 
                    //盖章
                    //doImageStamp(pdfSigner, imgFileData, PageSize.A4.GetWidth() / 2, 286.0f, imgWidth, imgHeight,pageNum);
                    success = true;
                    //resMsg = "签章成功";
                    DZQZPdfUtil.log.Error("iText7签章成功");
                    //byte[] docBytesHash = externalP7DetachSignatureContainer.GetDocBytesHash();
                    byte[] preSignedBytes = baos.ToArray();
                    //break;
                    SaveValue.outFileStream = new byte[preSignedBytes.Length];
                    SaveValue.outFileStream = preSignedBytes;
                    if(outFilePath.Length>0)//如果送了输出地址,签章后的文件可落地
                    {
                        FileStream esDataFile = new FileStream(outFilePath, FileMode.Create);
                        esDataFile.Write(preSignedBytes, 0, preSignedBytes.Length);
                        esDataFile.Close();
                    }
                     //DZQZIExternalSignatureContainer.flag = false;
                     //DZQZIExternalSignatureContainer.dzqz = null;
                    //成功后清除当前状态,不然连续签章的时候文档内容变了
                    isAddSize = false;
                    size = 0;
                    //tuichuKEY
                    //DZQZIExternalSignatureContainer.quitFlag = true;
                    DZQZIExternalSignatureContainer.CloseDev();
                }
                catch (IOException ioe)
                {
                    if (ioe.Message.Contains("enough space"))
                    {
                        //estimatedSize += 100;//逐渐增加保存签名结果空间,直到能够容纳
                        estimatedSize += (DZQZIExternalSignatureContainer.dzqzLen - estimatedSize);
                        size = estimatedSize;
                        icount++;
                        isAddSize = true;   //增加大小标识符                      
                        DZQZPdfUtil.log.Error(ioe.Message);
                        resMsg = ioe.Message;
                        DZQZPdfUtil.code = 666;//2020年5月15日18:45:43 沈雪冰 add 空间不够特殊处理
                        DZQZPdfUtil.log.Info("空间不够,需要输出扩充空间");
                        return false;
                        //continue;
                    }
                    else
                    {
                        resMsg = "Exception:  " + ioe.Message;
                        DZQZPdfUtil.log.Error(resMsg);
                        DZQZPdfUtil.code = -1;
                        return false;
                    }
                }
                catch (MyException mye)
                {
                    resMsg = "Exception:  " + mye.Message;
                    success = false;
                    DZQZPdfUtil.log.Error(resMsg);
                    DZQZPdfUtil.code = -1;
                    return false;
                }
                catch(Exception e)
                {
                    resMsg = "Exception:  " + e.Message;
                    success = false;
                    DZQZPdfUtil.log.Error(resMsg);
                    DZQZPdfUtil.code = -1;
                    return false;
                }
                //if (null != outputfile) { outputfile.Close(); outputfile = null; }
                //if (null != pdfReader) pdfReader.Close();
            }
            resMsg = "签章成功";
            DZQZPdfUtil.code = 0;
            return success;
        }

上述为了支持RSA和SM2的签章,我本人遇到了巨坑,尝试、调试了N多遍才最终实现可对SM2、RSA可追加签章。

常见遇到的问题与解决方案

2.问题:追加签章,签章是签上去了,可是Adobe在验章(RSA)的的时候只有最后一个章有效。

解决方案:
技术点:(1)将签章图片背景处理透明

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DZQZ.SignBase
{
    class TransImageOpacity
    {
        /// <summary>
        /// 将背景为白色的png图片变透明
        /// </summary>
        /// <param name="imgByte"></param>
        /// <returns></returns>
        public static byte[] Change(byte []imgByte)
        {
            //Image image = System.Drawing.Image.FromFile("E://img.JPG");
            //Bitmap pbitmap = new Bitmap(image);
            //pbitmap.MakeTransparent(Color.White);//当图片的背景为白色时
            //pbitmap.Save("E;//test.png");
            //Image Imageimage= BytesToImage(imgByte);
            Imageimage = System.Drawing.Image.FromFile(@"C:\A.JPG");
            Stream st = new MemoryStream(imgByte);
            //Bitmap bitmap = new Bitmap(Imageimage);
            //bitmap.MakeTransparent(Color.White);
            //bitmap.Save("yz_img.png");
            //return BitmapToBytes(bitmap);
            //2020年5月8日20:58:47 沈雪冰 update上述方法只使用于大白KEY中的章
            Image image = BytesToImage(imgByte);
            
            System.Drawing.Bitmap bitmapProxy = new System.Drawing.Bitmap(image);       
            image.Dispose();
            for (int i = 0; i < bitmapProxy.Width; i++)
            {
                for (int j = 0; j < bitmapProxy.Height; j++)
                {
                    System.Drawing.Color c = bitmapProxy.GetPixel(i, j);
                    if (!(c.R < 150 || c.G < 150 || c.B < 150)) //255 255 255 纯白 2020年5月9日15:46:34 值越低 可处理毛边接近灰色的像素值
                    {
                        bitmapProxy.SetPixel(i, j, System.Drawing.Color.Transparent);
                    }
                }
            }
            //bitmapProxy.Save("tets.png");
            return BitmapToBytes(bitmapProxy);
            //return bitmapProxy;
        }
        /// <summary>
        /// Convert Byte[] to Image
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static Image BytesToImage(byte[] buffer)
        {
            MemoryStream ms = new MemoryStream(buffer);
            Image image = System.Drawing.Image.FromStream(ms);
            return image;
        }
        public static byte[] ImageToBytes(Image image)
        {
            ImageFormat format = image.RawFormat;
            using (MemoryStream ms = new MemoryStream())
            {
                if (format.Equals(ImageFormat.Jpeg))
                {
                    image.Save(ms, ImageFormat.Jpeg);
                }
                else if (format.Equals(ImageFormat.Png))
                {
                    image.Save(ms, ImageFormat.Png);
                }
                else if (format.Equals(ImageFormat.Bmp))
                {
                    image.Save(ms, ImageFormat.Bmp);
                }
                else if (format.Equals(ImageFormat.Gif))
                {
                    image.Save(ms, ImageFormat.Gif);
                }
                else if (format.Equals(ImageFormat.Icon))
                {
                    image.Save(ms, ImageFormat.Icon);
                }
                byte[] buffer = new byte[ms.Length];
                //Image.Save()会改变MemoryStream的Position,需要重新Seek到Begin
                ms.Seek(0, SeekOrigin.Begin);
                ms.Read(buffer, 0, buffer.Length);
                return buffer;
            }
        }
        public static byte[] BitmapToBytes(Bitmap bitmap)
        {
            MemoryStream stream = new MemoryStream();

            bitmap.Save(stream, ImageFormat.Png);
            byte[] data = new byte[stream.Length];
            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(data, 0, Convert.ToInt32(stream.Length));
            return data;
        }
    }
}

2.问题:追加签章,签章是签上去了,可是Adobe在验章(RSA)的的时候只有最后一个章有效。

解决方案:
技术点:(1)设置可追加签名属性

 PdfSigner pdfSigner = new PdfSigner(pdfReader, new FileStream(outFilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write), new StampingProperties().UseAppendMode()); //new StampingProperties().UseAppendMode()重要属性,如果不需要追加可不设置

技术点:(2)设置认证级别

pdfSigner.SetCertificationLevel(int certificationLevel);
**certificationLevel参数说明:**
1.CERTIFIED_NO_CHANGES_ALLOWED 不许任何更改,否则签名失效 即连Ordinary (approval) signature都不许添加了
2.CERTIFIED_FORM_FILLING 后续可以添加表单和Ordinary (approval) signature而不影响签名的有效性
3.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS 可以添加Ordinary (approval) signature ,表单和注释,不影响签名的有效性。
回到上面的例子,在sig4签名后,Chuck对Carol的approved_carol(我暂时还是没弄清楚回头再细化)但是不影响签名,只是“违抗”了之前签名的权限。

以上两个一定要根据自己的应用需求去设置。

1.问题:Adobe不认签好的章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

离水的鱼儿

一分也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值