Technical Article

Encriptação PDF AES-256 no Delphi: Configuração do HotPDF e Cuidados

Uma flag de permissão de um PDF não é um bloqueio. É apenas um pedido que o ficheiro faz ao programa que o abre, o qual o visualizador é livre de ignorar. Este facto único determina a forma como deve analisar todas as outras opções nesta página. A confidencialidade real provém de um único local: a encriptação AES-256 baseada numa palavra-passe que o leitor do ficheiro não possui. Tudo o resto, como as caixas de verificação "sem impressão" e "sem cópia", são políticas que o software compatível aceita respeitar e o software hostil ignora. Se misturar estas duas camadas, arrisca-se a distribuir algo que parece seguro numa demonstração mas que falha em ambiente de produção.

O HotPDF é um componente PDF nativo VCL para Delphi e C++Builder que expõe o modelo de proteção da norma ISO 32000 através de um pequeno conjunto de propriedades. As propriedades são simples de configurar. A dificuldade consiste em saber qual delas lhe garante proteção criptográfica real e qual representa apenas uma sugestão de cortesia, bem como em definir a ordem correta de atribuição para que a encriptação solicitada seja efetivamente aplicada.

O que as duas palavras-passe realmente garantem

A encriptação de PDF define duas credenciais com funções distintas, e confundi-las é o erro de design mais comum em códigos de geração protegida. A palavra-passe do utilizador (user password) controla a desencriptação. Sem ela, ou sem a palavra-passe do proprietário, um leitor compatível não consegue reconstruir a chave do ficheiro e o conteúdo permanece criptograficamente ilegível. Por outro lado, a palavra-passe do proprietário (owner password) controla as definições de permissão: um leitor que receba a palavra-passe do proprietário obtém acesso total, independentemente do que digam as flags de restrição.

Os bits de permissão assentam em bases menos sólidas. Impressão, extração de conteúdo, preenchimento de formulários: cada um destes itens é apenas uma flag que o visualizador lê e decide respeitar (ISO 32000-2 §7.6.4). A encriptação protege os bytes. As flags de permissão apenas instruem o software compatível, e fazem-no após o acesso. Qualquer utilizador que abra o documento com a palavra-passe do utilizador já possui o conteúdo desencriptado em memória, pelo que as restrições de "cópia proibida" ou "impressão proibida" têm significado para um visualizador bem comportado, mas nenhum para um utilizador determinado. Construa o seu modelo de ameaças com base nesta premissa. A confidencialidade reside na palavra-passe do utilizador. As permissões apenas moldam o que os visualizadores comuns oferecem, e nada mais.

Ordem de configuração: tudo antes de BeginDoc

O HotPDF constrói o dicionário de encriptação e gera a chave do ficheiro no momento em que o BeginDoc é executado. O estado das propriedades de proteção nesse instante é o que determina as definições do documento, e alterá-las posteriormente não surtirá qualquer efeito. A propriedade mais importante neste contexto é a CryptKeyLength, que seleciona o esquema a partir dos valores THPDFKeyType (k40, k128, aes128 e aes256). Se a atribuir após o BeginDoc, não receberá qualquer exceção ou aviso, mas sim um ficheiro que manteve silenciosamente as configurações iniciais. Este tipo de divergência silenciosa é o pior cenário: passa em todos os testes locais e manifesta-se meses mais tarde como uma falha de conformidade no ambiente de produção do cliente.

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := 'statement.pdf';
    Pdf.ActivateProtection := True;
    Pdf.CryptKeyLength := aes256;        // must be set before BeginDoc
    Pdf.UserPassword := 'open-secret';
    Pdf.OwnerPassword := 'admin-secret';
    Pdf.UseAES256R6 := False;            // R=5: widest viewer support
    Pdf.BeginDoc;
    Pdf.CurrentPage.SetFont('Arial', [], 11);
    Pdf.CurrentPage.TextOut(50, 720, 0, 'Account statement, June 2026');
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

