Criptografia: AES-256-CBC e AES-256-GCM
Visão geral
Seção intitulada “Visão geral”O Core criptografa arquivos Portable Document Format (PDF) com AES-256 (Advanced Encryption Standard com chaves de 256 bits) pelo manipulador de segurança padrão da ISO 32000-2:2020 §7.6. O modo padrão é V=5 / R=6 / AESV3 (AES-256-CBC, Cipher Block Chaining). O modo autenticado opcional é o caminho AES-256-GCM (Galois/Counter Mode) V=6 / R=7 da ISO/TS 32003:2023. Esta página define a derivação de chave, o formato de transmissão, o limite das permissões e os limites de implantação.
Instalação
Seção intitulada “Instalação”composer require nextpdf/core:^3O caminho padrão exige a extensão openssl. O caminho AES-256-GCM usa openssl ou ext-sodium. Em hosts sem hardware AES-NI, a libsodium recusa o GCM; o Core recorre à implementação mais lenta do OpenSSL sem alterar o algoritmo.
Visão conceitual
Seção intitulada “Visão conceitual”O manipulador padrão usa o manipulador de segurança padrão V=5 / R=6 com o filtro de criptografia AESV3. Quando você chama setEncryption(), o Core gera uma chave de arquivo aleatória de 256 bits a partir da fonte criptográfica aleatória da plataforma (random_bytes()). A chave tem 32 bytes, correspondendo ao comprimento de chave da FIPS 197. O Core criptografa o conteúdo por objeto com AES-256-CBC. Ele prefixa cada texto cifrado com o vetor de inicialização de 16 bytes, conforme determina a ISO 32000-2:2020 §7.6.4.
A derivação de chave segue o Algoritmo 2.B na revisão 6. O Core primeiro normaliza a senha com SASLprep (RFC 4013) e depois a trunca para 127 bytes UTF-8 em um limite de caractere, conforme determina a ISO 32000-2:2020 §7.6.4.3.3. Ele calcula o hash derivado com uma rotina iterada de SHA-256 / SHA-384 / SHA-512 conduzida por uma etapa AES-128-CBC, elevando o custo de adivinhação de senha offline. O Core gera os salts de usuário, de proprietário e por chave uma vez por instância do criptografador, de modo que uma instância emita bytes de dicionário determinísticos, uma precondição para um gravador de múltiplas passagens.
useAesGcm() ativa o caminho opcional AES-256-GCM. Ele implementa o filtro de criptografia AESV4 V=6 / R=7 da ISO/TS 32003:2023. A cifra é AES-256-GCM com parâmetros da NIST SP 800-38D. Para cada objeto criptografado, o layout de transmissão contém um IV de 12 bytes, o texto cifrado e uma tag de autenticação de 16 bytes. Os dados autenticados adicionais ficam vazios, conforme determina o perfil §5.2 da TS 32003. A descriptografia verifica a tag e lança TamperedDataException em caso de incompatibilidade; ela nunca retorna texto simples depois de uma tag malsucedida. Esse caminho adiciona a detecção de modificação que o caminho CBC padrão não fornece por si só.
O caminho GCM segue a disciplina de unicidade de IV da NIST SP 800-38D §8. Os 4 bytes superiores do IV são um campo fixo por instância, definido a partir de uma fonte aleatória durante a construção. Os 8 bytes inferiores são um contador big-endian incrementado após cada IV emitido. Isso segue a abordagem de construção determinística da §8.2.1, exceto que o campo fixo é aleatorizado para evitar colisões entre documentos, em vez de ser enumerado. Uma segunda proteção registra cada IV emitido em um conjunto de colisões e lança NonceReuseException se um valor se repetir. O estouro do contador também lança NonceReuseException, porque esse estouro é o modo de falha de reutilização de IV contra o qual a §8 alerta.
Dois limites de comprimento se aplicam ao caminho GCM. O teto de texto simples por objeto é de 2^39 − 256 bytes, o limite por invocação derivado na NIST SP 800-38D §5.2.1.1. Uma entrada maior lança uma exceção de comprimento com orientação para particionar os dados entre objetos. O limite de segurança de invocação é de 2^32 chamadas por chave. assertWithinSafetyBound() é uma verificação opcional que lança GcmInvocationLimitExceededException, permitindo que o chamador rotacione a chave do documento antes do limiar da §8.3. A NIST SP 800-57 Parte 1 §4 trata essa decisão de tempo de vida da chave como uma responsabilidade de implantação.
As flags de permissão são consultivas. O Core grava a máscara de bits na entrada criptografada /Perms e no valor /P, depois a recupera com validatePerms() na leitura, que falha de forma fechada quando encontra um marcador corrompido. Espera-se que um leitor compatível respeite as flags. As flags não são impostas por criptografia: um processador que tenha a chave de descriptografia e ignore os bits pode ler, copiar ou modificar o conteúdo. Descreva as flags de permissão como uma convenção de leitor, não como controle de acesso.
Superfície da API
Seção intitulada “Superfície da API”| Tipo | Categoria | Membros principais | Estabilidade | Desde |
|---|---|---|---|---|
Aes256Encryptor | classe | encrypt(), decrypt(), encryptForObject(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms(), getEncryptionKey() | estável | 1.0.0 |
Aes256GcmEncryptor | classe | encrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount(), isAvailable() | estável | 2.18.0 |
KeyMaterial | classe final readonly | generate(), exposeKey(), fingerprint() | estável | 2.18.0 |
EncryptedPayloadSpec | classe final readonly | toDict() | estável | 2.18.0 |
CryptoCapabilities | classe final | hasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile() | estável | 2.0.0 |
NonceReuseException | exceção | — | estável | 2.18.0 |
TamperedDataException | exceção | — | estável | 2.18.0 |
DecryptionFailedException | exceção | — | estável | 2.18.0 |
GcmInvocationLimitExceededException | exceção | — | estável | 3.0.0 |
Exemplo de código — Início rápido
Seção intitulada “Exemplo de código — Início rápido”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
// AES-256-CBC, V=5/R=6. Call before addPage().$doc->setEncryption( userPassword: 'demo', ownerPassword: 'admin', permissions: 4, // printing only; copy/modify denied for a conforming reader);
$doc->addPage();$doc->setFont('helvetica', '', 12);$doc->cell(0, 8, 'Confidential', newLine: true);
$doc->save(__DIR__ . '/output/22-protection.pdf');Exemplo de código — Produção
Seção intitulada “Exemplo de código — Produção”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Security\CryptoCapabilities;use NextPDF\Security\Encryption\Aes256GcmEncryptor;use NextPDF\Security\Exception\TamperedDataException;use NextPDF\Security\KeyMaterial;use Psr\Log\LoggerInterface;
final readonly class AuthenticatedBlobCipher{ public function __construct(private LoggerInterface $logger) {}
/** * Seal a payload with AES-256-GCM and return the wire-format bytes. * * @param non-empty-string $plaintext The payload to protect. * * @return non-empty-string IV(12) || ciphertext || tag(16). */ public function seal(string $plaintext, KeyMaterial $key): string { if (!CryptoCapabilities::hasAesGcm()) { throw new \RuntimeException('Host cannot perform AES-256-GCM.'); }
$cipher = new Aes256GcmEncryptor($key); // Opt-in NIST SP 800-38D §8.3 key-rotation guard. $cipher->assertWithinSafetyBound();
$wire = $cipher->encrypt($plaintext);
$this->logger->info('Payload sealed', [ 'key_fingerprint' => $key->fingerprint(), 'invocations' => $cipher->invocationCount(), ]);
return $wire; }
/** * Open a sealed payload; a modified payload raises, never returns plaintext. * * @param non-empty-string $wire IV(12) || ciphertext || tag(16). */ public function open(string $wire, KeyMaterial $key): string { try { return (new Aes256GcmEncryptor($key))->decrypt($wire); } catch (TamperedDataException $e) { $this->logger->warning('Tampered payload rejected', [ 'key_fingerprint' => $key->fingerprint(), ]);
throw $e; } }}A cifra verifica a capacidade do host, aplica a proteção opcional de invocação, registra apenas a impressão digital não reversível da chave e relança rejeições de adulteração em vez de retornar bytes suspeitos.
Casos extremos e armadilhas
Seção intitulada “Casos extremos e armadilhas”- O caminho padrão AES-256-CBC fornece apenas confidencialidade. Ele não detecta texto cifrado modificado por si só. Use o caminho AES-256-GCM quando precisar de detecção de modificação.
useAesGcm()lança uma exceção quando o modo PDF/A está ativo e quando nemopensslnemext-sodiumoferecem AES-256-GCM. Capture ambos os casos e exiba uma mensagem acionável para o operador.- Em hosts sem AES-NI, a libsodium recusa o GCM. O Core recorre ao GCM do OpenSSL, que é correto, mas mais lento; o que cai é a taxa de transferência, não a segurança.
- O teto de texto simples por objeto do GCM é de
2^39 − 256bytes. Uma entrada maior lança uma exceção de comprimento; particione o conteúdo entre múltiplos objetos comencryptStream(). - Uma instância de
KeyMaterialdeve ter exatamente 32 bytes. A construção rejeita um comprimento incorreto em vez de truncá-lo. - O caminho de leitura (
verifyUserPassword(),verifyOwnerPassword(),validatePerms()) usa comparação de tempo constante para material criptográfico e falha de forma fechada em um marcador de permissão corrompido.
Desempenho
Seção intitulada “Desempenho”A criptografia AES-256-CBC por objeto é uma chamada do OpenSSL e é O(n) no corpo do objeto. A derivação de chave executa a rotina iterada do Algoritmo 2.B uma vez por instância do criptografador; o custo é limitado e constante por documento. O caminho de streaming AES-256-GCM particiona a entrada em blocos de 16 MiB, limitando o uso de heap ativo a aproximadamente 64 MB, independentemente do tamanho total da entrada, e mantendo-se abaixo do orçamento de pico documentado de 64 MB. Cada objeto GCM adiciona 28 bytes de overhead (IV de 12 bytes mais tag de 16 bytes). O hardware AES-NI melhora materialmente a taxa de transferência do GCM; sem ele, apenas a taxa de transferência cai.
Notas de segurança
Seção intitulada “Notas de segurança”Esta superfície de criptografia tem um modelo de ameaças explícito. A normalização SASLprep mais a derivação de chave iterada da revisão 6 elevam o custo de adivinhação de senha offline, mas uma senha fraca continua sendo o risco residual dominante. Nenhuma derivação elimina esse risco. O caminho GCM detecta a modificação do texto cifrado por meio da verificação da tag; o caminho CBC padrão não detecta. No caminho GCM, um contador mais um conjunto de colisões evitam a reutilização de IV, em conformidade com a disciplina de IV da NIST SP 800-38D §8.1. O estouro do contador recusa a operação em vez de circular. A ocultação de KeyMaterial e o atributo #[\SensitiveParameter] nas senhas mitigam a divulgação de chaves por meio de logs. O material de chave derivado é zerado após o uso onde a plataforma permite.
O limite também é explícito. O Core aplica a criptografia AES-256 conforme definido na ISO 32000-2:2020 §7.6 e, para o caminho opcional, na ISO/TS 32003:2023 §5.2. A proteção efetiva depende da força da senha, do gerenciamento de chaves, do ambiente de implantação e do leitor consumidor. Leitores compatíveis respeitam as flags de permissão, mas a criptografia não as impõe. A etapa AES-ECB usada para o valor /Perms é exigida pela ISO 32000-2:2020 §7.6.4.4.10 para um único bloco de 16 bytes. Ela não é um modo de uso geral. O Core expõe uma verificação para a rotação de chave antes do limite de 2^32 invocações, mas não a impõe por padrão; essa rotação é uma responsabilidade de implantação.
Residência de dados e mitigações de PII
Seção intitulada “Residência de dados e mitigações de PII”A criptografia e a descriptografia são executadas em processo; nenhum byte do documento, senha ou valor de chave deixa o host por meio desta superfície. O conjunto de colisões de IV do GCM é indexado por uma impressão digital de chave não reversível, não pelos bytes da chave. Se uma implantação coloca a chave atrás de um sistema externo de gerenciamento de chaves ou de um token PKCS#11, esse backend é responsável pela residência; o C_GenerateKey do OASIS PKCS#11 v3.1 é o ponto de contrato para gerar chaves residentes no token.
Telemetria segura e limpeza de logs
Seção intitulada “Telemetria segura e limpeza de logs”Registre o nome da política e a impressão digital de chave de 8 caracteres, nunca a chave ou a senha. KeyMaterial::__toString() e __debugInfo() retornam um placeholder ocultado. As exceções desta superfície incluem um rótulo de operação e uma impressão digital, não bytes de chave. A contagem de invocações do GCM é telemetria segura para painéis de rotação de chaves.
Modelo de ameaças
Seção intitulada “Modelo de ameaças”| Ameaça | Mitigação no Core | Limite residual |
|---|---|---|
| Adivinhação de senha offline | SASLprep mais derivação iterada da revisão 6 | Uma senha fraca ainda é o risco dominante |
| Modificação do texto cifrado | Verificação de tag GCM (caminho opcional) | O caminho CBC é somente de confidencialidade |
| Reutilização de IV (GCM) | Campo fixo aleatório mais contador mais conjunto de colisões; o estouro recusa | — |
| Texto simples GCM excessivamente longo | Verificação de comprimento em 2^39 − 256; orientação de particionamento | O chamador deve transmitir entradas grandes |
| Uso excessivo de chave (GCM) | assertWithinSafetyBound() em 2^32 | Opcional; não imposto por padrão |
| Bypass de flag de permissão | Nenhuma — as flags são consultivas | Um leitor não compatível ignora as flags |
| Divulgação de chave via logs | KeyMaterial é ocultado; #[\SensitiveParameter] | Um chamador que registra exposeKey() anula essa proteção |
Comportamento do modo FIPS
Seção intitulada “Comportamento do modo FIPS”O Core não é um módulo criptográfico validado por FIPS nem é certificado pela FIPS. CryptoCapabilities::detectFipsMode() é uma sondagem de melhor esforço que reporta ativo, ausente ou indeterminado. assertFipsAvailableForProfile() falha de forma fechada quando um perfil FIPS é selecionado em um host que não comprova um provedor FIPS. A superfície de criptografia opera em um modo compatível com FIPS quando é executada em uma compilação OpenSSL do host que carregou um provedor validado por FIPS. Uma postura validada e certificada é uma preocupação da edição Enterprise.
Conformidade
Seção intitulada “Conformidade”| Afirmação | Norma | Cláusula | Evidência |
|---|---|---|---|
| Cada IV do GCM é único por invocação por meio de uma construção determinística de campo fixo mais contador. | NIST SP 800-38D | §8.2.1 | |
| A disciplina de construção de IV evita a reutilização entre invocações em uma chave. | NIST SP 800-38D | §8.1 | |
| O teto de texto simples por objeto corresponde ao limite de comprimento por invocação. | NIST SP 800-38D | §5.2.1.1 | |
| O criptoperíodo da chave e sua rotação são uma responsabilidade de implantação. | NIST SP 800-57 Parte 1 Rev. 5 | §4 | |
| A chave de arquivo AES tem 256 bits, correspondendo ao comprimento de chave da norma. | FIPS 197 | §4.2.1 | |
| A geração de chaves residentes no token é o ponto de integração com o armazenamento externo de chaves. | OASIS PKCS#11 v3.1 | C_GenerateKey |
A ISO 32000-2:2020 §7.6 e a ISO/TS 32003:2023 §5.2 são a base normativa para os manipuladores documentados aqui. O texto dessas normas é restrito por licença. Esta página as parafraseia, cita cláusulas por número e não reproduz nenhuma delas literalmente. O teste de normas do Algoritmo 2.B e a fixture de oráculo externo no rodapé de evidências da página fornecem a evidência de tempo de execução verificada para a derivação de chave byte-exata.
Contexto comercial
Seção intitulada “Contexto comercial”O Core inclui o caminho padrão AES-256-CBC, o caminho opcional AES-256-GCM, uma superfície de chave local e o gate da política de criptografia. A edição Enterprise adiciona um backend de custódia de chaves HSM/PKCS#11 e um perfil de política de criptografia em modo FIPS por trás dos mesmos contratos. A interface pública de programação de aplicações (API) é idêntica; o que difere é o backend de custódia de chaves e a implementação da política.
Veja também
Seção intitulada “Veja também”- Segurança — a visão geral do módulo de segurança e o limite das permissões.
- Contracts / Security Policy — o contrato de política de criptografia que controla a cifra.
- Security / Signing — assinaturas e carimbos de tempo, a superfície criptográfica irmã.
- Conformance — a proibição da chave
Encryptpelo PDF/A.