Search code examples
javascriptpdfencryptionclient-sidepdf-lib.js

My pdf encryption code encrypt stream but not string, what kind of string should i encrypt and in what encoding?


I tested this code to test by text fields:

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);
        }
      }
    }
  }
}

I used this exemple: enter image description here

I tested by ASCII (I think in PDF Literal Strings support just ASCII) and the encryption finally works(text fields) but not after every try, in every try I got one or many text empty fields: enter image description here

Here the code first 4 text fields: Before encryption:

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

After encryption:

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

What i want to know:

  1. Why the fields works just when I use ASCII? is there another way to use UTF-8 in PDF?
  2. What kind of PDF strings should I encryptin a PDF instead of just some (/V, /T, /DA) in text fields.

Solution

  • You should try this.

    // Pre-Init
    const LUT_HEX_4b = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
    const LUT_HEX_8b = new Array(0x100);
    for (let n = 0; n < 0x100; n++) {
      LUT_HEX_8b[n] = `${LUT_HEX_4b[(n >>> 4) & 0xF]}${LUT_HEX_4b[n & 0xF]}`;
    }
    // End Pre-Init
    function toHex(buffer) {
      let out = '';
      for (let idx = 0, edx = buffer.length; idx < edx; idx++) {
        out += LUT_HEX_8b[buffer[idx]];
      }
      return out;
    }
    
    
    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.UTF8.GetBytes(data.value)));
              data.value = toHex(encryptedData);
            }
          }
        }
      }
    }