💡 Exemplo completo disponível no GitHub:
compare-encrypted-pdf-and-word-documents-dotnet
O Antigo Método Era Doloroso
Duas revisões de um contrato de fornecimento chegam à sua caixa de entrada. Ambas estão protegidas por senha, cada uma com uma senha diferente, e alguém precisa de uma cópia anotada mostrando o que mudou. A biblioteca de comparação que você tem espera entrada em texto simples, então o pipeline ganha um passo: descriptografar ambos os arquivos para uma pasta temporária, comparar as cópias em texto simples e, então, lembrar de excluí‑las. Essa pasta temporária agora é o elo mais fraco em um fluxo de trabalho que existe especificamente porque os documentos são sensíveis.
Existe uma segunda versão do mesmo problema que é mais fácil de perder. Algumas equipes pulam a pasta temporária e descriptografam na memória, o que resolve a questão da limpeza, mas não a questão do formato: a API de descriptografia difere por formato, de modo que dar suporte a planilhas criptografadas após PDFs criptografados significa uma segunda integração em vez de uma segunda linha de código.
O custo não está principalmente na chamada de descriptografia – está em tudo ao redor dela. Cópias em texto simples precisam ser gravadas em algum lugar, limpas em cada caminho de saída, inclusive nos de falha, e mantidas fora de backups e dumps de falha. Um diff produzido dessa forma também chega desprotegido por padrão, de modo que a saída de duas entradas criptografadas se torna o único arquivo na cadeia que qualquer pessoa pode abrir.
O custo real do desvio de descriptografia: um diretório temporário contendo cópias em texto simples de documentos que foram criptografados por um motivo, com limpeza que precisa ser correta em cada caminho de erro.
Existe um Caminho Melhor
A comparação protegida por senha é um recurso do GroupDocs.Comparison para .NET que abre arquivos PDF, DOCX, XLSX e PPTX criptografados no local e decide qual senha protege o resultado da comparação. Sem etapa de descriptografia, sem intermediários em texto simples: a senha viaja com o documento para a própria comparação, como uma propriedade em LoadOptions.
Antes de começar, você precisará de:
- .NET 8.0 SDK ou posterior
- GroupDocs.Comparison 26.9.0 (licença temporária)
- Dois documentos criptografados do mesmo formato e suas senhas
Instale com um único comando:
dotnet add package GroupDocs.Comparison
O Novo Caminho: Documentos Criptografados Direto no Comparador
O exemplo abaixo compara dois PDFs criptografados – a origem abre com 1234, o destino com 4321 – e grava um único arquivo de resultado com as alterações mescladas inline. Senhas deliberadamente diferentes, porque é aí que o primeiro erro se esconde.
Etapa 1 – Dê a cada documento seu próprio LoadOptions
Um Comparer contém uma origem e qualquer número de destinos, e cada documento carrega sua própria proteção. A senha da origem vai para o construtor; a senha de cada destino vai para sua própria chamada Add.
// Um LoadOptions por documento – as opções do construtor desbloqueiam
// apenas a origem e nunca chegam aos destinos.
using var comparer = new Comparer("source.pdf",
new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });
Esse é o detalhe que pega as pessoas desprevenidas. Passar um único LoadOptions para o construtor e esperar que ele cubra os destinos é a forma mais comum de erro, e, devido ao momento em que a falha ocorre, ele não se anuncia onde você procuraria.
Etapa 2 – Decida o que protege o resultado
CompareOptions.PasswordSaveOption escolhe a proteção da saída: None, Source, Target ou User. O padrão é None, que silenciosamente transforma duas entradas criptografadas em um resultado desprotegido.
// Marcação inline, e o resultado reutiliza a senha do documento de origem.
var options = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.Source
};
comparer.Compare("Result/1-pdf-inline.pdf", options);
Pontos chave:
- PasswordSaveOption:
Sourcereutiliza a senha da origem na saída. EscolhaUsercomSaveOptions.Passwordpara definir uma nova senha. - ComparisonDisplayMode: aninhado dentro de
PdfCompareOptions, que também ofereceSideBySideeInterleaved.WordCompareOptionsdeclara seu próprio enum com o mesmo nome e valores diferentes, portanto o nome simples não compilará – qualifique‑o.
Etapa 3 – Proteja a saída com uma senha própria
Quando o diff vai para revisores que não devem possuir nenhuma das senhas originais, PasswordSaveOption.User usa o valor de SaveOptions.Password em vez de reutilizar a senha de entrada.
var compareOptions = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.User
};
var saveOptions = new SaveOptions { Password = "5678" };
comparer.Compare("Result/4-own-password.pdf", saveOptions, compareOptions);
Ambos os objetos vão para a sobrecarga de Compare com três argumentos. Definir SaveOptions.Password isoladamente não altera nada – o valor do enum é que ativa a senha do lado de salvamento. O resultado desta chamada abre com 5678 e rejeita 1234.
Por que meu try/catch ao redor do Comparer não captura uma senha errada?
Porque o construtor nunca abre o documento. Ele registra o caminho, e o mesmo acontece com Add. Ambos os documentos são lidos quando Compare é executado, e é aí que PasswordProtectedFileException com a mensagem Password is missing é lançada. Uma senha errada se comporta de forma idêntica: é aceita silenciosamente no momento da construção e, depois, rejeitada em Compare.
Portanto, proteja a chamada de comparação, não o construtor. Descobri isso da maneira lenta, envolvendo a construção em um try e observando um arquivo criptografado passar direto antes de falhar três linhas depois. O repositório imprime cada estágio, o que torna a ordem óbvia na primeira leitura:
using var comparer = new Comparer("source.pdf"); // tem sucesso
comparer.Add("target.pdf"); // tem sucesso
comparer.Compare("Result/unreachable.pdf"); // lança aqui
Lado a Lado: Antes vs. Depois
| Antes (descriptografar primeiro) | Depois (GroupDocs.Comparison) | |
|---|---|---|
| Etapas do pipeline | Descriptografar ambos, comparar, excluir cópias temporárias | Comparar |
| Texto simples no disco | Duas cópias, limpeza em cada caminho de erro | Nenhuma |
| Proteção do resultado | Etapa separada de re‑criptografia | Um valor PasswordSaveOption |
| Cobertura de formatos | Ferramentas de descriptografia por formato | Um LoadOptions.Password para PDF, DOCX, XLSX, PPTX |
| Código necessário | Helper de descriptografia + comparação | 4 linhas |
Os recursos de comparação não mudam com entrada criptografada. Modos de exibição, páginas de resumo e detecção de estilo comportam‑se exatamente como fazem para arquivos em texto simples, porque a proteção é tratada integralmente na camada de carregamento.
Essa camada é o que torna a cobertura de formatos barata. LoadOptions.Password é uma propriedade string simples, e a mesma propriedade desbloqueia PDF, DOCX, XLSX e PPTX – o código de carregamento no exemplo de Word mais abaixo é literalmente o mesmo que o dos exemplos de PDF. Apenas a classe de opções muda, e só porque cada formato expõe escolhas de renderização diferentes. Adicionar suporte a planilhas criptografadas a um código que já compara PDFs criptografados não custa nada no caminho de carregamento.
Exemplo Real: Redação de Contrato Entre Escritórios de Advocacia
Uma equipe jurídica recebe cada revisão de um contrato criptografada, com a senha rotacionada a cada troca para que uma senha vazada não exponha todo o histórico. O sócio revisor precisa de um documento anotado por rodada, e, segundo as regras de retenção, a cópia anotada não pode ficar desprotegida em um compartilhamento de arquivos.
Dois ajustes cobrem isso. Cada documento é desbloqueado por seu próprio LoadOptions, de modo que a rotação de senhas não requer tratamento especial, e PasswordSaveOption.User dá a cada diff distribuído uma senha própria – uma que desbloqueia a comparação e nada mais.
// Revisões de Word, para que o sócio revisor possa aceitar ou rejeitar cada edição.
var options = new WordCompareOptions
{
DisplayMode = WordCompareOptions.ComparisonDisplayMode.Revisions,
PasswordSaveOption = PasswordSaveOption.Source
};
using var comparer = new Comparer("round3.docx",
new LoadOptions { Password = "1234" });
comparer.Add("round4.docx", new LoadOptions { Password = "4321" });
comparer.Compare("Result/redline.docx", options);
O Que Mais Você Pode Fazer com GroupDocs.Comparison?
- Comparar mais de dois documentos protegidos: adicione vários alvos criptografados a uma única comparação, para formatos Word e de apresentação.
- Gerar revisões nativas do Word:
WordCompareOptions.ComparisonDisplayMode.Revisionsgrava alterações que o revisor aceita ou rejeita diretamente no Word. - Controlar o carregamento de recursos externos: bloqueie ou permita listas brancas de referências remotas que um documento contém, outra salvaguarda via
LoadOptions. - Gerar uma página de resumo:
GenerateSummaryPageadiciona uma visão geral das mudanças ao documento de resultado.
Conclusão
O desvio de descriptografia nunca foi sobre a comparação – era sobre uma biblioteca que não conseguia ler o que você tinha. Definir LoadOptions.Password por documento elimina a pasta temporária, os caminhos de limpeza e o diff desprotegido ao final da cadeia. Restam apenas três decisões: uma senha por documento, um PasswordSaveOption explícito em vez do padrão None, e tratamento de erro ao redor de Compare, onde a falha realmente ocorre.
Pronto para automatizar seu fluxo de trabalho de documentos?
- Experimente o teste gratuito da API
- Explore carregamento de documentos protegidos por senha
- Leia o guia completo de comparação de documentos protegidos
- Confira o projeto de exemplo no GitHub