Pular para o conteúdo

Segurança: criptografia, política de criptografia e superfície de assinatura

O módulo de segurança do Core aplica criptografia a documentos com Advanced Encryption Standard de 256 bits (AES-256), encaminha cada escolha de algoritmo por um contrato de política de criptografia e expõe pontos de integração para um serviço de gerenciamento de chaves gerenciado pela implantação. A proteção efetiva do documento depende do manuseio das chaves, da força da senha, do leitor que consome o documento e do ambiente de implantação. Esta página declara esses limites com clareza.

Terminal window
composer require nextpdf/core:^3

O módulo de segurança tem três superfícies. A superfície de criptografia usa o ponto de entrada de documento setEncryption() para configurar o handler de segurança Standard AES-256. O controle de política de criptografia usa CryptoPolicyInterface para decidir quais hashes, assinaturas, cifras e forças de chave uma implantação permite. A superfície de assinatura é mencionada aqui, mas documentada separadamente; consulte Assinatura.

A criptografia usa AES-256 conforme definido em ISO 32000-2:2020 §7.6. O caminho padrão é o handler de segurança Standard V=5 / R=6 com o crypt filter AESV3. A chave do arquivo tem 32 bytes (256 bits), o que corresponde ao Federal Information Processing Standards (FIPS) 197. Um caminho opcional adiciona criptografia autenticada ISO/TS 32003:2023 V=6 / R=7 AES-256 em Galois/Counter Mode (AES-256-GCM). A página detalhada documenta os dois caminhos: Criptografia.

O controle de política de criptografia é um predicado de negar ou permitir. O Core consulta CryptoPolicyInterface antes de qualquer etapa de assinatura, criptografia ou hashing. Se nenhuma política for definida, o Core permite todos os algoritmos. Esse padrão aberto é adequado para desenvolvimento, mas não para produção. Uma implantação regulada deve definir uma política explícita. Contracts / Security Policy documenta a superfície do contrato.

As flags de permissão são a fonte mais comum de afirmações exageradas, por isso esta página as trata de forma explícita. A bitmask de permissão é armazenada na entrada criptografada /Perms e no valor /P. Espera-se que um leitor em conformidade respeite essas restrições. As flags não são impostas pela criptografia. Um processador que ignora os bits ainda pode ler, copiar ou modificar o conteúdo depois de obter a chave de descriptografia. Declare esse limite a qualquer parte que dependa das flags de permissão.

O gerenciamento de chaves e a integração com Public-Key Cryptography Standards #11 (PKCS#11) são pontos de contrato. O Core inclui um caminho de chave local. O value object KeyMaterial encapsula uma chave de 256 bits com comprimento verificado e evita divulgação nas saídas de string e de depuração. O caminho de custódia de chave via hardware security module (HSM)/PKCS#11 é um recurso Enterprise controlado pelos mesmos contratos; esta página nomeia o ponto de integração, mas não documenta a implementação Enterprise.

TipoCategoriaMembros principaisEstabilidadeDesde
Document::setEncryption()método (concern HasSecurity)userPassword, ownerPassword, permissionsestável1.0.0
Document::useAesGcm()método (concern HasSecurity)?bool $enabled — opcional ISO/TS 32003 V=6/R=7estável2.18.0
Aes256Encryptorclasseencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()estável1.0.0
Aes256GcmEncryptorclasseencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()estável2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()estável2.18.0
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()estável1.9.0
Config::withCryptoPolicy()métodoCryptoPolicyInterface $policyestável1.9.0
CryptoCapabilitiesfinal classhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()estável2.0.0
examples/22-protection.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Encrypted Document — Restricted Permissions');
// Call setEncryption() BEFORE addPage().
// Permission bit 3 (value 4) = printing allowed; all other operations denied.
$doc->setEncryption(
userPassword: 'demo',
ownerPassword: 'admin',
permissions: 4,
);
$doc->addPage();
$doc->setFont('helvetica', 'B', 20);
$doc->cell(0, 14, 'Encrypted PDF Document', newLine: true);
$doc->save(__DIR__ . '/output/22-protection.pdf');

A senha de usuário abre o documento. A senha de proprietário concede acesso total. As flags de permissão restringem apenas leitores em conformidade.

