Bhinish Dhiman

Por que juntar um PDF criptografado pode deixar páginas em branco: nós medimos

Traduzido do original em inglês. Ler o original

Juntar um PDF protegido por senha com o pdf-lib original e a opção ignoreEncryption produziu um arquivo de quatro páginas em que as três páginas protegidas ficaram em branco e só 49 de 373 caracteres sobreviveram, porque o conteúdo das páginas foi copiado ainda criptografado. A mesma junção com o @cantoo/pdf-lib e a senha deu quatro páginas, 373 caracteres e nada em branco.

O sintoma é conhecido: você junta um extrato bancário a uma carta de apresentação, nenhum erro aparece, e as páginas do extrato saem brancas. Reproduzimos isso em código e contamos o que se perdeu.

O que a criptografia de PDF realmente criptografa

Criptografia de PDF aplica uma cifra (AES-256, segundo a ISO 32000-2) às strings e aos streams do arquivo, e só a eles. A estrutura de objetos fica às claras: um leitor consegue ver, sem senha, que há três páginas, qual é o tamanho delas e qual stream de conteúdo cada uma usa. O que ele não consegue fazer sem a senha é transformar esses streams de conteúdo de texto cifrado em instruções de desenho.

Essa divisão é todo o mecanismo da falha das páginas em branco. Uma biblioteca consegue percorrer a estrutura, copiar as páginas e nunca perceber que os bytes que copiou continuam criptografados.

A medição

Montamos um extrato de três páginas com 324 caracteres de texto conhecido e o criptografamos com AES-256 e uma senha de usuário, usando a mesma chamada encrypt() da nossa ferramenta Protect PDF. Depois o juntamos, após uma carta de apresentação de uma página e 49 caracteres, por dois caminhos: o pdf-lib 1.17.1 original (upstream) carregado com ignoreEncryption: true, e o @cantoo/pdf-lib 2.11.1 carregado com a senha, que é o que o src/lib/pdf/ops.ts faz. Cada resultado foi aberto no pdf.js 6.3.289, teve o texto extraído e todas as páginas renderizadas em meia escala e varridas em busca de qualquer pixel não branco. Executado no Node 24 em 1º de outubro de 2026.

Caminho Páginas na saída Caracteres extraídos Páginas em branco Dicionário Encrypt na saída
pdf-lib original, ignoreEncryption: true 4 49 3 Não
@cantoo/pdf-lib, com a senha 4 373 0 Não

Os dois caminhos informam sucesso. Os dois produzem um arquivo que abre sem senha. Um deles jogou o extrato fora.

Por que as páginas ficam em branco em vez de embaralhadas

O pdf-lib original recusa um arquivo criptografado por padrão, com uma mensagem que aponta a saída de emergência: “Input document to PDFDocument.load is encrypted. You can use PDFDocument.load(..., { ignoreEncryption: true }).” (o documento de entrada está criptografado; você pode usar a opção ignoreEncryption). As ferramentas que querem parecer compatíveis com arquivos criptografados usam essa saída.

Com a opção ativada, a biblioteca analisa a estrutura que consegue ler e copia três objetos de página, cada um apontando para um stream de conteúdo com texto cifrado em AES. O novo documento não tem dicionário de criptografia, então o leitor trata esses streams como dados comuns comprimidos com Flate, descomprime, obtém ruído e para de desenhar. O pdf.js registra Trying to parse invalid object e Invalid object ref: 14 0 R e segue em frente. Os 49 caracteres que sobreviveram são os da carta de apresentação, que nunca foi criptografada.

A variante no próprio arquivo é pior

Também carregamos o arquivo criptografado com ignoreEncryption, alteramos um campo de metadados e o salvamos sem copiar nada. Esse resultado nem abria: o pdf.js informou Incorrect Password (senha incorreta) quando recebeu a senha correta. O salvamento tinha reescrito a estrutura do arquivo em volta de um texto cifrado cujas chaves já não batiam, o que gera um documento que ninguém consegue recuperar, e não um documento com uma página em branco.

O fork faz a descriptografia

O @cantoo/pdf-lib é um fork do pdf-lib que adiciona uma opção password ao load() e um método encrypt(). Com a senha, ele descriptografa cada stream durante a análise, então o copyPages move texto às claras, e o resultado da junção guarda os 373 caracteres com todas as páginas renderizando. Sem a senha, ele lança um erro exatamente como o original: não tenta adivinhar, e não existe caminho que remova uma senha que você não conhece.

O teste para fazer em qualquer ferramenta de juntar PDF

Junte um arquivo protegido e extraia o texto depois, com a nossa ferramenta PDF to text ou qualquer outra. Se os caracteres do documento protegido não estiverem lá, a ferramenta copiou texto cifrado. Uma página em branco não é uma falha de renderização que outro visualizador vá resolver; o conteúdo não sobreviveu à junção.