Article technique

Chiffrement PDF 2.0 AES-GCM en Delphi : ISO/TS 32003

PDFiumPas écrit le chiffrement ISO/TS 32003 via SaveAsEncrypted : réglez Revision sur erR7 et chaque chaîne et chaque flux est protégé avec AES-256 en mode GCM, le chiffrement authentifié que PDF 2.0 a gagné en 2023. Réglez également EnableIntegrityProtection et le document porte aussi un jeton PDF MAC autonome, que ValidatePdfMac vérifie côté lecture

Ce sont deux protections différentes que l'on confond régulièrement. GCM authentifie chaque valeur chiffrée. Le MAC authentifie le document dans son ensemble. Vous voulez les deux, pour des raisons différentes

Qu'apporte GCM que CBC n'a jamais fourni ?

L'authentification du texte chiffré. AES-256 en mode CBC, le schéma AESV3 de ISO 32000-2, garde le contenu confidentiel et ne dit rien sur le fait qu'il soit arrivé sans modification. CBC est malléable de façons spécifiques et bien étudiées : un attaquant capable d'inverser des bits dans le texte chiffré produit des changements prévisibles dans le texte clair du bloc suivant, et rien dans le format ne le remarque

GCM comble cette lacune. Chaque valeur chiffrée porte une balise d'authentification de 16 octets, sérialisée intégralement comme l'exige ISO/TS 32003, et le déchiffrement échoue plutôt que de renvoyer un texte clair altéré quand la balise ne correspond pas. En termes PDF, une chaîne ou un flux altéré dans un document AESV4 est une erreur dure au point d'utilisation, pas une valeur étrange qui se propage dans votre application. Le dictionnaire Encrypt marque cela avec /CFM /AESV4 et V 6 / R 7, aux côtés d'une entrée d'extension déclarant /ExtensionLevel 32003 et /ExtensionRevision (:2023)

Trois révisions, trois écosystèmes

TPdfEncryptionRevision propose erR5, erR6 et erR7, et le choix relève davantage d'une décision de compatibilité que d'une décision cryptographique. R5 est le schéma AES-256 d'origine publié comme extension de PDF 1.7, avec un simple hachage de mot de passe SHA-256, et il s'ouvre pratiquement dans tout ce qui existe depuis quinze ans. R6 est la dérivation de clé renforcée normalisée dans ISO 32000-2, utilisant la construction itérative SHA-256/384/512 de l'algorithme 2.B, et c'est ce qu'attend un flux de travail PDF 2.0 ou PDF/A-4 actuel. R7 est ISO/TS 32003, utilisant la même dérivation 2.B avec AES-GCM comme chiffrement

La prise en charge par les lecteurs suit exactement cet ordre, et la prise en charge de R7 reste mince en dehors des visionneuses grand public actuelles. C'est le même arbitrage qui gouverne toute fonctionnalité de PDF 2.0 : l'option la plus récente est la meilleure ingénierie et le public le plus restreint. Décidez selon qui doit ouvrir le fichier, et si la réponse est « un système d'archives que personne n'a mis à jour depuis 2019 », la réponse est R5 quelle que soit la préférence de la politique de sécurité

uses
  PDFium, FPdfEncrypt;

var
  Pdf: TPdf;
  Opts: TPdfEncryptOptions;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'quarterly-report.pdf';
    Pdf.LoadDocument;

    Opts := TPdfEncryptOptions.Default;
    Opts.UserPassword := 'open-secret';
    Opts.OwnerPassword := 'admin-secret';
    Opts.EncryptMetadata := True;
    Opts.Revision := erR7;                    // ISO/TS 32003 AESV4-GCM
    Opts.EnableIntegrityProtection := True;   // jeton PDF MAC autonome

    if not Pdf.SaveAsEncrypted('quarterly-report.enc.pdf', Opts) then
      raise Exception.Create('Encrypted save failed');
  finally
    Pdf.Free;
  end;
end;

Pourquoi un MAC de document en plus d'un chiffrement authentifié ?

Parce que les balises GCM protègent les valeurs, pas l'agencement des valeurs. Chaque chaîne et chaque flux dans un document AESV4 est authentifié individuellement, pourtant la table de références croisées, la numérotation des objets et le trailer sont de la structure, pas du contenu chiffré. Un attaquant ne peut pas forger un flux, mais rien dans le chiffrement seul ne l'empêche de réarranger vers quels objets pointe le document, ou d'épisser des objets provenant d'une révision antérieure du même fichier

