Fachartikel

AES-256-PDF-Verschlüsselung in Delphi: HotPDF-Konfiguration und Fallstricke

Ein PDF-Berechtigungs-Flag ist kein Schloss. Es ist eine Bitte, die die Datei an das öffnende Programm stellt, und ein Betrachter kann sie ignorieren. Diese Tatsache bestimmt, wie alle anderen Entscheidungen auf dieser Seite bewertet werden sollten. Echte Vertraulichkeit kommt nur aus einer Quelle: AES-256-Verschlüsselung, geschützt durch ein Passwort, das der Leser nicht besitzt. Alles andere, die Kontrollkästchen „Kein Drucken" und „Kein Kopieren", ist eine Richtlinie, der konforme Software zustimmt und feindliche Software nicht. Wer diese beiden Ebenen verwechselt, liefert etwas aus, das in einer Demo sicher wirkt und im Einsatz leckt.

HotPDF ist eine native VCL-PDF-Komponente für Delphi und C++Builder, die das ISO 32000-Schutzmodell über eine kleine Menge von Eigenschaften zugänglich macht. Die Eigenschaften sind leicht zu setzen. Das Schwierige ist zu wissen, welche kryptografischen Schutz bietet und welche nur eine höfliche Empfehlung ausspricht, und die Zuweisungsreihenfolge so hinzubekommen, dass die gewünschte Verschlüsselung tatsächlich die erhaltene ist.

Was die zwei Passwörter wirklich versprechen

PDF-Verschlüsselung definiert zwei Zugangsdaten mit unterschiedlichen Aufgaben, und sie zu verwechseln ist der häufigste Entwurfsfehler bei Code für geschützte Ausgaben. Das Benutzerpasswort kontrolliert die Entschlüsselung. Ohne dieses oder das Inhaberpasswort kann ein konformer Betrachter den Dateischlüssel nicht rekonstruieren, und der Inhalt bleibt kryptografisch unlesbar. Das Inhaberpasswort kontrolliert stattdessen die Berechtigungseinstellungen: Ein Betrachter, der das Inhaberpasswort erhält, bekommt unabhängig von den Einschränkungs-Flags vollen Zugang.

Die Berechtigungs-Bits stehen auf schwächerem Boden. Drucken, Inhaltsextraktion, Formularausfüllen: jedes ist ein Flag, das ein Betrachter liest und zu respektieren wählt (ISO 32000-2 §7.6.4). Verschlüsselung schützt die Bytes. Die Berechtigungs-Flags weisen nur konforme Software an, und das erst nachträglich. Jeder, der das Dokument mit dem Benutzerpasswort öffnet, hält den entschlüsselten Inhalt bereits im Speicher, sodass „Kein Kopieren" und „Kein Drucken" für einen wohlverhaltenen Betrachter etwas bedeuten und für einen entschlossenen nichts. Das Bedrohungsmodell sollte auf dieser Grundlage aufgebaut werden. Vertraulichkeit liegt im Benutzerpasswort. Berechtigungen bestimmen, was Mainstream-Betrachter anbieten, und das ist der gesamte Umfang dessen, was sie tun.

Konfigurationsreihenfolge: alles vor BeginDoc

HotPDF erstellt das Verschlüsselungs-Dictionary und leitet den Dateischlüssel beim Aufruf von BeginDoc ab. Was die Schutzeigenschaften zu diesem Zeitpunkt enthalten, ist das, was das Dokument erhält; sie danach zu ändern, ändert nichts. Die hier am wichtigsten Eigenschaft ist CryptKeyLength, die das Schema aus den THPDFKeyType-Werten k40, k128, aes128 und aes256 auswählt. Nach BeginDoc zugewiesen erhält man keine Ausnahme, keine Warnung, nur eine Datei, die stillschweigend bei dem bleibt, womit sie gestartet ist. Diese Art von stillschweigender Abweichung ist die schlimmste: Sie besteht jeden lokalen Test und taucht Monate später als Compliance-Befund auf dem Schreibtisch eines Kunden auf.

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;

