💡 Exemple complet fonctionnel disponible sur GitHub :
compare-encrypted-pdf-and-word-documents-dotnet

L’ancienne méthode était pénible

Deux révisions d’un accord de fourniture atterrissent dans votre boîte de réception. Les deux sont protégées par mot de passe, chacune avec un mot de passe différent, et quelqu’un a besoin d’une copie annotée montrant ce qui a changé. La bibliothèque de comparaison que vous utilisez attend une entrée en texte clair, donc le pipeline ajoute une étape : déchiffrer les deux fichiers dans un dossier temporaire, comparer les copies en texte clair, puis se souvenir de les supprimer. Ce dossier temporaire devient alors le maillon le plus faible d’un flux de travail qui existe spécifiquement parce que les documents sont sensibles.

Il existe une seconde version du même problème, plus facile à manquer. Certaines équipes sautent le dossier temporaire et déchiffrent en mémoire à la place, ce qui résout la question du nettoyage mais pas celle du format : l’API de déchiffrement diffère selon le format, donc prendre en charge les feuilles de calcul chiffrées après les PDF chiffrés signifie une seconde intégration plutôt qu’une seconde ligne de code.

Le coût ne réside pas principalement dans l’appel de déchiffrement – il se trouve dans tout ce qui l’entoure. Les copies en texte clair doivent être écrites quelque part, nettoyées à chaque chemin de sortie, y compris les chemins d’échec, et exclues des sauvegardes et des vidages de mémoire. Un diff produit de cette façon arrive également non protégé par défaut, de sorte que la sortie de deux entrées chiffrées devient le seul fichier de la chaîne que n’importe qui peut ouvrir.

Le vrai coût du détour de déchiffrement : un répertoire temporaire contenant des copies en texte clair de documents qui ont été chiffrés pour une raison, avec un nettoyage qui doit être correct sur chaque chemin d’erreur.

Il existe une meilleure façon

La comparaison protégée par mot de passe est une capacité de GroupDocs.Comparison pour .NET qui ouvre les fichiers PDF, DOCX, XLSX et PPTX chiffrés sur place et décide quel mot de passe protège le résultat de la comparaison. Aucun pas de déchiffrement, aucun intermédiaire en texte clair : le mot de passe voyage avec le document dans la comparaison elle‑même, comme propriété de LoadOptions.

Avant de commencer, vous aurez besoin de :

  • SDK .NET 8.0 ou ultérieur
  • GroupDocs.Comparison 26.9.0 (licence temporaire)
  • Deux documents chiffrés du même format, ainsi que leurs mots de passe

Installez avec une seule commande :

dotnet add package GroupDocs.Comparison

La nouvelle façon : documents chiffrés directement dans le comparateur

L’exemple ci‑dessous compare deux PDF chiffrés – la source s’ouvre avec 1234, la cible avec 4321 – et écrit un seul fichier de résultat avec les modifications fusionnées en ligne. Des mots de passe délibérément différents, car c’est là que se cache la première erreur.

Étape 1 – Attribuer à chaque document son propre LoadOptions

Un Comparer possède une source et un nombre quelconque de cibles, et chaque document porte sa propre protection. Le mot de passe de la source est passé au constructeur ; le mot de passe de chaque cible est passé à son appel Add propre.

// Un LoadOptions par document – les options du constructeur déverrouillent
// uniquement la source, et n'atteignent jamais les cibles.
using var comparer = new Comparer("source.pdf",
    new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });

C’est le détail qui piège les gens. Passer un seul LoadOptions au constructeur en s’attendant à ce qu’il couvre les cibles est la façon la plus courante dont cela échoue, et à cause du moment où l’échec se produit, il ne s’annonce pas là où vous le chercheriez.

Étape 2 – Décider ce qui protège le résultat

CompareOptions.PasswordSaveOption choisit la protection de la sortie : None, Source, Target ou User. La valeur par défaut est None, qui transforme silencieusement deux entrées chiffrées en un résultat non protégé.

// Marquage en ligne, et le résultat réutilise le mot de passe du document source.
var options = new PdfCompareOptions
{
    DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
    PasswordSaveOption = PasswordSaveOption.Source
};

comparer.Compare("Result/1-pdf-inline.pdf", options);

Points clés :

  • PasswordSaveOption : Source réutilise le mot de passe de la source sur la sortie. Choisissez User avec SaveOptions.Password pour en définir un nouveau.
  • ComparisonDisplayMode : imbriqué dans PdfCompareOptions, qui propose également SideBySide et Interleaved. WordCompareOptions déclare son propre enum du même nom avec des valeurs différentes, donc le nom seul ne compilera pas – qualifiez‑le.

Étape 3 – Protéger la sortie avec son propre mot de passe

