Bhinish Dhiman

Por qué unir un PDF cifrado puede dejarte páginas en blanco: lo medimos

Traducido del original en inglés. Leer el original

Unir un PDF protegido con contraseña usando la versión original de pdf-lib con ignoreEncryption produjo un archivo de cuatro páginas en el que las tres páginas protegidas quedaron en blanco y solo sobrevivieron 49 de 373 caracteres, porque el contenido de las páginas se copió todavía cifrado. La misma unión con @cantoo/pdf-lib y la contraseña dio cuatro páginas, 373 caracteres y ninguna en blanco.

El síntoma es conocido: unes un estado de cuenta bancario a una carta de presentación, no aparece ningún error y las páginas del estado de cuenta salen en blanco. Lo reprodujimos en código y contamos lo que se perdió.

Lo que realmente cifra el cifrado de un PDF

El cifrado de PDF aplica un algoritmo de cifrado (AES-256 según la norma ISO 32000-2) a las cadenas y los flujos del archivo, y solo a ellos. La estructura de objetos queda a la vista: un lector puede ver que hay tres páginas, de qué tamaño son y qué flujo de contenido usa cada una, sin contraseña. Lo que no puede hacer sin la contraseña es convertir esos flujos de contenido de texto cifrado en instrucciones de dibujo.

Esa división es todo el mecanismo de la falla de las páginas en blanco. Una biblioteca puede recorrer la estructura, copiar las páginas y nunca darse cuenta de que los bytes que copió siguen cifrados.

La medición

Creamos un estado de cuenta de tres páginas con 324 caracteres de texto conocido y lo ciframos con AES-256 y una contraseña de usuario, con la misma llamada encrypt() que usa nuestra herramienta Protect PDF. Después lo unimos, detrás de una carta de presentación de una página y 49 caracteres, por dos vías: la versión original de pdf-lib 1.17.1 cargada con ignoreEncryption: true, y @cantoo/pdf-lib 2.11.1 cargada con la contraseña, que es lo que hace src/lib/pdf/ops.ts. Abrimos cada resultado en pdf.js 6.3.289, extrajimos su texto y renderizamos cada página a media escala para buscar cualquier píxel que no fuera blanco. Ejecutado con Node 24 el 1 de octubre de 2026.

Vía Páginas resultantes Caracteres extraídos Páginas en blanco Diccionario Encrypt en el resultado
pdf-lib original, ignoreEncryption: true 4 49 3 No
@cantoo/pdf-lib, con contraseña 4 373 0 No

Las dos vías informan que todo salió bien. Las dos producen un archivo que se abre sin contraseña. Una de ellas tiró a la basura el estado de cuenta.

Por qué las páginas salen en blanco y no con basura

La versión original de pdf-lib rechaza de forma predeterminada un archivo cifrado, con un mensaje que nombra la vía de escape: “Input document to PDFDocument.load is encrypted. You can use PDFDocument.load(..., { ignoreEncryption: true }).” Las herramientas que quieren aparentar que aceptan archivos cifrados toman esa vía.

Con esa opción activada, la biblioteca analiza la estructura que puede leer y copia tres objetos de página, cada uno apuntando a un flujo de contenido con texto cifrado AES. El documento nuevo no tiene diccionario de cifrado, así que el lector trata esos flujos como datos normales comprimidos con Flate, los descomprime, obtiene ruido y deja de dibujar. pdf.js registra Trying to parse invalid object e Invalid object ref: 14 0 R y sigue adelante. Los 49 caracteres que sobrevivieron son los de la carta de presentación, que nunca estuvo cifrada.

La variante sobre el mismo archivo es peor

También cargamos el archivo cifrado con ignoreEncryption, cambiamos un campo de metadatos y lo guardamos sin copiar nada. Ese resultado no se pudo abrir de ninguna manera: pdf.js informó Incorrect Password aunque le dimos la contraseña correcta. Al guardar se reescribió la estructura del archivo alrededor de un texto cifrado cuyas claves ya no coinciden, y eso es un documento que nadie puede recuperar, no un documento con una página en blanco.

El fork se encarga del descifrado

@cantoo/pdf-lib es un fork de pdf-lib que añade una opción password a load() y un método encrypt(). Con la contraseña, descifra cada flujo a medida que lo analiza, así que copyPages mueve texto sin cifrar, y el resultado de la unión conserva los 373 caracteres y renderiza todas las páginas. Sin la contraseña, lanza el mismo error que la versión original: no adivina, y no hay ninguna vía que quite una contraseña que no conoces.

La prueba que debes hacerle a cualquier herramienta para unir PDF

Une un archivo protegido y después extrae el texto, con nuestra herramienta PDF to text o con cualquier otra. Si faltan los caracteres del documento protegido, la herramienta copió texto cifrado. Una página en blanco no es una falla de visualización que se arregle con otro visor; el contenido no sobrevivió a la unión.