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

PDF加密技术咨询:字符串编码适配及加密范围疑问

PDF文本字段加密问题与解答

自定义加密方法代码

PDFWriter.prototype.encrypt = function (ref, obj, pdfSecurity) {
  let encryptedData;

  const encryptFn = pdfSecurity.getEncryptFn(
    ref.objectNumber,
    ref.generationNumber,
  );

  if (encryptFn) {

    if (obj instanceof PDFStream) {
      let toBeEncrypt = obj.getContents();
      encryptedData = new Uint8Array(encryptFn(toBeEncrypt));
      obj.contents = encryptedData;
    }
    else if (obj.lookup(PDFLib.PDFName.of("Type")) == PDFLib.PDFName.of("Annot")) {
      let values = ["V", "T", "DA"];

      for (var i = 0; i < values.length; i++) {
        let data = obj.lookup(PDFLib.PDFName.of(values[i]));
        if (data && data.value) {
          encryptedData = encryptFn(new Uint8Array(System.Text.Encoding.ASCII.GetBytes(data.value)));
          data.value = System.Text.Encoding.ASCII.GetString(encryptedData);
        }
      }
    }
  }
}

测试用例:加密前后PDF对象内容

加密前

4 0 obj
<<
/AP <<
/N 26 0 R
>>
/DA (0 0 0 rg /F3 11 Tf)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 453.700012 315.700012 467.899994 ]
/Subtype /Widget
/T (Given Name Text Box)
/TU <FEFF004600690072007300740020006E0061006D0065>
/Type /Annot
/V (Hello)
>>
endobj

5 0 obj
<<
/AP <<
/N 27 0 R
>>
/DA (0 0 0 rg /F3 11 Tf)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 421.200012 315.700012 435.399994 ]
/Subtype /Widget
/T (Family Name Text Box)
/TU <FEFF004C0061007300740020006E0061006D0065>
/Type /Annot
/V (þÿ'D91\(J\))
>>
endobj

6 0 obj
<<
/AP <<
/N 28 0 R
>>
/DA (0 0 0 rg /F3 11 Tf)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 388.299988 315.700012 402.5 ]
/Subtype /Widget
/T (Address 1 Text Box)
/Type /Annot
/V (þÿY'U‰WߊeM)
>>
endobj

7 0 obj
<<
/AP <<
/N 29 0 R
>>
/DA (0 0 0 rg /F3 11 Tf)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 20
/P 22 0 R
/Rect [ 378.4 388.4 446.9 402.6 ]
/Subtype /Widget
/T (House nr Text Box)
/TU <FEFF0048006F00750073006500200061006E006400200066006C006F006F0072>
/Type /Annot
/V <FEFF>
>>
endobj

加密后

4 0 obj
<<
/AP <<
/N 26 0 R
>>
/DA (Bý„¡Öû‹¾B Þ¤„îfbÎ&óp£ÿIp‘ù›Š\þ:ø„{†?-}­B<ª    )
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 453.700012 315.700012 467.899994 ]
/Subtype /Widget
/T (Bý„¡Öû‹¾B Þ¤„ñ“æ®ÖLÄc&žQþÍuòÖÒt.ó-‘Å´ƒ}p)
/TU <FEFF004600690072007300740020006E0061006D0065>
/Type /Annot
/V (Bý„¡Öû‹¾B Þ¤„Šª™†÷ß¿`?Õò˜o)
>>
endobj

5 0 obj
<<
/AP <<
/N 27 0 R
>>
/DA (4‘_‚J~ßZñuJ]\îÍø)ô[0¸ßœT;ÌÔjÀÇ\éY»X6ß-M.üí)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 421.200012 315.700012 435.399994 ]
/Subtype /Widget
/T (4‘_‚J~ßZñuJ]\î"o÷§Àij\Ôˆu!•‡e˜‰Îó)Öçy¥¤ïJFdŠ)
/TU <FEFF004C0061007300740020006E0061006D0065>
/Type /Annot
/V (4‘_‚J~ßZñuJ]\îR|™ARqƒ¡hã³»Uy<÷<@@>"I»a£Ê§0Û)
>>
endobj

6 0 obj
<<
/AP <<
/N 28 0 R
>>
/DA (Q¾Ú©hª¶ÈŒæäêèæ@îx ªùé–Cóï5ÍÏ$°léu*Çì‹!t­&)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 40
/P 22 0 R
/Rect [ 165.699997 388.299988 315.700012 402.5 ]
/Subtype /Widget
/T (Q¾Ú©hª¶ÈŒæäêèæg;«è·k6W¹Q!ä€åư]ŒÎ˜*õö5èÅ›t)
/Type /Annot
/V (Q¾Ú©hª¶ÈŒæäêèæÈ۫ʱ'  ½R7ì!ñ1)
>>
endobj

7 0 obj
<<
/AP <<
/N 29 0 R
>>
/DA (ó„Fû’6ò\ñ=t><ÉA¾©ªí˜$•Ã5G ÉFÁþy¸x n‹£§)âÈ×)
/DR <<
/Font 24 0 R
>>
/DV <FEFF>
/F 4
/FT /Tx
/MaxLen 20
/P 22 0 R
/Rect [ 378.4 388.4 446.9 402.6 ]
/Subtype /Widget
/T (ó„Fû’6ò\ñ=t><3xN-ñ>dVù¬H©u`‚7‘ÍžDÆ—í J2g)
/TU <FEFF0048006F00750073006500200061006E006400200066006C006F006F0072>
/Type /Annot
/V <ó„Fû’6ò\ñ=t><žqæ;F˶¶.­öLK>
>>
endobj