examples/security/policy-gated-encryption.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;
use NextPDF\Core\Document;
use Psr\Log\LoggerInterface;
final readonly class PolicyGatedEncryption
{
public function __construct(
private CryptoPolicyInterface $cryptoPolicy,
private LoggerInterface $logger,
) {}
/**
* Encrypt only when the active policy permits AES-256-CBC.
*
* @param non-empty-string $userPassword Opens the document.
* @param non-empty-string $ownerPassword Grants full access.
*/
public function protect(
Document $doc,
string $userPassword,
string $ownerPassword,
int $permissions,
): void {
if (!$this->cryptoPolicy->isEncryptionAlgorithmAllowed('aes-256-cbc')) {
$this->logger->error('Encryption refused by crypto policy', [
'policy' => $this->cryptoPolicy->getName(),
]);
throw new \RuntimeException('AES-256-CBC denied by the active crypto policy.');
}
$doc->setEncryption($userPassword, $ownerPassword, $permissions);
$this->logger->info('Document encrypted', [
'policy' => $this->cryptoPolicy->getName(),
'algorithm' => 'aes-256-cbc',
]);
}
}

Esse controle consulta a política antes da criptografia, registra o nome da política na trilha de auditoria e lança uma exceção específica quando a política nega a cifra.

  • Chame setEncryption() antes de addPage(). Uma chamada posterior não criptografa retroativamente o conteúdo que o writer já emitiu.
  • O modo PDF/A e a criptografia são mutuamente exclusivos. ISO 19005 proíbe a chave de trailer Encrypt em qualquer variante de PDF/A, portanto setEncryption() e useAesGcm() lançam uma exceção quando um gerenciador de PDF/A está ativo.
  • Dentro de setEncryption(), uma senha de proprietário vazia passa a usar a senha de usuário. Um documento com uma única senha compartilhada concede ao detentor da senha de usuário acesso de nível de proprietário.
  • Quando nenhuma política é injetada, CryptoPolicyInterface permite todos os algoritmos. Trate o padrão aberto como uma conveniência de desenvolvimento e defina uma política explícita em qualquer implantação regulada.
  • As flags de permissão são consultivas para o leitor. Não as descreva como controle de acesso que um processador hostil não possa contornar.

setEncryption() executa uma rotina iterada de derivação de chave (Algorithm 2.B, revision 6) durante a construção do documento. O custo é limitado e constante por documento; ele não escala com a contagem de páginas. A criptografia por objeto realiza uma operação AES por stream ou string. O caminho opcional AES-256-GCM adiciona 28 bytes de sobrecarga por objeto (initialization vector (IV) de 12 bytes mais tag de 16 bytes) e transmite conteúdo grande em blocos de 16 MiB. Isso mantém a operação de streaming abaixo do pico documentado de 64 MB. O performance_budget de 1500 ms de wall e 64 MB de pico é dominado pela renderização do documento, não pela criptografia.

O modelo de ameaças é explícito. O controle de política de criptografia mitiga o downgrade de algoritmo ao recusar cifras fracas, hashes fracos e chaves curtas antes de qualquer operação. O motor não substitui silenciosamente por um primitivo mais fraco quando o solicitado está ausente; ele lança uma exceção para que o operador possa agir. KeyMaterial mitiga a divulgação de chave por meio de logging: suas formas de string e de depuração ocultam os bytes e expõem apenas um fingerprint não reversível. A adulteração de texto cifrado é detectada apenas no caminho opcional AES-256-GCM, onde a tag de autenticação é verificada e uma incompatibilidade lança uma exceção em vez de retornar texto em claro. O caminho padrão AES-256 Cipher Block Chaining (AES-256-CBC) oferece somente confidencialidade e não detecta modificação por si só. No caminho GCM, a reutilização de IV é mitigada por um contador monotônico mais um conjunto de controle de colisões como defesa em profundidade, em conformidade com o requisito de IV único em NIST SP 800-38D §8.

O limite é igualmente explícito. A criptografia AES-256 é aplicada conforme definido em ISO 32000-2:2020 §7.6. A proteção efetiva depende da força da senha, do gerenciamento de chaves, do ambiente de implantação e do leitor que consome o documento. Leitores em conformidade respeitam as flags de permissão, mas a criptografia não as impõe. A sondagem de modo FIPS informa se a build do OpenSSL do host carregou um provedor FIPS. A biblioteca opera em um modo compatível com FIPS quando o host fornece um módulo validado; ela não certifica nenhum módulo. NIST SP 800-57 Part 1 §4 enquadra o tempo de vida da chave e o cryptoperiod como responsabilidades da implantação. O Core expõe os controles, e a implantação define a política de rotação.

