Ein Berechtigungsflag ist kein Sicherheitsmechanismus. Das Bit, das „kein Kopieren“ sagt, liegt im selben /Encrypt-Dictionary wie die Kryptografie, was ihm einen Anschein von Durchsetzung verleiht, den es nicht hat, und sobald Sie beides als eine Sache behandeln, beginnt Ihr Audit falsche Antworten zu liefern. Die einzige Frage, die sich an ein PDF zu stellen lohnt, lautet nicht „ist es verschlüsselt“. Sie ist spezifischer und schwerer: welcher Algorithmus, welche Revision des Security-Handlers, welches der beiden Passwörter gesetzt wurde, welche Berechtigungsbits beansprucht werden und welche Teile der Datei die Verschlüsselung tatsächlich berührt. Eine Datei kann formal verschlüsselt und praktisch offen sein. Sie kann sich dem Lesen verweigern und trotzdem ihre Metadaten im Klartext lassen. Sie kann das Drucken in einem Flag sperren, das jeder Viewer ignorieren darf. Ein PDF zu auditieren heißt, all das getrennt aufzulösen, und PDF Library for Delphi, die PDF-Engine von losLab für Delphi und C++Builder, stellt jeden dieser Punkte sowohl über eine flache Integer-Handle-API als auch über eine typisierte Klassenschicht bereit
Was das /Encrypt-Dictionary tatsächlich festhält
ISO 32000-1 §7.6 definiert die Dokumentsicherheit über eine Handvoll Dictionary-Einträge, und PDF Library for Delphi spiegelt sie eins zu eins im Record TPDFEncryption. Filterversion V und Revision R wählen die Algorithmusfamilie. Length trägt die Schlüsselgröße. Die Berechtigungsbits sitzen in P, die Validierungsstrings für Owner- und User-Passwort in O und U (für AES-256 ergänzt um OE und UE), ein EncryptMetadata-Flag läuft nebenher mit, und drei weitere Felder benennen die Crypt-Filter, die jeweils auf Strings, Streams und eingebettete Dateien angewendet werden
Der Wert dieses Records liegt darin, dass er nichts für Sie interpretiert. Er liefert das rohe Dictionary und überlässt Ihnen die Schlussfolgerungen, genau das, was ein Audit braucht. Der Fall „Klartext innerhalb von verschlüsselt“ zeigt sich in StringFilterIdentity und StreamFilterIdentity: Ist eines davon wahr, passieren die entsprechenden Daten den Identity-Filter unverändert, ganz gleich, was der Verschlüsselungsstatus des Dokuments meldet. Ein Scanner, der bei „ein /Encrypt-Dictionary ist vorhanden“ stehen bleibt, nennt eine solche Datei geschützt, während ihre Strings und Streams im Klartext liegen. Dieselbe Nuance gilt für Metadaten. Ist EncryptMetadata falsch, bleibt das XMP-Paket für jeden Indexer lesbar, der Seiteninhalt hingegen nicht, was man in dem Moment wissen sollte, in dem die eigenen Routing-Regeln auf ein Titel- oder Autorfeld reagieren
Eine kurze Sicherheitssonde mit der flachen API
Für die meisten Pipelines beantworten vier flache Aufrufe die Alltagsfragen. LoadFromFile liefert bei Erfolg 1, und sobald das Dokument offen ist, berichten die Verschlüsselungsinspektoren über seinen entschlüsselten Zustand:
var
PDF: TPDFlib;
begin
PDF := TPDFlib.Create;
try
if PDF.LoadFromFile('contract.pdf', UserPassword) <> 1 then
raise Exception.Create('Open failed: wrong password or damaged file');
Writeln('status : ', PDF.EncryptionStatus); // entschlüsselt / verschlüsselt / unbekannt
Writeln('algorithm : ', PDF.EncryptionAlgorithm); // RC4- vs. AES-Familie
Writeln('strength : ', PDF.EncryptionStrength); // Schlüssellängenklasse
Writeln('owner pw? : ', PDF.CheckPassword(CandidatePassword));
finally
PDF.Free;
end;
end;
CheckPassword ist wichtiger, als seine einzeilige Signatur vermuten lässt. PDF definiert zwei Passwörter mit ungleicher Macht. Das User-Passwort ist nötig, um die Datei überhaupt zu öffnen. Das Owner-Passwort gewährt volle Rechte und übersteuert jedes Berechtigungsbit. Die Bytes auf der Festplatte sind in beiden Fällen identisch, aber eine mit dem Owner-Passwort geöffnete Sitzung kann Dinge tun, die die User-Passwort-Sitzung nicht kann, sodass ein Audit, das nicht festhält, welche Berechtigung vorgelegt wurde, nur die halbe Wahrheit festhält. Die Klassenschicht macht die Unterscheidung abfragbar. TPDFDocument.HasUserPassword und HasOwnerPassword melden, was die Datei verlangt, während IsUserPassword und IsOwnerPassword melden, welches Passwort die aktuelle Sitzung tatsächlich geöffnet hat. Protokollieren Sie diesen Umstand. Protokollieren Sie nie die Passwortwerte selbst
Die Strength-Leiter, auf der „AES-256“ zweierlei bedeutet
Die flachen Funktionen Encrypt und EncryptFile nehmen einen Integer Strength mit fünf bedeutsamen Werten: 0 für 40-Bit-RC4, 1 für 128-Bit-RC4, 2 für 128-Bit-AES, lesbar ab Acrobat 7, 3 für 256-Bit-AES, wie mit Acrobat 9 eingeführt, und 4 für 256-Bit-AES, wie von Acrobat X und später verlangt
Das Interessante ist, dass 3 und 4 beide als AES-256 bezeichnet werden und nicht dasselbe Schema sind. Strength 3 entspricht Security-Handler-Revision 5, einem Übergangsdesign, das Acrobat 9 auslieferte und das die ISO nie übernahm. Strength 4 entspricht Revision 6, deren Schlüsselableitungsfunktion gehärtet und in ISO 32000-2 standardisiert wurde. Für ein Dokument, das Sie heute erstellen, gibt es keinen Grund, 3 statt 4 zu wählen. Für ein Audit ist die Lücke entscheidend: Eine Richtlinie, die „AES-256 nach ISO 32000-2“ verlangt, erfüllt allein R6, und eine R5-Datei, die sich AES-256 nennt, fällt bei dieser Richtlinie durch, während sie eine naive Stärkeprüfung besteht. Die Klassenschicht hält beide namentlich auseinander, esAES256Bit für R5 gegenüber esAES256BitAcroX für R6, und die Eigenschaft EncryptionAcroX beantwortet die Revisionsfrage mit einem einzigen Boolean
Berechtigungsbits und ihr Kleingedrucktes zur Schlüssellänge
EncodePermissions packt acht Flags in den Integer, den Encrypt und EncryptFile erwarten. Drucken, Kopieren, Ändern und Notizen-Hinzufügen bilden den Grundsatz; Felder-Ausfüllen, Kopieren-für-Barrierefreiheit, Zusammenstellen und Drucken-in-voller-Qualität bilden den erweiterten Satz. Das Kleingedruckte, das die bibliothekseigene Verschlüsselungsdemo ausdrücklich nennt: Die erweiterten vier greifen nur ab 128-Bit-Stärke. Das Flag für Druck in voller Qualität fällt unter dieselbe Regel: Löschen Sie es, um niedrig aufgelöstes Drucken zu erzwingen, ignoriert Sie ein 40-Bit-Dokument, denn auch diese Herabstufung erfordert 128-Bit- oder stärkere Verschlüsselung. Kodieren Sie eine Richtlinie „nur niedrig aufgelöst drucken“ in eine 40-Bit-Datei, druckt trotzdem jeder Viewer in voller Qualität
Die tiefere Frage ist, wer eines dieser Bits durchsetzt, und die Antwort lautet: niemand, dem Sie vertrauen können. Berechtigungen sind Anweisungen an konforme Reader, keine kryptografischen Beschränkungen. Der Entschlüsselungsschlüssel ist identisch, ob Kopieren erlaubt oder verweigert ist, ein restriktiver Berechtigungssatz hält also nur ehrliche Viewer ehrlich. Ein Reader, der die Bits ignorieren will, stößt auf keinerlei kryptografisches Hindernis. Besteht die Pflicht darin, Extraktion zu verhindern statt sie zu erschweren, braucht die Datei ein User-Passwort und der Workflow Kontrollen auf Prozessebene drumherum, und ein Audit-Bericht sollte benennen, unter welchem der beiden Regimes jede Datei tatsächlich steht, statt ein Berechtigungsflag als Schloss zu behandeln
Richtlinie setzen und nachweisen, dass sie gegriffen hat
Um bestehende Dateien zu verschlüsseln, müssen sie nicht in den Objektbaum geladen werden. EncryptFile verarbeitet Eingabe zu Ausgabe in einem einzigen Aufruf, und die Audit-Schleife öffnet das Ergebnis erneut, um zu bestätigen, was auf der Festplatte gelandet ist. Die mitgelieferte Verschlüsselungsdemo folgt demselben Muster aus Schreiben und Zurücklesen:
var
PDF: TPDFlib;
R: Integer;
begin
PDF := TPDFlib.Create;
try
R := PDF.EncryptFile('in.pdf', 'out.pdf', 'owner-secret', 'user-secret', 4,
PDF.EncodePermissions(1, 0, 0, 0, // Drucken erlaubt; Kopieren/Ändern/Notizen verweigert
0, 0, 0, 1)); // erweiterter Satz: nur Druck in voller Qualität
if (R = 1) and (PDF.LoadFromFile('out.pdf', 'user-secret') = 1) then
begin
Writeln('algorithm = ', PDF.EncryptionAlgorithm);
Writeln('strength = ', PDF.EncryptionStrength);
Writeln('owner pw accepted: ', PDF.CheckPassword('owner-secret'));
end;
finally
PDF.Free;
end;
end;
Teams, die auf Dokumentebene arbeiten, bekommen dieselbe Operation mit typisierten Mengen statt Bit-Packen, was ein Code-Review mit deutlich weniger Stirnrunzeln übersteht:
if not Doc.Encrypt('owner-secret', 'user-secret', esAES256BitAcroX,
[ppCanPrint], [ppCanPrintFull]) then
raise Exception.Create('Encryption failed');
So oder so ist der Rücklese-Schritt kein optionales Zeremoniell. Er fängt die Deployment-Fehler ab, die sonst Monate später auf der Maschine eines Kunden auftauchen: ein alter Bibliotheks-Build, der die angeforderte Stärke stillschweigend herabstuft, ein Ausgabepfad, der nie geschrieben wurde, weil das Verzeichnis schreibgeschützt war, ein Berechtigungs-Integer, dessen Argumente in falscher Reihenfolge hineingingen. Alle drei bestehen einen lokalen Smoke-Test und versagen im Feld, und das erneute Öffnen der Ausgabe verwandelt jeden davon in eine Exception, die Sie während des Laufs sehen, der die Datei erzeugt hat. GetEncryptionFingerprint liefert einen kompakten Wert, den Sie beim Job-Datensatz speichern können, sodass ein späterer Vergleich sagen kann, ob zwei Ausgaben dieselbe Verschlüsselungskonfiguration teilen, ohne eine von beiden erneut zu öffnen
Audit-Fehlalarme, für die sich Code lohnt
Ein paar Muster treiben Sicherheitsscanner zuverlässig zum falschen Schluss, und jedes davon entsteht, wenn eine mehrteilige Frage auf eine Ja-oder-Nein-Antwort zusammengefaltet wird. Der Identity-Crypt-Filter ist das sauberste Beispiel. Ein /Encrypt-Dictionary ist vorhanden, die Datei meldet sich als verschlüsselt, und doch laufen Strings und Streams unverändert durch den Identity-Filter, der eigentliche Inhalt ist also Klartext. StringFilterIdentity und StreamFilterIdentity zu lesen, bevor man irgendetwas für geschützt erklärt, ist die Abhilfe
Die Metadaten-Trennung ist subtiler. EncryptMetadata kann dem Rest des Dokuments in beide Richtungen widersprechen und eine verschlüsselte Datei mit lesbarem XMP-Paket hinterlassen oder, seltener, das Umgekehrte. „Die Datei ist verschlüsselt“ sagt nichts darüber, ob es ihre Metadaten sind, was in dem Moment zählt, in dem ein Indexer oder eine Routing-Regel nach dem Titel greift. Eingebettete Dateien fügen eine dritte Achse hinzu: PDF erlaubt einen eigenen Crypt-Filter nur für Anhänge, sodass die Anhänge der einzige verschlüsselte Teil eines ansonsten offenen Dokuments sein können oder der einzige Klartextteil eines verschlüsselten. Erfassen Sie die drei Filterzuweisungen als getrennte Felder für Strings, Streams und eingebettete Dateien, und keine dieser Fallen kann Sie erwischen. Speichern Sie einen einzigen Boolean, und die falsche Entscheidung ist nur eine Frage der Zeit
Verschlüsselung entfernen und für neue Dateien wählen
Ein Audit endet oft mit der Entscheidung, den Schutz zu entfernen, und die Mechanik ist dabei nicht das Hindernis. DecryptFile(InputFileName, OutputFileName, Password) schreibt eine entschlüsselte Kopie ohne vollständiges Laden, und das Decrypt des geladenen Dokuments tut dasselbe im Speicher, sobald eine Datei bereits offen ist. Beide verlangen ein gültiges Passwort; keines umgeht die Kryptografie. Das eigentliche Tor ist Richtlinie, nicht Code, lassen Sie Ihre Eingangsregeln also klar sagen, wann das Entfernen erlaubt ist, und halten Sie die Passwortklasse fest, die es autorisiert hat, denn der technische Schritt selbst hinterlässt keine Spur
Die Wahl für neue Ausgaben ist enger, als die fünf Strength-Werte nahelegen. Verwenden Sie Strength 4, AES-256 Revision 6, sofern Sie Dateien nicht in Viewern älter als Acrobat X öffnen müssen. Strength 2, AES-128, ist die pragmatische Untergrenze für eine alternde Viewer-Flotte, die sich nicht aktualisieren lässt. Die RC4-Optionen 0 und 1 sind da, damit Sie historische Archive lesen und auditieren können, nicht damit Sie etwas Neues damit erzeugen; wer in einem Design von 2026 danach greift, hat ein Zeichen dafür, dass eine Anforderung weiter vorne veraltet ist
Der Verschlüsselungszustand fließt direkt in Signaturentscheidungen ein, denn eine Workbench, die Dokumente validiert und signiert, braucht dieselbe Rücklese-Disziplin, auf die dieses Audit setzt. Dieses Terrain deckt der Artikel zur Compliance- und Signatur-Workbench ab. Wenn ein Batch EncryptFile über Tausende großer Dokumente anwendet, zeigt der Direktzugriffs-Leitfaden zu großen PDFs, wie der Speicherbedarf dabei flach bleibt. Die vollständige Referenz der Verschlüsselungs-API finden Sie auf der Produktseite von PDF Library for Delphi