As palavras-passe são em UTF-8 e estão limitadas a 127 bytes, que é o limite da norma ISO 32000-2 para os esquemas AES-256. Se a sua política de segurança fornecer credenciais mais longas, efetue o corte do seu lado, onde pode controlar exatamente onde a truncatura ocorre. Se deixar isso ao acaso, a biblioteca e o visualizador podem divergir quanto ao ponto de corte, originando um ficheiro que se abre no seu ambiente mas recusa a mesma palavra-passe noutros sistemas.

Revisão 5 ou revisão 6: um boolean, dois ecossistemas

A propriedade UseAES256R6 seleciona o processo de validação AES-256, e esta escolha é mais complexa do que o seu tipo boolean sugere. Se a mantiver a False, o HotPDF aplica a revisão 5, o esquema AES-256 introduzido como extensão do PDF 1.7 e suportado por visualizadores com mais de quinze anos. Se a definir a True, obterá a revisão 6, a derivação de chave reforçada e normalizada na ISO 32000-2 para PDF 2.0, que corrige uma vulnerabilidade conhecida na validação de palavra-passe da revisão 5.

Desta forma, a revisão 6 é a melhor opção em termos criptográficos. Contudo, é também a que pode causar incompatibilidades. Um ficheiro com revisão 6 requer um visualizador compatível com PDF 1.7 Extension Level 3 ou PDF 2.0, e muito software em utilização não preenche estes requisitos: arquivos de gestão documental, renderizadores integrados noutros produtos e ferramentas antigas de fluxos de trabalho. Estes sistemas rejeitarão o ficheiro no computador do cliente, mesmo que no seu ambiente de desenvolvimento funcione. O padrão prático recomendado é, por isso, a revisão 5. Utilize a revisão 6 apenas quando uma política de segurança especificar expressamente a ISO 32000-2 por revisão, e após confirmar que todos os destinatários a conseguem ler. Em qualquer caso, documente a sua escolha no código para referência futura.

Os tipos de chave mais antigos merecem uma breve menção apenas para que saiba que os deve evitar. A enumeração THPDFKeyType ainda inclui k40, k128 e aes128, mas estes servem apenas para compatibilidade com arquivos históricos, e não para proteger documentos novos. O algoritmo RC4 de 40 bits é facilmente quebrado por hardware comum, e os esquemas de 128 bits são obsoletos face aos padrões AES-256 exigidos em qualquer auditoria de segurança atual. Para novos documentos, a única decisão relevante é entre a revisão 5 e a revisão 6; se ponderar utilizar os tipos antigos num novo projeto, algum requisito do fluxo de trabalho está incorreto.

Flags de permissão sem palavra-passe de abertura

Frequentemente, o requisito é o oposto do sigilo. Qualquer pessoa deve poder ler o documento, mas a impressão ou a extração de conteúdo devem ser limitadas. Isto configura-se definindo a palavra-passe do utilizador como vazia e especificando uma palavra-passe do proprietário, o que o PDF designa por modo de palavra-passe aberta (open-password mode), listando depois as ações permitidas em ProtectOptions.

Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.UserPassword := '';                      // anyone can open the file
Pdf.OwnerPassword := 'rotate-me-quarterly';  // guards the permission set
Pdf.ProtectOptions := [prPrint, prPrint12bit, prExtractContent];
Pdf.BeginDoc;
// ... page content ...
Pdf.EndDoc;

O conjunto THPDFProtectOptions mapeia diretamente os bits de permissão da norma ISO: prPrint e prPrint12bit para impressão em alta resolução, prInformationCopy para cópia e extração geral, prExtractContent para extração por tecnologias de apoio (como leitores de ecrã), além de prModifyStructure, prEditAnnotations, prFillAnnotations e prAssemble. Duas destas opções merecem especial atenção. Mantenha a prExtractContent ativa em quase todos os perfis. É o bit de que um leitor de ecrã necessita para aceder ao texto; desativá-lo converte uma opção de direitos numa barreira de acessibilidade que afetará utilizadores com deficiência sem que se aperceba. A outra rasteira é a flag prPrint isolada, sem a prPrint12bit: vários visualizadores reagem reduzindo a qualidade de impressão, o que os utilizadores reportarão como um erro de renderização e não como a definição de permissão que efetivamente é.