Lorsque le diff est envoyé à des examinateurs qui ne doivent pas connaître les mots de passe d’origine, PasswordSaveOption.User prend la valeur de SaveOptions.Password au lieu de réutiliser un mot de passe d’entrée.

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);

Les deux objets sont transmis à la surcharge Compare à trois arguments. Définir SaveOptions.Password seul ne change rien – c’est la valeur de l’enum qui active le mot de passe côté sauvegarde. Le résultat de cet appel s’ouvre avec 5678 et rejette 1234.

Pourquoi mon try/catch autour du Comparer ne capture‑t‑il pas un mauvais mot de passe ?

Parce que le constructeur n’ouvre jamais le document. Il enregistre simplement le chemin, tout comme Add. Les deux documents sont lus lorsque Compare s’exécute, et c’est à ce moment‑là que PasswordProtectedFileException avec le message Password is missing est levée. Un mauvais mot de passe se comporte de la même façon : il est accepté silencieusement au moment de la construction, puis rejeté plus tard lors de Compare.

Il faut donc protéger l’appel de comparaison, pas le constructeur. Je l’ai découvert à la dure, en enveloppant la construction dans un try et en observant un fichier chiffré traverser sans problème avant d’échouer trois lignes plus tard. Le dépôt affiche chaque étape, ce qui rend l’ordre évident dès la première lecture :

using var comparer = new Comparer("source.pdf");   // réussit
comparer.Add("target.pdf");                        // réussit
comparer.Compare("Result/unreachable.pdf");        // lève une exception ici

Comparaison côte à côte : avant vs. après

Avant (décryptage d’abord) Après (GroupDocs.Comparison)
Étapes du pipeline Décrypter les deux, comparer, supprimer les copies temporaires Comparer
Texte clair sur disque Deux copies, nettoyage à chaque chemin d’erreur Aucun
Protection du résultat Une étape de re‑chiffrement séparée Une valeur PasswordSaveOption
Couverture des formats Outils de décryptage par format Un LoadOptions.Password pour PDF, DOCX, XLSX, PPTX
Code requis Helper de décryptage + comparaison 4 lignes

Les fonctionnalités de comparaison ne changent pas avec une entrée chiffrée. Les modes d’affichage, les pages de résumé et la détection de style se comportent exactement comme pour les fichiers en texte clair, car la protection est entièrement gérée au niveau du chargement.

Cette couche d’abstraction rend la couverture des formats économique. LoadOptions.Password est une simple propriété string, et la même propriété déverrouille PDF, DOCX, XLSX et PPTX – le code de chargement dans l’exemple Word plus bas est caractère pour caractère identique à celui des exemples PDF. Seule la classe d’options change, et uniquement parce que chaque format expose des choix de rendu différents. Ajouter la prise en charge des feuilles de calcul chiffrées à du code qui compare déjà des PDF chiffrés ne coûte rien dans le chemin de chargement.

Exemple réel : rédaction de contrats entre cabinets d’avocats

Une équipe juridique reçoit chaque révision d’un accord chiffrée, le mot de passe étant tourné à chaque échange afin qu’un mot de passe divulgué n’expose pas tout l’historique. Le partenaire en charge de la révision a besoin d’un document annoté par cycle, et selon les règles de conservation, la copie annotée ne doit pas rester non protégée sur un partage de fichiers.

Deux réglages couvrent ce besoin. Chaque document est déverrouillé par son propre LoadOptions, donc la rotation des mots de passe ne nécessite aucune manipulation spéciale, et PasswordSaveOption.User donne à chaque diff distribué son propre mot de passe – un qui déverrouille la comparaison et rien d’autre.

// Révisions Word, afin que le partenaire puisse accepter ou rejeter chaque modification.
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);

Que pouvez‑vous encore faire avec GroupDocs.Comparison ?

  • Comparer plus de deux documents protégés : ajoutez plusieurs cibles chiffrées à une même comparaison, pour les formats Word et présentation.
  • Produire des révisions Word natives : WordCompareOptions.ComparisonDisplayMode.Revisions écrit les modifications qu’un examinateur accepte ou rejette directement dans Word.
  • Contrôler le chargement de ressources externes : bloquez ou autorisez les références distantes qu’un document porte, grâce à une autre protection LoadOptions.
  • Générer une page de résumé : GenerateSummaryPage ajoute un aperçu des changements au document de résultat.

Conclusion

Le détour de décryptage n’a jamais concerné la comparaison – il concernait une bibliothèque qui ne pouvait pas lire ce que vous aviez. Définir LoadOptions.Password par document élimine le dossier temporaire, les chemins de nettoyage et le diff non protégé à la fin de la chaîne. Trois décisions restent : un mot de passe par document, un PasswordSaveOption explicite au lieu du défaut None, et la gestion des erreurs autour de Compare où l’échec se produit réellement.

Prêt à automatiser votre flux de travail documentaire ?

Ressources supplémentaires