Skip to content

PDF 签名 (Signature)

PDF 签名用于创建和签署 PDF 文档的数字签名,以保护文档内容的安全性和完整性。通过数字签名,接收者可以验证文档的来源和内容是否被篡改。福昕 PDF SDK 提供 API,支持创建数字签名、验证签名有效性、删除现有签名、获取和设置签名属性,以及自定义签名表单域的外观。

福昕 PDF SDK 提供默认签名回调函数,支持以下两种类型的 signature filter 和 subfilter:

  1. filter: Adobe.PPKLite,subfilter: adbe.pkcs7.detached
  2. filter: Adobe.PPKLite,subfilter: adbe.pkcs7.sha1

使用以上任意一种 signature filter 和 subfilter,您无需注册自定义回调函数,即可直接签名 PDF 文档并验证签名有效性。

如何对 PDF 文档进行签名,并验证签名

js
import { FoxitRDKNative } from 'foxit_rdk';

class SignatureUnit {
  // 示例代码展示了如何对PDF文档进行签名,并验证签名
  public addNewSignatureAndSign(page: FoxitRDKNative.pdf.PDFPage, rect: FoxitRDKNative.common.fxcrt.RectF): void {
    try {
      // 在指定的页面矩形上添加一个新的签名
      const signature = page.AddSignature(rect);
      // 设置 appearance flags
      signature.SetAppearanceFlags(FoxitRDKNative.pdf.Signature.e_APFlagLabel |
      FoxitRDKNative.pdf.Signature.e_APFlagDN |
      FoxitRDKNative.pdf.Signature.e_APFlagText | FoxitRDKNative.pdf.Signature.e_APFlagLocation |
      FoxitRDKNative.pdf.Signature.e_APFlagReason | FoxitRDKNative.pdf.Signature.e_APFlagSigner);
      // 设置 signer
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameSigner, "Foxit");
      // 设置 location
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameLocation, "AnyWhere");
      // 设置 reason
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameReason, "ANyReason");
      // 设置 contact info
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameContactInfo, "AnyInfo");
      // 设置 domain name
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameDN, "AnyDN");
      // 设置 description
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameText, "AnyContent");
      // 默认支持  "Adobe.PPKLite" Filter
      signature.SetFilter("Adobe.PPKLite");
      // 默认支持 "adbe.pkcs7.sha1" 或 "adbe.pkcs7.detached" SubFilter
      signature.SetSubFilter("adbe.pkcs7.detached");

      // 输入的 PKCS#12 格式证书,其包含公钥和私钥
      const certPath = "/somewhere/cert.pfx";
      // 该证书的密码
      const certPassword = "123";
      const signedPDFPath = "/somewhere/signed.pdf";

      // 开始签名,如果成功,签名后的PDF将保存到 "save_path" 指定的路径
      class PauseCallBackImpl extends FoxitRDKNative.common.PauseCallback {
        NeedToPauseNow(): boolean {
          return false;
        }
      }

      const progressive =
        signature.StartSign(certPath, certPassword, FoxitRDKNative.pdf.Signature.e_DigestSHA1, signedPDFPath,
          new ArrayBuffer(0), new PauseCallBackImpl());
      if (progressive != null) {
        let state = FoxitRDKNative.common.Progressive.e_ToBeContinued;
        while (state == FoxitRDKNative.common.Progressive.e_ToBeContinued) {
          state = progressive.Continue();
        }
        if (state != FoxitRDKNative.common.Progressive.e_Finished) {
          return;
        }
      }

      // 从已签名的PDF文档中获取签名,然后进行验证
      const pdfDoc = new FoxitRDKNative.pdf.PDFDoc(signedPDFPath);
      const err = pdfDoc.Load(null);
      if (err != FoxitRDKNative.common.ErrorCode.e_ErrSuccess) {
        return;
      }
      const count = pdfDoc.GetSignatureCount();
      for (let i = 0; i < count; i++) {
        const sign = pdfDoc.GetSignature(i);
        if (sign != null && !sign.IsEmpty()) {
          const progressive_1 = sign.StartVerify(new ArrayBuffer(0), null);
          if (progressive_1 != null) {
            let state = FoxitRDKNative.common.Progressive.e_ToBeContinued;
            while (state == FoxitRDKNative.common.Progressive.e_ToBeContinued) {
              state = progressive_1.Continue();
            }
            if (state != FoxitRDKNative.common.Progressive.e_Finished) {
              continue;
            }
          }
          const verifiedState = sign.GetState();
          if ((verifiedState & FoxitRDKNative.pdf.Signature.e_StateVerifyValid) ==
          FoxitRDKNative.pdf.Signature.e_StateVerifyValid) {
            console.info("Signature", "addNewSignatureAndSign: Signature" + i + "is valid.");
          }
        }
      }
    } catch (e) {
      console.error(e);
    }
  }
}