A verificação demora apenas alguns minutos e deve constar da sua lista de verificação de lançamentos. Abra uma amostra de cada perfil no Acrobat, aceda às Propriedades do Documento e consulte o painel de Segurança, que discrimina o algoritmo ("AES de 256 bits") e lista as operações permitidas. Depois, abra o mesmo ficheiro no visualizador mais antigo que os seus clientes utilizem. Este segundo teste é uma salvaguarda simples para evitar que um ficheiro de revisão 6 passe nos testes de desenvolvimento e falhe no cliente que não atualizou o sistema.

Remover a proteção de ficheiros existentes

O processo de desencriptação utiliza o mesmo modelo de propriedades de forma inversa. Carregue o documento com uma credencial válida, desative a proteção e grave o resultado sem encriptação.

var
  Pdf: THotPDF;
  PageCount: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    PageCount := Pdf.LoadFromFile('encrypted.pdf', 'open-secret');
    if PageCount > 0 then
    begin
      Pdf.ActivateProtection := False;   // drop encryption on save
      Pdf.SaveLoadedDocument('plain.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Este método carrega todo o documento em memória, o que é adequado para ficheiros comuns mas ineficiente para ficheiros de grande dimensão. Quando o ficheiro atinge centenas de megabytes, a função DecryptFile é a melhor alternativa: realiza a desencriptação durante uma cópia a nível de ficheiro, utilizando um caminho de reescrita direta AES-256 que evita a criação da árvore completa de objetos. Esta função faz parte da API Direct File, detalhada no artigo de acompanhamento sobre processamento de PDFs de grande dimensão no Delphi.

Restrições relacionadas com a encriptação

Existem duas restrições importantes que deve conhecer antes de projetar sistemas com encriptação. A primeira prende-se com a conformidade de arquivo. A norma ISO 19005 proíbe expressamente a encriptação em conformidades PDF/A, pelo que qualquer fluxo que encripte um documento e declare simultaneamente a conformidade PDF/A é inconsistente; o HotPDF impede a ativação de ambas as opções no mesmo ficheiro. Se necessitar de ambas, a solução passa por gerar dois ficheiros: uma versão encriptada para distribuição e outra sem encriptação para arquivo.

O segundo limite é incontornável. A encriptação de PDF não disponibiliza mecanismos de recuperação de credenciais. Se perder a palavra-passe do utilizador num ficheiro R5 ou R6, as únicas alternativas são a força bruta ou desistir do acesso. Por isso, gira as palavras-passe do proprietário e do utilizador como geriria qualquer credencial de produção: crie-as dinamicamente, guarde-as num cofre digital e proceda à sua rotação periódica. A prática a evitar terminantemente é a inclusão destas chaves como constantes no código, sob pena de serem registadas no sistema de controlo de versões e ficarem expostas na área de trabalho de todos os programadores.

Uma última boa prática para o seu dia a dia: alterar a proteção de um ficheiro que não foi criado por si utiliza o mesmo mecanismo da desencriptação, e não uma funcionalidade distinta. Carregue-o com a palavra-passe respetiva através de LoadFromFile, edite as ProtectOptions ou as palavras-passe e grave-o novamente com SaveLoadedDocument. Se possui autorização para desencriptar um ficheiro, também a possui para alterar as suas permissões, sendo a estrutura do código idêntica à apresentada anteriormente.

As propriedades de proteção aqui demonstradas fazem parte do Componente HotPDF padrão para Delphi e C++Builder; a página do produto inclui a referência de encriptação completa, com a enumeração detalhada de todas as permissões.