Pular para o conteúdo

Criptografia: AES-256-CBC e AES-256-GCM

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.

Terminal window
composer require nextpdf/core:^3

O 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.

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.

TipoCategoriaMembros principaisEstabilidadeDesde
Aes256Encryptorclasseencrypt(), decrypt(), encryptForObject(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms(), getEncryptionKey()estável1.0.0
Aes256GcmEncryptorclasseencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount(), isAvailable()estável2.18.0
KeyMaterialclasse final readonlygenerate(), exposeKey(), fingerprint()estável2.18.0
EncryptedPayloadSpecclasse final readonlytoDict()estável2.18.0
CryptoCapabilitiesclasse finalhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()estável2.0.0
NonceReuseExceptionexceçãoestável2.18.0
TamperedDataExceptionexceçãoestável2.18.0
DecryptionFailedExceptionexceçãoestável2.18.0
GcmInvocationLimitExceededExceptionexceçãoestável3.0.0
examples/22-protection.php
<?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');
examples/security/gcm-authenticated-encryption.php
<?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.

  • 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 nem openssl nem ext-sodium oferecem 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 − 256 bytes. Uma entrada maior lança uma exceção de comprimento; particione o conteúdo entre múltiplos objetos com encryptStream().
  • Uma instância de KeyMaterial deve 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.

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.

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.

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.

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.

AmeaçaMitigação no CoreLimite residual
Adivinhação de senha offlineSASLprep mais derivação iterada da revisão 6Uma senha fraca ainda é o risco dominante
Modificação do texto cifradoVerificaçã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 longoVerificação de comprimento em 2^39 − 256; orientação de particionamentoO chamador deve transmitir entradas grandes
Uso excessivo de chave (GCM)assertWithinSafetyBound() em 2^32Opcional; não imposto por padrão
Bypass de flag de permissãoNenhuma — as flags são consultivasUm leitor não compatível ignora as flags
Divulgação de chave via logsKeyMaterial é ocultado; #[\SensitiveParameter]Um chamador que registra exposeKey() anula essa proteção

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.

AfirmaçãoNormaCláusulaEvidê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.1C_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.

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.