A superfície de criptografia não transmite os bytes do documento, incluindo qualquer informação de identificação pessoal (PII) contida neles, para fora do host. A derivação de chave, a criptografia e a descriptografia são executadas em processo. O caminho opcional GCM mantém em memória um índice do conjunto de colisões de IV por fingerprint de chave não reversível, não pelos bytes da chave. O módulo de segurança não grava nenhuma senha nem valor de chave em disco. Uma implantação que encaminha chaves por um serviço externo de gerenciamento de chaves é responsável pela residência desse serviço.

KeyMaterial::__toString() e __debugInfo() retornam um placeholder mascarado, de modo que um log acidental de um objeto de chave gera um fingerprint, não bytes de chave. As senhas passadas para setEncryption() carregam o atributo #[\SensitiveParameter], que as oculta de um stack trace. Para auditorias, use o nome da política de CryptoPolicyInterface::getName() e o fingerprint de chave de 8 caracteres como identificadores da operação de criptografia. Registre esses valores, nunca a chave nem a senha.

AmeaçaMitigação no CoreLimite residual
Downgrade de algoritmo / substituição por cifra fracaControle de política de criptografia; sem degradação silenciosa (lança UnsupportedAlgorithmException)Efetivo apenas quando uma política é injetada
Divulgação de chave por logsKeyMaterial faz o mascaramento; #[\SensitiveParameter] nas senhasUm chamador que passa exposeKey() para um logger anula isso
Adulteração de texto cifradoVerificação da tag GCM no caminho opcionalO caminho padrão CBC oferece somente confidencialidade
Reutilização de IV (GCM)Contador monotônico mais conjunto de colisões; o estouro recusa
Bypass de flag de permissãoNenhuma; as flags são consultivasUm leitor não conforme ignora as flags
Força bruta sobre uma senha fracaSASLprep mais derivação de chave iterada aumenta o custoUma senha fraca permanece o risco dominante

O Core não é um módulo criptográfico validado por FIPS e não possui certificação FIPS. CryptoCapabilities::detectFipsMode() é uma sondagem em tempo de execução de melhor esforço: ela lê uma substituição do operador, depois a lista de provedores do OpenSSL, depois a chamada legada de modo FIPS, e reporta active, absent ou indeterminate. assertFipsAvailableForProfile() falha de modo fechado quando um perfil FIPS é selecionado em um host que não consegue comprovar um provedor FIPS. A biblioteca opera em um modo compatível com FIPS quando é configurada com uma build do OpenSSL do host que carregou um provedor validado por FIPS. Uma postura validada e certificada para FIPS é uma questão Enterprise; consulte a documentação Enterprise.

AfirmaçãoNormaCláusulaEvidência
O caminho GCM mantém cada IV único para uma invocação, em conformidade com o requisito de unicidade da norma.NIST SP 800-38D§8.2.1
O Core expõe controles para o tempo de vida da chave e o cryptoperiod; a implantação é responsável pela política.NIST SP 800-57 Part 1 Rev. 5§4
A chave de arquivo AES tem 256 bits, o que corresponde ao comprimento de chave da norma.FIPS 197§4.2.1
A geração de chave residente no token é o ponto de integração para um armazenamento de chaves externo.OASIS PKCS#11 v3.1C_GenerateKey

ISO 32000-2:2020 §7.6 é a base normativa para o handler de segurança Standard. Seu texto é restrito por licença e é parafraseado aqui, nunca citado; esta página cita a cláusula pelo número. Cada ponto acima é parafraseado da norma citada.

O Core define e estabiliza o contrato de política de criptografia, inclui o caminho de criptografia AES-256 e fornece uma superfície de chave local. A edição Enterprise fornece um caminho de custódia de chave HSM/PKCS#11 e um perfil de política de criptografia em modo FIPS por trás da mesma CryptoPolicyInterface. A superfície do contrato é idêntica entre as edições; a implantação injeta uma implementação de política diferente e um backend de custódia de chave diferente.

  • Security / Encryption — a referência detalhada sobre AES-256 e AES-256-GCM.
  • Contracts / Security Policy — os contratos de política de criptografia e de política de recursos.
  • Security / Signing — PDF Advanced Electronic Signatures (PAdES), Cryptographic Message Syntax (CMS) e timestamps.
  • Audit — logging de auditoria de nome de política e de operação.
  • Conformance — interação do PDF/A com a criptografia.