Zum Inhalt springen
getnextpdf.com

Enterprise Edition

Digitales Wasserzeichen und steganografische Einbettung

NextPDF Enterprise bettet einen versteckten, verschlüsselten Payload in ein erzeugtes PDF ein, indem es kleine, kontrollierte Anpassungen an den Abständen zwischen Buchstabenpaaren vornimmt. Sie liefern einen Payload — typischerweise eine Kennung pro Empfänger — und einen geheimen Schlüssel; der Encoder schreibt den Payload als unmerkliche Abweichungen vom natürlichen Kerning des Texts. Ein passender Decoder, dem derselbe Schlüssel gegeben wird, stellt den Payload wieder her. Diese Seite ist auf Verhaltensebene: Sie benennt, was der Encoder schreibt, die verwendete Kryptografie und die Grenze der Technik.

Der vorgesehene Einsatz ist das interne Dokument-Leak-Tracing: Wenn ein kontrolliertes Dokument geleakt wird, identifiziert der wiederhergestellte Marker die Empfängerkopie. Es ist keine adversariale Steganografie und keine Garantie, beliebige Verarbeitung zu überstehen.

Voraussetzungen sind im Frontmatter benannt und unter Voraussetzungen wiederholt.

Diese Fähigkeit wird in NextPDF Enterprise (nextpdf/enterprise) ausgeliefert und aktiviert sich mit einem Lizenz-Envelope der Enterprise-Stufe. Eine Bereitstellung ohne diese Berechtigung lädt die Klassen der Fähigkeit nicht. Die Fähigkeit läuft während der Dokumenterzeugung vollständig in-process; kein Dokumentinhalt verlässt den Host. Editionen vergleichen und Lizenz erwerben.

PDF-Text, der mit einem Kerning-Array gezeichnet wird, trägt eine numerische Anpassung zwischen Glyphen. Der Encoder behandelt jede Anpassungsposition als Träger für einige Bits:

  1. Er verschlüsselt den Payload mit einem AEAD-Cipher (authenticated encryption with associated data) — standardmäßig AES-256-GCM oder ChaCha20-Poly1305. AEAD bietet sowohl Vertraulichkeit als auch Integrität, sodass ein manipulierter Träger bei der Entschlüsselung scheitert, statt stillschweigend einen falschen Payload zu liefern.
  2. Er leitet den 32-Byte-Verschlüsselungsschlüssel aus Ihrem geheimen Schlüssel und dem Font-Schlüssel mit der HMAC-basierten Key Derivation Function (HKDF) mit SHA-256 ab. HKDF extrahiert einen Pseudozufallsschlüssel fester Länge aus dem Eingabe-Schlüsselmaterial und expandiert ihn dann auf die erforderliche Länge, gemäß RFC 5869 §2.
  3. Er erzeugt pro Verschlüsselung einen frischen, zufälligen 12-Byte-Initialisierungsvektor (IV). AES-GCM erfordert, dass der IV für einen gegebenen Schlüssel eindeutig ist, sonst geht die Authentifizierungszusicherung verloren, gemäß NIST SP 800-38D §5.2.1.
  4. Er bildet die verschlüsselten Bytes auf eine Bitsequenz ab und verteilt die Bits über die verfügbaren Buchstabenpaar-Positionen, wobei ein oder zwei Bits pro Position codiert werden. Die Abweichung, die er dem natürlichen Kerning hinzufügt, ist durch einen konfigurierbaren Bruchteil des Gevierts (em) begrenzt — klein genug, um visuell unmerklich zu bleiben.

Der Decoder kehrt den Prozess um: Er liest die Kerning-Anpassungen aus einem Content-Stream, subtrahiert das natürliche Kerning, quantisiert die Abweichungen zurück zu Bits, setzt den verschlüsselten Blob wieder zusammen und entschlüsselt ihn mit demselben Schlüssel. Ist der Schlüssel falsch oder der Träger zerstört, gibt die Entschlüsselung nichts zurück, statt eines falschen Payloads.

Die Kapazität skaliert mit der Textlänge: Jede Buchstabenpaar-Position trägt ein oder zwei Bits, sodass ein Payload in die vom Text bereitgestellten Positionen passen muss. Der Encoder löst einen typisierten Overflow-Fehler aus, wenn der Payload die Kapazität überschreitet.

Ein PDF/A-Kompatibilitätsmodus halbiert die maximale Abweichung, um unter der Breitentoleranz-Schwelle eines Validators zu bleiben, und tauscht Kapazität gegen striktere Konformität.