Passwörter sind UTF-8 und auf 127 Bytes begrenzt, was dem ISO 32000-2-Limit für AES-256-Schemata entspricht. Wenn die eigene Passwortrichtlinie längere Geheimnisse liefert, sollte die Kürzung selbst durchgeführt werden, auf der eigenen Seite, wo exakt kontrolliert wird, wo der Schnitt fällt. Dem Zufall überlassen, können die Bibliothek und ein zukünftiger Betrachter über den Kürzungspunkt uneinig sein, was eine Datei produziert, die sich für den Ersteller öffnet und das gleiche Passwort anderswo verweigert.

Revision 5 oder Revision 6: ein Boolean, zwei Ökosysteme

UseAES256R6 wählt zwischen den zwei AES-256-Handshakes, und die Wahl ist folgenreicher als ihr Boolean-Typ vermuten lässt. Bei False schreibt HotPDF Revision 5, das AES-256-Schema, das als Erweiterung zu PDF 1.7 eingeführt wurde und das ungefähr fünfzehn Jahre alte Betrachter öffnen können. Bei True erhält man Revision 6, die gehärtete Schlüsselableitung, die in ISO 32000-2 für PDF 2.0 standardisiert wurde und eine bekannte Schwäche bei der Passwortprüfung in Revision 5 schließt.

Revision 6 ist also kryptografisch die bessere Wahl. Sie ist auch die, die Probleme verursacht. Eine Revision-6-Datei benötigt einen Betrachter, der für PDF 1.7 Extension Level 3 oder PDF 2.0 entwickelt wurde, und viel eingesetzte Software ist beides nicht: Archivierungssysteme für Aufzeichnungen, eingebettete Renderer in anderen Produkten, branchenspezifische Werkzeuge, die seit Jahren niemand angefasst hat. Diese werden die Datei vollständig ablehnen, und zwar auf dem Rechner des Kunden, nie auf dem eigenen. Die praktische Standardeinstellung ist daher Revision 5. Revision 6 sollte nur gewählt werden, wenn eine Sicherheitsrichtlinie ISO 32000-2 explizit nach Revision nennt und wenn tatsächlich bestätigt wurde, dass jeder Verbraucher sie lesen kann. In jedem Fall sollte aufgeschrieben werden, welche gewählt wurde und warum, denn die nächste Person, die diesen Code anfasst, wird sich fragen.

Die älteren Schlüsseltypen verdienen einen Satz, damit klar ist, sie zu überspringen. THPDFKeyType listet noch k40, k128 und aes128, aber sie existieren, um historische Archive zu reproduzieren, nicht um neue zu schützen. 40-Bit-RC4 fällt handelsüblicher Hardware zum Opfer, und die 128-Bit-Schemata stammen aus der Zeit vor den AES-256-Revisionen, die jede aktuelle Sicherheitsprüfung erwartet. Für ein 2026 erstelltes Dokument lautet die eigentliche Frage nur Revision 5 versus Revision 6; wer sich bei einem neuen Entwurf nach den Legacy-Typen greift findet, bei dem ist irgendwo vorgelagert etwas schiefgelaufen.

Berechtigungs-Flags ohne Öffnungspasswort

Oft ist die Anforderung das Gegenteil von Geheimhaltung. Jeder soll das Dokument lesen können, aber Drucken oder Extraktion soll eingeschränkt sein. Das wird mit einem leeren Benutzerpasswort und einem nicht leeren Inhaberpasswort ausgedrückt, was PDF als Öffnungspasswort-Modus bezeichnet, und die erlaubten Operationen werden in ProtectOptions aufgelistet.

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;

Das THPDFProtectOptions-Set entspricht den ISO-Berechtigungs-Bits: prPrint und prPrint12bit für hochauflösendes Drucken, prInformationCopy für allgemeines Kopieren und Extraktion, prExtractContent für Extraktion durch Hilfstechnologien, sowie prModifyStructure, prEditAnnotations, prFillAnnotations und prAssemble. Zwei verdienen eine Warnung. prExtractContent sollte in fast jedem erstellten Profil aktiviert bleiben. Es ist das Bit, das ein Screenreader benötigt, um an den Text zu gelangen, und es zu deaktivieren verwandelt eine Berechtigungsentscheidung stillschweigend in einen Zugänglichkeitsfehler, der jemanden mit einer Behinderung trifft und nie gesehen wird. Die andere Falle ist prPrint allein ohne prPrint12bit: mehrere Betrachter reagieren darauf, indem sie die Druckqualität verringern, und Benutzer melden das als Rendering-Fehler statt als die Berechtigungseinstellung, die es tatsächlich ist.