技术疑问解答

问题1:为何仅ASCII编码下加密可生效?PDF中是否支持UTF-8编码的加密方式?

你当前代码用System.Text.Encoding.ASCII.GetBytes和GetString处理字符串,ASCII编码会把所有非ASCII字符替换成默认替代符(比如?),直接丢失原始字节信息,导致加密后无法正确还原,所以只有纯ASCII内容能正常工作。

PDF加密本身不关心字符串编码——加密是作用在字节流上的操作,不管是UTF-8、PDF常用的UTF-16BE(比如带<FEFF> BOM的十六进制字符串)还是ASCII,只要你按以下方式处理就能正常生效:

  1. 区分PDF字符串类型:如果是括号包裹的普通ASCII字符串(...),将其转为UTF-8或ASCII字节数组;如果是尖括号包裹的十六进制Unicode字符串<...>,直接解析十六进制为字节数组。
  2. 用这些字节数组执行加密,加密后的字节按对应格式写回PDF:ASCII字符串用括号(...)包裹,Unicode字符串转成十六进制后用尖括号<...>包裹。

你现在的问题是把所有字符串都按ASCII转字节,破坏了Unicode字符串的原始数据,而且加密后的非ASCII字节用ASCII转回字符串,放到PDF的括号格式里会被错误解析,导致空白或乱码。

问题2:除文本字段中的/V、/T、/DA外,PDF中还有哪些类型的字符串需要进行加密?

根据PDF规范,除了加密字典本身、文件头、交叉引用表、trailer固定字段外,所有字符串对象和流对象都需要加密。针对表单字段和注释,还需要处理:

  • /TU:字段的工具提示字符串(你测试用例里的/TU是十六进制Unicode,当前未加密)
  • /DV:字段的默认值字符串
  • /AA:注释动作字典中的字符串(比如/JS脚本内容)
  • /RC:注释的富文本内容
  • /Contents:注释的说明文本
  • /Q:字段拼写检查相关字符串(如果存在)

另外,整个PDF文档里的其他字符串,比如文档信息字典的/Title、/Author,书签的标题字符串,也都属于需要加密的范围。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:45:54