Die tragende Entscheidung ist, den Marker im Kerning zu verstecken, statt in einem sichtbaren Overlay oder einem Metadatenfeld. Ein Metadaten-Marker lässt sich trivial entfernen, und ein sichtbarer Stempel verändert die Seite. Kerning-Abweichungen hingegen fahren im Text mit, den der Empfänger behalten muss, und bleiben unmerklich. Authentifizierte Verschlüsselung ist die zweite Säule: Ein manipulierter oder unvollständiger Träger scheitert an der Authentifizierung, sodass der Decoder nichts zurückgibt statt eines falschen Empfängers. Der Schlüssel wird pro Font mit HKDF abgeleitet, was den Marker an den Dokumentkontext bindet, nicht an ein bloßes geteiltes Geheimnis. Die ehrliche Robustheitsoffenlegung folgt daraus unmittelbar: Der Marker übersteht gewöhnliche Weiterverteilung, aber kein gezieltes Content-Stream-Rewriting, weshalb der benannte Umfang internes Leak-Tracing ist, nicht adversariale Steganografie.

Design-Hintergrund: Schwärzung ist kein schwarzes Rechteck.

  1. Installieren Sie NextPDF Core und das Enterprise-Paket und halten Sie eine aktive Enterprise-Lizenz.
  2. Erzeugen Sie das Dokument mit einem Font, der Kerning-Paar-Metriken bereitstellt; der Encoder liest das natürliche Kerning aus den Font-Metriken.
  3. Liefern Sie den geheimen Schlüssel aus Ihrem Secret Manager, nicht aus dem Quellcode. Derselbe Schlüssel ist zum Decodieren erforderlich.
  4. Entscheiden Sie über die Bit-Tiefe (ein oder zwei Bits pro Position) und ob PDF/A-Kompatibilität erforderlich ist, basierend auf Ihren Kapazitäts- und Konformitätsbedürfnissen.

Die Encoding-Konfiguration ist unveränderlich und wird bei der Konstruktion validiert:

  • Bit-Tiefe — ein oder zwei Bits pro Buchstabenpaar-Position. Höhere Tiefe gibt mehr Kapazität, aber größere Abweichungen.
  • Maximales Anpassungsverhältnis — die Abweichungsobergrenze als Bruchteil des Gevierts (em), innerhalb eines begrenzten Bereichs. Größere Werte geben mehr Spielraum, riskieren aber Sichtbarkeit.
  • Cipher — AES-256-GCM (Standard) oder ChaCha20-Poly1305. Beide sind AEAD.
  • PDF/A-Kompatibilität — wenn aktiviert, halbiert sie die effektive maximale Abweichung.

Verwenden Sie dieselbe Konfiguration für Encoding und Decoding; eine Abweichung ergibt keinen wiederhergestellten Payload.

  1. Lesen Sie den geheimen Schlüssel aus Ihrem Secret Manager.
  2. Bauen Sie die Encoding-Konfiguration (Bit-Tiefe, Abweichungsverhältnis, Cipher, PDF/A-Flag).
  3. Berechnen Sie die Kerning-Anpassungen für den Text, den Sie gleich rendern, und übergeben Sie dabei den Payload, den Text, den Font-Schlüssel, die Font-Metriken, den geheimen Schlüssel und die Konfiguration.
  4. Wenden Sie die zurückgegebenen Anpassungen an, wenn Sie den Textrun schreiben, sodass der Marker während der Erzeugung eingebettet wird.
  5. Um eine geleakte Kopie zu verfolgen, führen Sie den Decoder über den Content-Stream des verdächtigen Dokuments mit demselben Font-Schlüssel, denselben Font-Metriken, demselben geheimen Schlüssel und derselben Konfiguration aus und lesen Sie den wiederhergestellten Payload.