Die Überprüfung dauert fünf Minuten und gehört in die Release-Checkliste. Eine Stichprobe jedes Profils in Acrobat öffnen, Dokumenteigenschaften öffnen und den Sicherheits-Tab lesen, der den Algorithmus aufschlüsselt („AES 256-Bit") und die erlaubten Operationen einzeln auflistet. Dann dieselbe Datei im ältesten Betrachter öffnen, den Kunden tatsächlich verwenden, nicht dem neuesten auf dem eigenen Rechner. Dieser zweite Öffnungsvorgang ist die günstige Versicherung gegen eine Revision-6-Datei, die die gesamte Entwicklung übersteht und bei einem Kunden stirbt, der nie aktualisiert hat.

Schutz aus bestehenden Dateien entfernen

Die Entschlüsselung folgt demselben Eigenschaftsmodell rückwärts. Das Dokument mit einem gültigen Zugangsdaten laden, Schutz deaktivieren und das Ergebnis ohne ihn speichern.

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;

Dieser Weg parst das gesamte Dokument in den Speicher, was für gewöhnliche Dateien in Ordnung und für sehr große verschwenderisch ist. Wenn die Eingabe Hunderte von Megabytes umfasst, ist DecryptFile die kostengünstigere Option: Es entschlüsselt während einer Kopie auf Dateiebene und nimmt einen direkten AES-256-Neuschreibepfad, der das Aufbauen des vollständigen Objektbaums überspringt, wo die Eingabe es erlaubt. Es ist Teil der Direct File API, die im Begleitartikel zur Verarbeitung großer PDFs aus Delphi behandelt wird.

Einschränkungen, die mit Verschlüsselung interagieren

Zwei Grenzen sollten bekannt sein, bevor das Design um Verschlüsselung herum erfolgt und nicht danach. Die erste ist die Archivkonformität. ISO 19005 verbietet Verschlüsselung in PDF/A, sodass jeder Workflow, der ein Dokument verschlüsselt und gleichzeitig PDF/A-Konformität beansprucht, konstruktionsbedingt widersprüchlich ist; HotPDF erlaubt es nicht, beides in einer Datei zu haben. Wenn beides tatsächlich benötigt wird, lautet die Antwort zwei Artefakte: eine verschlüsselte Kopie für die Verteilung und eine separate unverschlüsselte Kopie für das Archiv.

Die zweite Grenze ist drastischer. PDF-Verschlüsselung hat kein Treuhandsystem und keine Wiederherstellung. Das Benutzerpasswort einer R5- oder R6-Datei verlieren, und die Optionen sind Brute Force oder Aufgeben. Daher sollten Inhaber- und Benutzergeheimnisse wie jedes andere Produktions-Zugangsdaten behandelt werden. Generieren, in einem Tresor speichern, nach Plan rotieren. Das Einzige, was niemals getan werden darf, ist sie als Konstanten in einem Unit hartkodieren, wo sie direkt in die Versionsverwaltung gelangen und für immer in jeder Arbeitskopie eines Entwicklers sitzen.

Ein letzter Reflex ist es wert, eingebaut zu werden. Das Ändern des Schutzes einer nicht selbst erstellten Datei ist dieselbe Mechanik wie Entschlüsselung, kein separates Feature: sie mit ihrem Passwort über LoadFromFile laden, ProtectOptions oder die Passwörter an Ort und Stelle bearbeiten und mit SaveLoadedDocument zurückschreiben. Wer eine Datei entschlüsseln kann, kann sie auch neu berechtigen, und der Code sieht dem obigen Beispiel fast identisch aus.

Die hier gezeigten Schutzeigenschaften sind Teil der Standard-API der HotPDF Component für Delphi und C++Builder; die Produktseite enthält die vollständige Verschlüsselungsreferenz, einschließlich der vollständigen Berechtigungs-Aufzählung.