Le jeton PDF MAC autonome traite cette couche. PDFiumPas le dérive de la clé de chiffrement du fichier avec un /KDFSalt dédié de 32 octets enregistré dans le dictionnaire Encrypt, si bien que c'est la possession du mot de passe qui permet à un lecteur de confirmer le jeton. Le résultat est une réponse unique à une question unique : ce document, dans son ensemble, est-il le document qui a été écrit

var
  Pdf: TPdf;
  Mac: TPdfMacValidationResult;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.Password := 'open-secret';
    Pdf.FileName := 'quarterly-report.enc.pdf';
    Pdf.LoadDocument;

    Mac := Pdf.ValidatePdfMac('open-secret');
    case Mac.Status of
      pmvsValid:       ProcessDocument(Pdf);
      pmvsNotPresent:  ProcessWithWarning(Pdf);       // aucun jeton dans ce fichier
      pmvsInvalid:     Quarantine(Mac.MessageText);   // altéré ou tronqué
      pmvsUnsupported: RouteForManualReview(Mac.MessageText);
    end;
  finally
    Pdf.Free;
  end;
end;

Les quatre valeurs de statut appellent quatre réponses différentes, et les réduire à un booléen fait perdre la distinction qui compte. pmvsNotPresent signifie que le fichier n'a simplement aucun jeton, ce qui décrit presque tous les PDF chiffrés écrits avant 2024 et ne constitue la preuve de rien. pmvsInvalid signifie qu'un jeton est présent et ne se vérifie pas, ce qui est une véritable découverte et devrait arrêter le traitement. pmvsUnsupported signifie que le jeton existe sous une forme que cette version n'implémente pas, ce qui est un manque de compatibilité, pas une attaque. Traiter « absent » comme « invalide » mettrait en quarantaine tout votre catalogue existant dès le premier jour

Ce que le chiffrement ne fait toujours pas

Les indicateurs de permission restent ce qu'ils ont toujours été : une requête adressée à un logiciel conforme, pas un contrôle. Les bits /P du tableau 22 d'ISO 32000-1 qui interdisent l'impression ou l'extraction sont honorés par les visionneuses bien élevées et ignorés par tout le reste, et quiconque détient le mot de passe utilisateur détient déjà le contenu déchiffré. Le chiffrement est la frontière ; les permissions décrivent l'intention à l'intérieur de cette frontière

Deux détails opérationnels méritent d'être anticipés. Premièrement, le chiffrement et une modification ultérieure interagissent : ajouter une mise à jour incrémentielle à un document chiffré a ses propres règles, couvertes dans les mises à jour incrémentielles sur les PDF chiffrés, et un jeton MAC est une affirmation au niveau du document qu'un ajout négligent invalidera. Deuxièmement, la construction GCM utilise un compteur d'IV déterministe, et PDFiumPas lève une exception plutôt que de réutiliser une valeur de compteur si cet espace venait à s'épuiser, car la réutilisation d'un nonce en GCM est catastrophique d'une façon qu'un bouclage silencieux dissimulerait

Choisir entre les trois révisions en pratique

Notez qui ouvre le fichier, puis choisissez. Pour une diffusion interne où chaque lecteur est une visionneuse actuelle sous votre contrôle, R7 avec protection d'intégrité est l'option la plus solide disponible et rien ne justifie de ne pas l'utiliser. Pour les documents qui quittent l'organisation, R6 est la valeur par défaut défendable : elle est normalisée dans ISO 32000-2 plutôt que dans une spécification technique qui s'y superpose, et la prise en charge est large. Pour les archives et les consommateurs hérités, R5 est le seul choix qui s'ouvre de façon fiable, et vous devriez en noter la raison au même endroit où vous notez le reste de votre politique de conservation

Quel que soit votre choix, vérifiez la sortie plutôt que de faire confiance au succès de l'appel. Rouvrez le fichier chiffré, vérifiez ValidatePdfMac, et confirmez que la version déclarée est celle que vous attendez, en utilisant les contrôles de conformité de version dans la conformité de version PDF exacte. Une liste de contrôle d'entrée plus large pour les documents non fiables se trouve dans l'audit des risques de sécurité PDF

PDFiumPas est un composant Delphi et Lazarus autour du moteur PDFium avec la pile de chiffrement PDF 2.0 implémentée nativement en Pascal, si bien qu'AES-256, GCM et le jeton MAC ne nécessitent aucune DLL crypto externe. L'API de chiffrement est documentée sur la page PDFium Delphi component