examples/enterprise/steganography-capacity-guard.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
/**
* Reject a payload that cannot fit the carrier text before encoding.
*
* Each letter-pair position carries $bitDepth bits. Guarding capacity up
* front turns an unencodable payload into a clear caller-side error instead
* of relying on the encoder's overflow exception alone.
*
* @param non-empty-string $payload The bytes to embed (already minimal).
* @param positive-int $textLength The character count of the carrier text.
* @param int<1, 2> $bitDepth Bits encoded per letter-pair position.
*
* @throws \OverflowException When the payload cannot fit the available positions.
*/
function assertPayloadFits(string $payload, int $textLength, int $bitDepth): void
{
$positions = $textLength - 1;
$capacityBytes = \intdiv($positions * $bitDepth, 8);
if (\strlen($payload) > $capacityBytes) {
throw new \OverflowException(\sprintf(
'Payload of %d bytes exceeds carrier capacity of %d bytes.',
\strlen($payload),
$capacityBytes,
));
}
}
examples/enterprise/steganography-decode-guarded.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Enterprise\Security\Steganography\SteganographyDecoder;
use NextPDF\Enterprise\Security\Steganography\SteganographyConfig;
use NextPDF\Typography\FontMetrics;
use Psr\Log\LoggerInterface;
final readonly class LeakTracer
{
public function __construct(private LoggerInterface $logger) {}
/**
* Recover the embedded marker from a suspect document's content stream.
*
* Decoding returns null on a wrong key or a destroyed carrier rather than
* a wrong payload, so the caller treats null as "no marker recovered".
*
* @param string $contentStream The suspect content-stream bytes.
* @param non-empty-string $fontKey The font key used at generation.
* @param FontMetrics $metrics Font metrics with kerning pairs.
* @param string $secretKey The same secret key used to encode.
* @param SteganographyConfig $config The same configuration used to encode.
*
* @return string|null The recovered marker, or null when none is found.
*/
public function trace(
string $contentStream,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config,
): ?string {
$marker = SteganographyDecoder::decodeFromContentStream(
$contentStream,
$fontKey,
$metrics,
$secretKey,
$config,
);
if ($marker === null) {
$this->logger->info('No steganographic marker recovered from content stream.');
}
return $marker;
}
}
  1. Codieren Sie einen bekannten Payload in einen bekannten Textrun und decodieren Sie ihn dann mit demselben Schlüssel und derselben Konfiguration zurück; bestätigen Sie, dass der wiederhergestellte Payload übereinstimmt.
  2. Decodieren Sie mit einem bewusst falschen Schlüssel und bestätigen Sie, dass das Ergebnis null ist, kein falscher Payload — dies ist die AEAD-Integritätsgarantie in Aktion.
  3. Inspizieren Sie die gerenderte Seite und bestätigen Sie, dass die Abstandsänderung beim konfigurierten Abweichungsverhältnis nicht visuell wahrnehmbar ist.
  4. Wenn PDF/A-Kompatibilität erforderlich ist, validieren Sie die Ausgabe gegen Ihr PDF/A-Profil und bestätigen Sie, dass die Breitentoleranz nicht ausgelöst wird.
  • Authentifizierte Verschlüsselung. Der Payload wird mit AES-256-GCM oder ChaCha20-Poly1305 verschlüsselt. Ein manipulierter oder abgeschnittener Träger scheitert bei der Entschlüsselung an der Authentifizierung; er liefert keinen falschen Payload.
  • IV pro Verschlüsselung. Für jede Verschlüsselung wird ein frischer, zufälliger 12-Byte-IV erzeugt, was die AES-GCM-Eindeutigkeitsanforderung gemäß NIST SP 800-38D §5.2.1 erfüllt.
  • Abgeleiteter Schlüssel. Der Verschlüsselungsschlüssel wird mit HKDF-SHA-256 aus Ihrem Secret und dem Font-Schlüssel abgeleitet (RFC 5869 §2). Bewahren Sie das Secret in Ihrem Secret Manager auf; behandeln Sie es wie jedes Signier-Secret.
  • Der Marker ist Dokumentinhalt. Die eingebetteten Bytes sind Teil des Seiteninhalts, nicht Log-Inhalt. Schreiben Sie den Payload oder den geheimen Schlüssel nicht in Logs.

Diese Seite betrifft kryptografische Einbettung. Jede normative Quelle ist paraphrasiert; es wird kein normativer Text wiedergegeben. ### Robustheitsoffenlegung

Der Marker wird in Kerning-Anpassungen getragen. Er kann durch Drucken und erneutes Scannen, durch PDF-Konvertierungswerkzeuge, durch erneute Linearisierung oder durch jedes Content-Stream-Rewriting, das das Kerning normalisiert, zerstört werden. Die Technik eignet sich am besten für das interne Leak-Tracing von Dokumenten, die in ihrer erzeugten Form verteilt werden. Sie ist keine adversariale Steganografie und übersteht keine beliebige nachgelagerte Verarbeitung. Verlassen Sie sich nicht als alleinige Kontrolle darauf, wenn das Bedrohungsmodell ein gezieltes Entfernen umfasst.

  • Payload zu groß. Der Encoder löst einen typisierten Overflow-Fehler aus, wenn der Payload die Textkapazität überschreitet. Kürzen Sie den Payload oder verlängern Sie den Trägertext.
  • Zu wenig Trägertext. Text, der kürzer als zwei Zeichen ist, bietet keine Trägerposition und löst einen Fehler aus.
  • Falscher Schlüssel beim Decodieren. Das Decodieren gibt null zurück. Behandeln Sie null als „kein Marker wiederhergestellt“, nicht als Teilergebnis.
  • Konfigurations-Mismatch. Encoding und Decoding müssen dieselbe Bit-Tiefe, dasselbe Abweichungsverhältnis, denselben Cipher und dasselbe PDF/A-Flag verwenden; eine Abweichung ergibt keinen wiederhergestellten Payload.

Diese Seite dokumentiert ausschließlich extern beobachtbares Verhalten und die unterstützte öffentliche API-Oberfläche. Interne Namespace-Pfade, Hilfsklassen, Mechanismus-Tabellen, Runbook-Dateinamen und Ticket-Präfixe liegen außerhalb des Umfangs.