O Excel expõe duas coisas designadas por 'palavra-passe', mas apenas uma delas constitui encriptação real. A palavra-passe de abertura aciona uma cifra real: sem ela, o ficheiro não pode de todo ser lido. As palavras-passe de proteção de folhas de cálculo e de livros de trabalho não fazem nada disso. Apenas definem um sinalizador que um editor cooperante concorda em respeitar, e um livro de trabalho que contenha apenas esse sinalizador é um simples ficheiro zip legível com os dados em texto simples. Escolha a errada e enviará uma folha de pagamentos que parece bloqueada no Excel, mas que pode ser lida em qualquer editor de texto.
A prova demora dez segundos. Renomeie um ficheiro .xlsx protegido para .zip, abra-o em qualquer ferramenta de arquivo e verifique o ficheiro xl/worksheets/sheet1.xml. Se os valores das células estiverem lá em UTF-8 simples, o ficheiro não está encriptado, independentemente do número de avisos de palavra-passe que o Excel apresente quando alguém tenta editar uma célula. Essa lacuna sobrevive anos em equipas que assumem que a proteção de folhas é sinónimo de confidencialidade, e normalmente vem à tona no dia em que uma auditoria de segurança realiza exatamente esta renomeação.
O HotXLS é uma biblioteca nativa de folhas de cálculo para Delphi e C++Builder, e mantém estas duas funcionalidades em lados opostos dessa linha. A proteção de folhas de cálculo e de livros de trabalho consiste em restrições de edição suportadas por um hash legado intencionalmente fraco. O método SaveAsEncrypted produz um pacote encriptado com AES que nada além da palavra-passe conseguirá abrir. As secções abaixo cobrem o que essa chamada escreve, a assimetria que deve prever no seu desenho (o HotXLS escreve ficheiros encriptados mas não os consegue ler de volta) e como o caminho XLS mais antigo difere.
Porque é que a proteção de folhas não é encriptação
Os métodos Protect nas folhas e ProtectWorkbook no livro de trabalho guardam um hash de 4 dígitos hexadecimais da palavra-passe. Esse é o algoritmo legado que o OOXML e o BIFF herdaram do Excel dos anos 90, e a documentação do formato nunca afirma que faça mais do que impedir edições acidentais. O pacote permanece um ficheiro zip legível comum: dados de células, fórmulas e cadeias de caracteres partilhadas em XML em texto limpo. O comportamento padrão agrava a situação. Cada célula começa com Locked=True, pelo que chamar Protect sem primeiro desbloquear um intervalo de entrada bloqueia a folha inteira contra edições, deixando todos os valores visíveis.
Nada disto torna a proteção inútil. Orientar os utilizadores para intervalos editáveis e estabilizar um layout para impressão são tarefas reais, abordadas no nosso artigo sobre proteção de folhas de cálculo e configuração de página. Mas essas são tarefas de usabilidade. A partir do momento em que o requisito passa a ser a confidencialidade, a única API que responde a isso é o método SaveAsEncrypted.
O que o SaveAsEncrypted realmente escreve
A implementação segue a Encriptação Padrão (Standard Encryption) ECMA-376, especificada na secção 2.3.4 da norma [MS-OFFCRYPTO]. A palavra-passe passa por 50 000 iterações de SHA-1 para derivar uma chave AES-128. Um bloco verificador, encriptado com AES-128 no modo ECB, permite que o leitor confirme a palavra-passe antes de desencriptar qualquer conteúdo, e o pacote completo do livro de trabalho é então encriptado com AES-128 no modo CBC. O que vai parar ao disco não é de todo um ficheiro zip. Trata-se de um ficheiro composto OLE que contém os fluxos EncryptionInfo, EncryptedPackage e DataSpaces, sem qualquer diretório xl/ para uma ferramenta de arquivo listar, motivo pelo qual o teste de renomeação não revela nada legível. O Excel 2007 e posterior abre-o apenas com a palavra-passe, e a versão atual do LibreOffice também lê esta Encriptação Padrão.
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
rc: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Payroll');
Sheet.Cells[1, 1].Value := 'Employee';
Sheet.Cells[1, 2].Value := 'Net pay';
Sheet.Cells[2, 1].Value := 'A. Garcia';
Sheet.Cells[2, 2].Value := 4815.16;
rc := Book.SaveAsEncrypted('payroll-2026-06.xlsx', PasswordFromVault);
if rc <> 1 then
raise Exception.CreateFmt('Encrypted save failed (rc=%d)', [rc]);
finally
Book.Free;
end;
end;
Trate a variável da palavra-passe com o mesmo cuidado que dedicaria a uma cadeia de ligação (connection string). Obtenha-a de um cofre (vault) ou de um serviço de segredos gerados no último momento, nunca a registe em diários de log e nunca a escreva no próprio livro de trabalho. A verificação do código de retorno não é formalidade opcional. Uma gravação encriptada que falhe a meio deve abortar a entrega, porque a única alternativa que o código de chamada pode oferecer é uma cópia não encriptada, e essa cópia representa exatamente o incidente que esta funcionalidade visa evitar.
Existe também um teste de aceitação automatizado que não custa quase nada: chame CanReadEncrypted no ficheiro que acabou de escrever. Devolve true apenas quando a saída é realmente um contentor de encriptação, pelo que validá-lo após cada gravação encriptada deteta a regressão mais crítica, um caminho de código que recorreu silenciosamente a um SaveAs comum, no momento em que ocorre, em vez de semanas mais tarde na caixa de correio eletrónico de um cliente. A última palavra continua a pertencer a uma abertura manual no Excel com a palavra-passe real durante os testes de lançamento.
Apenas para escrita por conceção: gerir EXlsxEncryptionNotImplemented
Eis a assimetria que deve moldar a arquitetura do seu fluxo de dados: o HotXLS encripta ao gravar, mas não desencripta ao abrir. O método OpenEncrypted gera a exceção EXlsxEncryptionNotImplemented quando apontado para um pacote encriptado real; num livro de trabalho comum, limita-se a passar para um Open normal. A sonda companheira CanReadEncrypted deteta o contentor de encriptação OLE de forma económica, para que o código de receção possa encaminhar esses ficheiros sem desencadear a exceção:
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.CanReadEncrypted(FileName) then
begin
// Encrypted container: HotXLS cannot decrypt it.
Writeln(FileName + ': needs manual decryption in Excel first');
Exit;
end;
try
Book.OpenEncrypted(FileName, ''); // plain files fall through to Open
Writeln(FileName + ': opened, ' + IntToStr(Book.Sheets.Count) + ' sheet(s)');
except
on EXlsxEncryptionNotImplemented do
Writeln(FileName + ': encrypted - routed to manual queue');
end;
finally
Book.Free;
end;
end;
Essa assimetria tem uma interpretação arquitetural clara: encriptar no limite de entrega, no final. Mantenha o original em texto limpo dentro do seu limite de confiança, numa base de dados, num repositório de documentos ou numa partilha com controlo de acesso, e produza a cópia encriptada como o passo final antes de o ficheiro sair do sistema. Um fluxo que arquive apenas a saída encriptada bloqueará o acesso aos seus próprios dados, pois nenhuma fase posterior do mesmo sistema poderá reabrir esses ficheiros. Quando um processo HotXLS a jusante necessitar novamente do livro de trabalho, forneça-lhe o original em texto limpo, nunca o artefacto de entrega.
Encriptação Padrão AES-128 e a conformidade com AES-256
A encriptação de ficheiros do Office apresenta-se em duas gerações. A Encriptação Padrão (Standard Encryption), escrita pelo HotXLS, utiliza AES-128 com derivação de chave SHA-1. A Encriptação Ágil (Agile Encryption) surgiu mais tarde e evoluiu para AES-256 com SHA-512 e um contentor de chave diferente descrito em XML. Ambas abrem de forma transparente no Excel, e o AES-128 continua a ser computacionalmente seguro para proteger um ficheiro em trânsito para um cliente.
A diferença deixa de ser académica no dia em que um questionário de segurança exige 'encriptação AES-256 de ficheiros em repouso'. A Encriptação Padrão não cumpre essa exigência, independentemente da força da palavra-passe, e nenhum parâmetro do SaveAsEncrypted altera o algoritmo gerado. Por isso, declare o perfil com precisão na sua documentação de segurança: AES-128, Encriptação Padrão ECMA-376, derivação de chave SHA-1 com 50 000 iterações. Uma declaração que resista a uma revisão vale mais do que uma otimista que desabe numa auditoria.
O caminho XLS legado: RC4 para saída, RC4 e XOR para entrada
A fachada BIFF tem a forma oposta. A sua encriptação é mais antiga e fraca, mas o ciclo completo funciona: o que escreve, também consegue ler de volta. Definir EncryptionPassword antes de SaveAs produz um .xls encriptado com RC4 através do mecanismo FilePass do BIFF, e a abertura Open com o parâmetro da palavra-passe lê os três esquemas legados: RC4, RC4 CryptoAPI e a antiga ofuscação XOR:
var
Writer, Reader: IXLSWorkbook; // interface refs: no manual Free
begin
Writer := TXLSWorkbook.Create;
Writer.Sheets.Add.Cells.Item[1, 1].Value := 'Confidential';
Writer.EncryptionPassword := 'S3cret!';
Writer.SaveAs('confidential.xls');
Reader := TXLSWorkbook.Create;
if Reader.Open('confidential.xls', 'S3cret!') > 0 then
Writeln(Reader.Sheets[1].Cells.Item[1, 1].Value); // Entries are 1-based
end;
O RC4 é uma criptografia obsoleta e nunca deve proteger dados importantes atualmente; o seu único valor residual reside na interoperabilidade com sistemas que ainda trocam ficheiros .xls. O lado da leitura, contudo, revela-se útil em trabalhos de migração. Um ficheiro antigo protegido por palavra-passe abre com Open(FileName, Password), faz a ponte para o modelo OOXML e é protegido novamente através do caminho AES, uma atualização unidirecional executada sem necessidade do Excel em qualquer parte do fluxo. Para entregas encriptadas de grande volume, as notas de desempenho de gravação no nosso artigo sobre escritas em fluxo para tarefas em lote no servidor aplicam-se à fase de construção do conteúdo que ocorre antes da encriptação.
Encriptação e proteção não são rivais
Mais um ponto a esclarecer, pois surge assim que alguém lê o aviso no topo desta página como 'a proteção é inútil'. Não é. A encriptação e a proteção recomendam respostas a questões diferentes e combinam-se perfeitamente. A encriptação decide quem pode abrir o ficheiro; a proteção decide o que um leitor que já acedeu pode alterar. Uma entrega de folha de pagamentos pode perfeitamente fazer ambas: encriptar o pacote para que apenas o portador da palavra-passe o veja, e depois bloquear as células de fórmulas para que o destinatário possa filtrar e ordenar, mas não reescrever as fórmulas de cálculo silenciosamente. O erro nunca é adicionar proteção. O erro é deixar que a sua presença substitua a encriptação quando o requisito era a confidencialidade.
A custódia das palavras-passe não tem rede de segurança, e isso é intencional. A derivação de chave com 50 000 iterações existe para tornar a adivinhação dispendiosa, e nada dentro do ficheiro salvaguarda o segredo. Uma palavra-passe perdida é sinónimo de dados perdidos. Gere, entregue e armazene estas palavras-passe com a mesma disciplina que aplica às credenciais de bases de dados, e a encriptação cumprirá a sua parte.
A encriptação real de ficheiros resume-se a uma chamada no HotXLS. A disciplina reside em tudo o que envolve essa chamada: a custódia de palavras-passe, o limite de apenas escrita que impede o HotXLS de reabrir a sua própria saída e uma especificação do algoritmo que possa defender numa auditoria. O método SaveAsEncrypted e o ciclo legado completo são fornecidos com o Componente HotXLS, sendo executados nativamente em processos Delphi e C++Builder sem automação do Excel em qualquer ponto do caminho.