如何为签名设置定制化时间信息

通过 Signature 对象的 SetSignTime 方法不能改变时间格式。我们可以通过传递参数(时间字符串)给签名词典来解决这个问题。具体参考下述代码。

js
import { FoxitRDKNative } from 'foxit_rdk';

class SignatureUnit2 {
  public addNewSignatureAndSign(page: FoxitRDKNative.pdf.PDFPage, rect: FoxitRDKNative.common.fxcrt.RectF): void {
    try {
      // 在指定的页面矩形上添加一个新的签名
      const signature = page.AddSignature(rect);
      // 设置 appearance flags
      signature.SetAppearanceFlags(FoxitRDKNative.pdf.Signature.e_APFlagLabel |
      FoxitRDKNative.pdf.Signature.e_APFlagDN |
      FoxitRDKNative.pdf.Signature.e_APFlagText | FoxitRDKNative.pdf.Signature.e_APFlagLocation |
      FoxitRDKNative.pdf.Signature.e_APFlagReason | FoxitRDKNative.pdf.Signature.e_APFlagSigner |
      FoxitRDKNative.pdf.Signature.e_APFlagSigningTime);
      // 设置 signer
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameSigner, "Foxit");
      // 设置 location
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameLocation, "AnyWhere");
      // 设置 reason
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameReason, "ANyReason");
      // 设置 contact info
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameContactInfo, "AnyInfo");
      // 设置 domain name
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameDN, "AnyDN");
      // 设置 description
      signature.SetKeyValue(FoxitRDKNative.pdf.Signature.e_KeyNameText, "AnyContent");
      // DateTime dateTime = new DateTime();
      // ...
      // signature.SetSignTime(dateTime);
      // 签名日期的默认格式是yyMMddhhmmss-时区
      // 如果您需要设置自定义格式的时间,请参考以下代码
      const dictionary = signature.GetSignatureDict();
      dictionary.SetAtString("M", "2022/02/13 11:00:00"/* formatted time string*/);
      // 默认支持 "Adobe.PPKLite" Filter
      signature.SetFilter("Adobe.PPKLite");
      // 默认支持 "adbe.pkcs7.sha1" 或 "adbe.pkcs7.detached" SubFilter
      signature.SetSubFilter("adbe.pkcs7.detached");

      // 输入的 PKCS#12 格式证书,其包含公钥和私钥
      const certPath = "/somewhere/cert.pfx";
      // 该证书的密码
      const certPassword = "123";
      const signedPDFPath = "/somewhere/signed.pdf";

      // 开始签名,如果成功,签名后的PDF将保存到 "save_path" 指定的路径
      class PauseCallBackImpl extends FoxitRDKNative.common.PauseCallback {
        NeedToPauseNow(): boolean {
          return false;
        }
      }

      const progressive =
        signature.StartSign(certPath, certPassword, FoxitRDKNative.pdf.Signature.e_DigestSHA1, signedPDFPath,
          new ArrayBuffer(0), new PauseCallBackImpl());
      if (progressive != null) {
        let state = FoxitRDKNative.common.Progressive.e_ToBeContinued;
        while (state == FoxitRDKNative.common.Progressive.e_ToBeContinued) {
          state = progressive.Continue();
        }
        if (state != FoxitRDKNative.common.Progressive.e_Finished) {
          return;
        }
      }

      // 从已签名的PDF文档中获取签名,然后进行验证
      const pdfDoc = new FoxitRDKNative.pdf.PDFDoc(signedPDFPath);
      const err = pdfDoc.Load('');
      if (err != FoxitRDKNative.common.ErrorCode.e_ErrSuccess) {
        return;
      }
      const count = pdfDoc.GetSignatureCount();
      for (let i = 0; i < count; i++) {
        const sign = pdfDoc.GetSignature(i);
        if (sign != null && !sign.IsEmpty()) {
          const progressive_1 = sign.StartVerify(null, null);
          if (progressive_1 != null) {
            let state = FoxitRDKNative.common.Progressive.e_ToBeContinued;
            while (state == FoxitRDKNative.common.Progressive.e_ToBeContinued) {
              state = progressive_1.Continue();
            }
            if (state != FoxitRDKNative.common.Progressive.e_Finished) {
              continue;
            }
          }
          const verifiedState = sign.GetState();
          if ((verifiedState & FoxitRDKNative.pdf.Signature.e_StateVerifyValid) ==
          FoxitRDKNative.pdf.Signature.e_StateVerifyValid) {
            console.info("Signature", "addNewSignatureAndSign: Signature" + i + "is valid.");
          }
        }
      }
    } catch (e) {
      console.error(e);
    }
  }
}