Cifrado (HasSecurity)
El trait HasSecurity en Document proporciona cifrado AES-256 a través del motor Aes256Encryptor. TCPDF-Next implementa exclusivamente el manejador de seguridad PDF 2.0 (AESV3, Revision 6, V5) — RC4 y AES-128 se eliminaron deliberadamente. Las contraseñas se normalizan a través de SASLprep (RFC 4013) para el manejo adecuado de Unicode, y la derivación de claves usa el Algoritmo 2.B (SHA-256/384/512 iterativo).
Referencia rápida
| Método | Descripción |
|---|---|
setProtection() | Habilitar cifrado AES-256 con permisos y contraseñas |
Habilitar el cifrado
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->setProtection(
permissions: ['print', 'copy'],
userPass: 'reader-password',
ownerPass: 'owner-secret-password',
)
->addPage()
->setFont('Helvetica', '', 12)
->cell(0, 10, 'This PDF is AES-256 encrypted', newLine: true)
->save('encrypted.pdf');setProtection() retorna static, por lo que se encadena con cualquier otro método de Document.
$pdf->setProtection(
array $permissions = [], // Banderas de permisos (ver tabla a continuación)
string $userPass = '', // Contraseña requerida para abrir el documento
string $ownerPass = '', // Contraseña para acceso sin restricciones
);Contraseña de usuario vs contraseña de propietario
- Contraseña de usuario — el lector debe ingresar esta contraseña para abrir y ver el PDF. Cuando está vacía, el documento se abre sin solicitud pero las restricciones de permisos siguen aplicándose.
- Contraseña de propietario — otorga acceso completo al documento, omitiendo todas las restricciones de permisos. Cuando está vacía, se genera internamente una contraseña de propietario aleatoria de 32 bytes.
Ambas contraseñas se normalizan a través de SASLprep (RFC 4013) antes de la derivación de claves. Esto asegura que las contraseñas Unicode como "Pässwörd" se manejen de forma consistente en todos los visores PDF.
Banderas de permisos
Pasa cualquier combinación de estas banderas de cadena en el arreglo $permissions:
| Bandera | Descripción |
|---|---|
print | Permitir impresión (baja resolución) |
modify | Permitir modificación de contenido |
copy | Permitir extracción de texto e imágenes |
annotate | Permitir agregar anotaciones |
fill-forms | Permitir llenado de campos de formulario |
extract | Permitir extracción de accesibilidad |
assemble | Permitir inserción, rotación y eliminación de páginas |
print-highres | Permitir impresión de alta resolución |
Cuando $permissions está vacío, todas las operaciones están restringidas (se requiere contraseña de propietario para cualquier acción).
Cifrado solo de propietario
Para restringir permisos sin requerir contraseña para abrir:
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->setProtection(
permissions: ['print', 'fill-forms'],
ownerPass: 'admin-password',
)
->addPage()
->setFont('Helvetica', '', 12)
->cell(0, 10, 'Open freely, but only print and fill forms.', newLine: true)
->save('restricted.pdf');El documento se abre sin solicitud de contraseña, pero la modificación, copia y anotación están bloqueadas a menos que se proporcione la contraseña de propietario.
Arquitectura de seguridad
TCPDF-Next aplica exclusivamente el estándar de cifrado PDF más fuerte:
- Algoritmo: AES-256-CBC (AESV3), Revision 6, V5
- Longitud de clave: 256 bits
- Sin legado: RC4 y AES-128 se eliminaron deliberadamente
Normalización de contraseñas SASLprep
La clase SaslPrep (RFC 4013) normaliza contraseñas con normalización Unicode NFKC, rechaza caracteres prohibidos y aplica restricciones de texto bidireccional. Esto asegura hashes idénticos independientemente de la plataforma o método de entrada.
Derivación de claves — Algoritmo 2.B
El Algoritmo 2.B de ISO 32000-2 deriva la clave de cifrado a través de hashing iterativo SHA-256/384/512 (hasta 64 rondas), proporcionando fuerte resistencia contra ataques de fuerza bruta.
Incompatibilidad con PDF/A
El cifrado no está permitido en documentos compatibles con PDF/A. Si intentas llamar a setProtection() en un documento que tiene el modo PDF/A habilitado, se lanza una PdfAException:
use Yeeefang\TcpdfNext\Core\Document;
// Esto lanzará PdfAException
$pdf = Document::create()
->setPdfA(true)
->setProtection(permissions: ['print'], ownerPass: 'secret');
// -> throws PdfAException: "Encryption is not allowed in PDF/A documents"Si necesitas tanto cumplimiento de archivo como control de acceso, considera usar firmas digitales con restricciones de permisos en su lugar.
Ejemplo completo
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->setTitle('Confidential Report')
->setAuthor('Security Team')
->setProtection(
permissions: ['print-highres', 'copy'],
userPass: 'open-me',
ownerPass: 'full-access-2026',
)
->addPage()
->setFont('Helvetica', 'B', 18)
->cell(0, 15, 'Confidential Report', newLine: true)
->setFont('Helvetica', '', 12)
->multiCell(0, 6, 'This document is protected with AES-256 encryption. '
. 'Readers can print and copy, but cannot modify or annotate.')
->save('confidential-report.pdf');