Un indicador de permisos no es un mecanismo de seguridad. El bit que dice "sin copia" reside dentro del mismo diccionario /Encrypt que la criptografía, lo que le concede una apariencia de aplicación que no tiene, y en el momento en que trata ambos como una sola cosa su auditoría comienza a producir respuestas equivocadas. La única pregunta que vale la pena hacer sobre un PDF no es "¿está cifrado?". Es más específica y más difícil: qué algoritmo, qué revisión del controlador de seguridad, cuál de las dos contraseñas se configuró, qué bits de permisos se declaran y qué partes del archivo toca realmente el cifrado. Un archivo puede estar cifrado formalmente y abierto en la práctica. Puede negarse a leerse y, sin embargo, dejar sus metadatos en texto plano. Puede bloquear la impresión mediante un indicador que cualquier visor tiene libertad de ignorar. Auditar un PDF significa resolver todo eso por separado, y PDF Library for Delphi, el motor PDF de losLab para Delphi y C++Builder, expone cada elemento tanto mediante una API plana de identificadores enteros como mediante una capa de clases tipadas
Lo que realmente registra el diccionario /Encrypt
ISO 32000-1 §7.6 define la seguridad de los documentos mediante un conjunto reducido de entradas de diccionario, y PDF Library for Delphi las refleja una por una en el registro TPDFEncryption. La versión del filtro V y la revisión R seleccionan la familia de algoritmos. Length contiene el tamaño de clave. Los bits de permisos están en P, las cadenas de validación de contraseñas de propietario y usuario en O y U (con OE y UE agregadas para AES-256), junto a ellas aparece un indicador EncryptMetadata, y otros tres campos nombran los filtros criptográficos aplicados respectivamente a cadenas, streams y archivos incrustados
El valor de este registro es que no interpreta nada por usted. Devuelve el diccionario sin procesar y le permite sacar las conclusiones, que es exactamente lo que necesita una auditoría. El caso de texto plano dentro de un archivo cifrado aparece en StringFilterIdentity y StreamFilterIdentity: cuando cualquiera de los dos es verdadero, los datos correspondientes pasan sin modificación a través del filtro Identity, sin importar el estado de cifrado que informe el documento. Un escáner que se detiene en "hay un diccionario /Encrypt" llamará protegido a ese archivo cuando sus cadenas y streams están expuestos. El mismo matiz rige los metadatos. Cuando EncryptMetadata es falso, el paquete XMP queda legible para cualquier indexador aunque el contenido de la página no lo esté, algo que importa en cuanto sus reglas de enrutamiento se basan en un campo de título o autor
Una comprobación de seguridad breve con la API plana
Para la mayoría de los pipelines, cuatro llamadas planas responden las preguntas cotidianas. LoadFromFile devuelve 1 si tiene éxito y, una vez abierto el documento, los inspectores de cifrado informan sobre su estado descifrado:
var
PDF: TPDFlib;
begin
PDF := TPDFlib.Create;
try
if PDF.LoadFromFile('contract.pdf', UserPassword) <> 1 then
raise Exception.Create('Open failed: wrong password or damaged file');
Writeln('status : ', PDF.EncryptionStatus); // decrypted / encrypted / unknown
Writeln('algorithm : ', PDF.EncryptionAlgorithm); // RC4 vs AES family
Writeln('strength : ', PDF.EncryptionStrength); // clase de longitud de clave
Writeln('owner pw? : ', PDF.CheckPassword(CandidatePassword));
finally
PDF.Free;
end;
end;
CheckPassword importa más de lo que su firma de una línea sugiere. PDF define dos contraseñas con poder desigual. La contraseña de usuario es necesaria para abrir el archivo. La contraseña de propietario concede todos los derechos y anula cada bit de permiso. Los bytes en disco son idénticos de cualquier manera, pero una sesión abierta con la contraseña de propietario puede hacer cosas que la sesión con contraseña de usuario no puede, por lo que una auditoría que no registra qué credencial se presentó está registrando media verdad. La capa de clases permite consultar la diferencia. TPDFDocument.HasUserPassword y HasOwnerPassword informan qué exige el archivo, mientras que IsUserPassword e IsOwnerPassword informan qué contraseña abrió realmente la sesión actual. Registre ese dato. Nunca registre los valores de las contraseñas
La escala Strength, donde "AES-256" significa dos cosas
Las funciones planas Encrypt y EncryptFile aceptan un Strength entero con cinco valores significativos: 0 para RC4 de 40 bits, 1 para RC4 de 128 bits, 2 para AES de 128 bits legible desde Acrobat 7, 3 para AES de 256 bits introducido con Acrobat 9 y 4 para AES de 256 bits requerido por Acrobat X y versiones posteriores
La parte interesante es que 3 y 4 se etiquetan como AES-256 y no son el mismo esquema. Strength 3 se asigna a la revisión 5 del controlador de seguridad, un diseño provisional que Acrobat 9 distribuyó y que ISO nunca adoptó. Strength 4 se asigna a la revisión 6, cuya función de derivación de claves fue reforzada y estandarizada en ISO 32000-2. Para un documento que está creando hoy no hay razón para elegir 3 en lugar de 4. En una auditoría, la diferencia es decisiva: una política que dice "AES-256 según ISO 32000-2" se cumple solo con R6, y un archivo R5 que se llama a sí mismo AES-256 incumple esa política mientras supera una comprobación ingenua de Strength. La capa de clases mantiene ambos separados por nombre, esAES256Bit para R5 frente a esAES256BitAcroX para R6, y la propiedad EncryptionAcroX responde la pregunta de revisión con un solo booleano
Bits de permisos y la letra pequeña sobre la longitud de clave
EncodePermissions empaqueta ocho indicadores en el entero que esperan Encrypt y EncryptFile. Imprimir, copiar, cambiar y agregar notas componen el conjunto básico; llenar campos, copiar para accesibilidad, ensamblar e imprimir con calidad completa componen el conjunto extendido. La letra pequeña, que la propia demostración de cifrado de la biblioteca expresa claramente, es que los cuatro extendidos tienen efecto solo con Strength de 128 bits o superior. El indicador de impresión de calidad completa sigue la misma regla: desactívelo para forzar impresión de baja resolución y un documento de 40 bits lo ignorará, porque esa degradación también requiere cifrado de 128 bits o más. Codifique una política de "solo impresión de baja resolución" en un archivo de 40 bits y todos los visores imprimirán en calidad completa de todos modos
La pregunta más profunda es quién aplica alguno de esos bits, y la respuesta es nadie en quien pueda confiar. Los permisos son instrucciones para lectores conformes, no restricciones criptográficas. La clave de descifrado es idéntica, ya sea que se permita o se niegue la copia, de modo que un conjunto de permisos restrictivo solo mantiene honestos a los visores honestos. Un lector que decide ignorar los bits no enfrenta ningún obstáculo criptográfico. Si la obligación es impedir la extracción en lugar de desalentarlo, el archivo necesita una contraseña de usuario y el flujo de trabajo necesita controles de proceso a su alrededor, y un informe de auditoría debe indicar bajo cuál de los dos regímenes se encuentra realmente cada archivo en vez de tratar un indicador de permisos como un candado
Establecer una política y demostrar que quedó aplicada
Aplicar cifrado a archivos existentes no exige cargarlos en el árbol de objetos. EncryptFile procesa la entrada hacia la salida en una sola llamada, y el ciclo de auditoría vuelve a abrir el resultado para confirmar qué llegó al disco. La demostración de cifrado incluida sigue la misma forma de escribir y luego leer de vuelta:
var
PDF: TPDFlib;
R: Integer;
begin
PDF := TPDFlib.Create;
try
R := PDF.EncryptFile('in.pdf', 'out.pdf', 'owner-secret', 'user-secret', 4,
PDF.EncodePermissions(1, 0, 0, 0, // print allowed; copy/change/notes denied
0, 0, 0, 1)); // set extendido: solo impresión a calidad completa
if (R = 1) and (PDF.LoadFromFile('out.pdf', 'user-secret') = 1) then
begin
Writeln('algorithm = ', PDF.EncryptionAlgorithm);
Writeln('strength = ', PDF.EncryptionStrength);
Writeln('owner pw accepted: ', PDF.CheckPassword('owner-secret'));
end;
finally
PDF.Free;
end;
end;
Los equipos que trabajan en la capa de documentos obtienen la misma operación con conjuntos tipados en vez de empaquetado de bits, algo que sobrevive a una revisión de código con mucho menos esfuerzo:
if not Doc.Encrypt('owner-secret', 'user-secret', esAES256BitAcroX,
[ppCanPrint], [ppCanPrintFull]) then
raise Exception.Create('Encryption failed');
De cualquier manera, el paso de lectura de vuelta no es una ceremonia opcional. Detecta los errores de despliegue que de otro modo aparecen meses después en la máquina de un cliente: una compilación antigua de la biblioteca que reduce silenciosamente la Strength solicitada, una ruta de salida que nunca se escribió porque el directorio era de solo lectura, un entero de permisos cuyos argumentos se introdujeron en el orden equivocado. Los tres superan una prueba de humo local y fallan en producción, y volver a abrir la salida convierte cada uno en una excepción que verá durante la ejecución que creó el archivo. GetEncryptionFingerprint devuelve un valor compacto que puede guardar con el registro del trabajo, de modo que una comparación posterior puede indicar si dos salidas comparten la misma configuración de cifrado sin volver a abrir ninguna
Falsos positivos de auditoría para los que conviene programar
Algunos patrones llevan de forma fiable a los escáneres de seguridad a la conclusión equivocada, y cada uno proviene de reducir una pregunta de varias partes a una respuesta de sí o no. El filtro criptográfico Identity es el ejemplo más claro. Hay un diccionario /Encrypt, el archivo se informa como cifrado y, sin embargo, las cadenas y los streams pasan sin cambios por el filtro Identity, por lo que el contenido real es texto plano. Leer StringFilterIdentity y StreamFilterIdentity antes de declarar algo protegido es la corrección
La separación de metadatos es más sutil. EncryptMetadata puede diferir del resto del documento en ambas direcciones, dejando un archivo cifrado con un paquete XMP legible o, con menor frecuencia, lo contrario. "El archivo está cifrado" no dice nada sobre si sus metadatos lo están, lo que importa en cuanto un indexador o una regla de enrutamiento busca el título. Los archivos incrustados agregan un tercer eje: PDF permite un filtro criptográfico dedicado solo para adjuntos, de modo que los adjuntos pueden ser la única parte cifrada de un documento que por lo demás está abierto, o la única parte en texto plano de uno cifrado. Capture las tres asignaciones de filtro como campos independientes para cadenas, streams y archivos incrustados, y ninguna de estas trampas podrá sorprenderlo. Guarde un solo booleano y la llamada equivocada será solo cuestión de tiempo
Eliminar el cifrado y elegirlo para archivos nuevos
Una auditoría suele terminar con la decisión de quitar la protección, y la mecánica no es el obstáculo. DecryptFile(InputFileName, OutputFileName, Password) escribe una copia descifrada sin una carga completa, y Decrypt del documento cargado hace lo mismo en memoria una vez abierto el archivo. Ambos requieren una contraseña válida; ninguno evita la criptografía. La verdadera puerta es de política, no de código, así que haga que sus reglas de admisión indiquen con claridad cuándo se permite la eliminación y registre la clase de contraseña que la autorizó, porque el paso técnico por sí mismo no deja rastro
La elección para una salida nueva es más limitada de lo que implican los cinco valores Strength. Use Strength 4, AES-256 revisión 6, salvo que deba abrir archivos en visores anteriores a Acrobat X. Strength 2, AES-128, es el mínimo práctico para un parque de visores antiguos que no se puede actualizar. Las opciones RC4 en 0 y 1 están para que pueda leer y auditar archivos históricos, no para producir nada nuevo con ellas; recurrir a ellas en un diseño de 2026 es señal de que un requisito anterior está desactualizado
El estado de cifrado influye directamente en las decisiones de firma, ya que un banco de trabajo que valida y firma documentos necesita la misma disciplina de lectura de vuelta en la que se apoya esta auditoría. Ese tema se trata en el artículo sobre el banco de trabajo de conformidad y firma. Cuando un lote aplica EncryptFile a miles de documentos grandes, la guía de acceso directo para PDF grandes muestra cómo mantener estable el uso de memoria durante la ejecución. La referencia completa de la API de cifrado está en la página del producto PDF Library for Delphi