Zum Inhalt springen
getnextpdf.com

Enterprise Edition

Steganographie — Ausführliche Referenz

Diese Tiefenreferenz dokumentiert den steganographischen Kanal von NextPDF Enterprise. Der Kanal verbirgt eine verschlüsselte Payload in den numerischen Kern-Anpassungen eines TJ-Textausgabe-Arrays. Er verfügt über vier öffentliche Symbole: SteganographyEncoder, SteganographyDecoder, SteganographyConfig und SteganographyCapacity. Der Encoder leitet einen Schlüssel mit HKDF-SHA-256 ab, verschlüsselt die Payload mit einer AEAD-Chiffre und gibt positionsbezogene Kern-Offsets zurück. Der Decoder kehrt den Vorgang aus beobachteten Anpassungen oder aus einem Roh-Content-Stream um.

Der Kanal ist für die interne Rückverfolgung von Dokumentenlecks konzipiert. Er ist keine Steganographie in Angreiferqualität. Kodierte Daten können durch Drucken-dann-Scannen, PDF-Konvertierung, Re-Linearisierung, Umschreiben des Content-Streams oder jeden Vorgang, der das Kerning normalisiert, zerstört werden. NextPDF besitzt für diesen Kanal keine Zertifizierung und erteilt keine. Diese Seite beschreibt Fähigkeit, nicht Konformität.

Diese Fähigkeit wird mit 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. Editionen vergleichen und eine Lizenz erwerben.

Der Kanal stellt vier finale Klassen bereit. Alle Einstiegspunkte sind public static, mit Ausnahme des SteganographyConfig-Konstruktors und seines effectiveMaxOffset-Accessors. Die unterstützende NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException wird vom Encoder geworfen; sie ist kein durch den Aufrufer zu konstruierender Typ.

SymbolParameterStandardverhaltenRückgabeWirft oder scheitert mitAnmerkungen
SteganographyEncoder::encode$payload, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Leere $payload gibt [] zurück; prüft die Schlüsselstärke; verschlüsselt; berechnet positionsbezogene Kern-Offsets.array<int, float> (Position => Anpassung in 1/1000 em, AFM-Konvention)InvalidArgumentException (Schlüssel unter dem Mindestwert); OverflowException (Text unter 2 Zeichen oder Payload über der Kapazität); SteganographyEncryptionException (AEAD-Fehler)Übergeben Sie das Ergebnis an NextPDF\Content\TextRenderer::buildTjArrayOperator(). Die API liefert Anpassungen nach AFM-Konvention; buildTjArrayOperator() führt die numerische PDF-TJ-Konvertierung durch (ISO 32000-2 subtrahiert die Zahl von der aktuellen Position). Autoren, die Content-Streams manuell schreiben, müssen diese Vorzeichenkonvention beibehalten.
SteganographyEncoder::assertSecretKeyStrength$secretKeyWeist einen Schlüssel zurück, der kürzer als der Mindestwert ist.voidInvalidArgumentException (Schlüssel unter dem Mindestwert)Gemeinsame Schreibpfad-Absicherung, gespiegelt auf dem Lesepfad.
SteganographyEncoder::MIN_SECRET_KEY_LENGTHKonstanteDer 128-Bit-Mindestwert für die Schlüssellänge in Bytes.int (16)Nicht anwendbarDie Bibliothek erzwingt Länge, nicht Entropie.
SteganographyDecoder::decode$observedAdjustments, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Prüft die Schlüsselstärke; quantisiert Abweichungen; rekonstruiert den Blob; entschlüsselt per AEAD.`stringnull(Payload odernull` bei falschem Schlüssel oder ohne Payload)InvalidArgumentException (Schlüssel unter dem Mindestwert)
SteganographyDecoder::decodeFromContentStream$contentStream, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Tokenisiert den Stream, rekonstruiert Text und Anpassungen aus TJ-Arrays und delegiert dann an decode.`stringnull(Payload odernull, wenn kein TJ`-Text vorhanden ist oder die Entschlüsselung fehlschlägt)InvalidArgumentException (Schlüssel unter dem Mindestwert, über decode)
SteganographyConfig::__construct$bitDepth, $maxAdjustmentEmRatio, $cipher, $requirePdfACompatibilityValidiert die Domäne jedes Arguments; erzeugt ein unveränderliches Value-Object.SteganographyConfig-InstanzInvalidArgumentException (ungültige $bitDepth, $maxAdjustmentEmRatio oder $cipher)readonly-Klasse; die vier Argumente sind öffentlich promotete Eigenschaften.
SteganographyConfig::effectiveMaxOffsetkeineGibt $maxAdjustmentEmRatio * 1000 zurück, halbiert, wenn PDF/A-Kompatibilität angefordert wird.float (Offset in 1/1000 em)Nicht anwendbarDie Halbierung verringert das Risiko der Breitenabweichungs-Erkennung.
SteganographyConfig::CRYPTO_OVERHEADKonstanteDer feste Verschlüsselungs-Overhead pro Payload in Bytes.int (32)Nicht anwendbar4-Byte-Länge, 12-Byte-Nonce, 16-Byte-Tag.
SteganographyCapacity::calculate$text, $config (SteganographyConfig)Berechnet die nutzbaren Payload-Bytes für den Text nach Abzug des Overheads.int (0, wenn der Text zu kurz ist)Nicht anwendbarDie Kapazität ist positions * bitDepth / 8 minus Overhead.
SteganographyCapacity::minimumTextLength$payloadBytes, $config (SteganographyConfig)Berechnet die minimale UTF-8-Zeichenanzahl für eine Payload.int (Zeichenanzahl)Nicht anwendbarUmkehrung von calculate.

Die wortgetreuen Signaturen folgen, jeweils mit Quellenangabe.

public static function encode(
string $payload,
string $text,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): array
public static function assertSecretKeyStrength(string $secretKey): void
public const int MIN_SECRET_KEY_LENGTH = 16;
public static function decode(
array $observedAdjustments,
string $text,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): ?string
public static function decodeFromContentStream(
string $contentStream,
string $fontKey,
FontMetrics $metrics,
string $secretKey,
SteganographyConfig $config = new SteganographyConfig(),
): ?string
public function __construct(
public int $bitDepth = 1,
public float $maxAdjustmentEmRatio = 0.02,
public string $cipher = 'aes-256-gcm',
public bool $requirePdfACompatibility = false,
)
public function effectiveMaxOffset(): float
public const int CRYPTO_OVERHEAD = 32;
public static function calculate(
string $text,
SteganographyConfig $config = new SteganographyConfig(),
): int
public static function minimumTextLength(
int $payloadBytes,
SteganographyConfig $config = new SteganographyConfig(),
): int

Der Encoder zerlegt $text in UTF-8-Zeichen und bildet eine Position pro aufeinanderfolgendem Zeichenpaar. Jede Position trägt $config->bitDepth Bits, also eines oder zwei. Die Payload wird zuerst verschlüsselt, dann zu einem Blob serialisiert und schließlich in eine Bitsequenz umgewandelt. Jede Position kodiert ihre Bits als kleinen nicht-negativen Offset, der zum natürlichen Kern-Wert für dieses Zeichenpaar addiert wird.

Der Offset ist ein Bruchteil des effektiven maximalen Offsets. Der effektive maximale Offset ist $maxAdjustmentEmRatio * 1000 Design-Einheiten, halbiert, wenn $requirePdfACompatibility true ist. Der natürliche Kern wird aus $metrics über FontMetrics::getKernPair gelesen. Die zurückgegebene Map ist dünn besetzt: eine Position, deren endgültige Anpassung exakt null ist, wird weggelassen.

Die Verschlüsselung verwendet HKDF-SHA-256, um einen 32-Byte-Schlüssel abzuleiten. Das HKDF-Salt ist der nicht geheime $fontKey und das Info-Label eine feste Konstante. Daher ist der $secretKey des Aufrufers die einzige Vertraulichkeitsgrenze. Die AEAD-Chiffre ist aes-256-gcm oder chacha20-poly1305, ausgewählt über $config->cipher, ausgeführt über openssl_encrypt mit einer frischen 12-Byte-Nonce und einem 16-Byte-Tag. Der serialisierte Blob besteht aus einer 4-Byte-Big-Endian-Länge, der 12-Byte-Nonce, dem Chiffretext und dem 16-Byte-Tag; dieser feste Overhead ist CRYPTO_OVERHEAD, also 32 Bytes.

Der Decoder kehrt die Transformation um. Er berechnet die Abweichung jeder beobachteten Anpassung vom natürlichen Kern, normalisiert sie über den effektiven maximalen Offset und quantisiert auf die nächstgelegene Stufe. Er setzt den Blob wieder zusammen, validiert den Längen-Header und ruft openssl_decrypt auf. Ein falscher Schlüssel, eine fehlende Payload oder beschädigte Anpassungen lassen die AEAD-Authentifizierung fehlschlagen, und der Decoder gibt null zurück. decodeFromContentStream tokenisiert zuerst den Roh-Stream mit NextPDF\Pro\Projection\ContentProjectionWriter::tokenize, rekonstruiert den Text und die numerischen Anpassungen aus jedem TJ-Array und delegiert dann an decode.

SteganographyCapacity::calculate meldet die nutzbare Payload-Größe für einen Text und eine Konfiguration nach Abzug von CRYPTO_OVERHEAD; sie gibt null zurück, wenn der Text zu kurz ist. SteganographyCapacity::minimumTextLength ist die Umkehrung: die kleinste UTF-8-Zeichenanzahl, die eine Payload der angeforderten Größe zulässt.

  • Eine leere $payload gibt aus encode eine leere Map zurück; es werden keine Bytes geschrieben, und die Schlüsselstärke-Absicherung wird nicht erreicht.
  • Für eine nicht-leere Payload löst ein $text mit weniger als zwei Zeichen in encode eine OverflowException aus (eine leere Payload wird vor der Längenprüfung zu [] kurzgeschlossen); derselbe Text liefert null in decode und null in SteganographyCapacity::calculate.
  • Eine $payload, die größer als die Textkapazität ist, löst eine OverflowException aus, bevor irgendeine Anpassung emittiert wird.
  • Ein $secretKey, der kürzer als MIN_SECRET_KEY_LENGTH (16 Bytes) ist, löst sowohl auf dem Schreib- als auch auf dem Lesepfad eine InvalidArgumentException aus. Dies ist eine Vertragsverletzung, unterschieden von einem normalen Falscher-Schlüssel-Fehlschlag.
  • Ein falscher Schlüssel, ein beschädigter Anpassungssatz oder ein abgeschnittener Blob lässt decode durch AEAD-Authentifizierungsfehler null zurückgeben, nicht eine Ausnahme.
  • Positionen, die in einer dünn besetzten $observedAdjustments-Map fehlen, werden während der Extraktion als Nullabweichung behandelt.
  • decodeFromContentStream gibt null zurück, wenn der Stream keinen TJ-Text enthält.
  • Der Kanal ist bewusst fragil. Drucken-dann-Scannen, PDF-Konvertierung, Re-Linearisierung, Umschreiben des Content-Streams oder Kerning-Normalisierung können die kodierten Daten zerstören. Er ist für den adversarialen oder archivarischen Einsatz ungeeignet.

Der Kanal verwendet HKDF-SHA-256 zur Schlüsselableitung und eine AEAD-Chiffre für Vertraulichkeit und Integrität. NextPDF besitzt für diesen Kanal keine FIPS-Validierung und behauptet keine. Das Modul erzwingt kein FIPS-Profil; die Chiffrenauswahl ist die Entscheidung des Aufrufers über $config->cipher. aes-256-gcm ist AES im Galois/Counter-Modus, ein Authenticated-Encryption-Modus, der auf einer zugelassenen 128-Bit-Blockchiffre aufbaut, deren Konformität unter dem CMVP validiert wird, gemäß NIST SP 800-38D §2. chacha20-poly1305 ist nicht durch eine NIST-Betriebsmodus-Empfehlung definiert, sodass ein FIPS-beschränkter OpenSSL-Provider es zurückweist; openssl_encrypt gibt dann false zurück und der Encoder löst eine SteganographyEncryptionException aus. Ob eine Bereitstellung eine FIPS-Anforderung erfüllt, ist die Feststellung des Betreibers gegenüber seinem validierten Provider, keine Zusicherung von NextPDF.

Die Einbettung schreibt numerische Elemente in ein TJ-Textausgabe-Array. Gemäß ISO 32000-2:2020 §9.4.3 zeigt ein TJ-Array Text an und lässt ein numerisches Element die Glyphenposition anpassen; die Zahl wird in Tausendsteln einer Textraum-Einheit ausgedrückt und von der aktuellen Position subtrahiert. Nachdem eine Glyphe gezeichnet wurde, wird die Textmatrix um die kombinierte Verschiebung verschoben, sodass eine Positionierungszahl die Platzierung nachfolgender Glyphen verschiebt — ISO 32000-2:2020 §9.4.4. Der Kanal addiert seine Offsets zu den natürlichen Kern-Werten in derselben 1/1000-em-(AFM-)Konvention, bei der ein negativer Wert den Abstand verengt.

Die AEAD-Grundlage beschränkt sich auf die Primitivauswahl: aes-256-gcm entspricht dem GCM-Modus von NIST SP 800-38D §2. Diese Referenz benennt einen Algorithmus; sie ist keine Validierung dieses Kanals.

Alle Klauseln sind paraphrasiert; NextPDF reproduziert keinen normativen Text. NextPDF erhebt für diesen Kanal keinen Steganographie-, Kryptographie- oder PDF-Konformitätsanspruch. Die strukturelle Ausrichtung am TJ-Positionierungsmodell ist eine Fähigkeitsaussage, keine Zertifizierung. Die Robustheitsangabe bleibt bestehen: Der Kanal dient der internen Leck-Rückverfolgung und ist nicht von Angreiferqualität.

  • Einstiegspunkte sind public static-Methoden in NextPDF\Enterprise\Security\Steganography, mit Ausnahme des SteganographyConfig-Konstruktors und effectiveMaxOffset.
  • SteganographyConfig ist ein final readonly-Value-Object. Seine vier Eigenschaften sind nach der Konstruktion unveränderlich, und ihre Argumentdomänen werden im Konstruktor validiert: $bitDepth ist 1 oder 2, $maxAdjustmentEmRatio liegt in (0, 0.05], und $cipher ist aes-256-gcm oder chacha20-poly1305.
  • Die Ausgabe von encode wird von NextPDF\Content\TextRenderer::buildTjArrayOperator konsumiert. Kern-Paare stammen aus NextPDF\Typography\FontMetrics. Die Content-Stream-Dekodierung liest über NextPDF\Pro\Projection\ContentProjectionWriter und mutiert den Stream nicht.
  • Der Mindestwert der Schlüssellänge wird am Einstiegspunkt erzwungen und an der privaten Krypto-Grenze erneut geprüft, sodass kein interner Pfad HKDF mit einem schwachen Schlüssel erreichen kann. Die Bibliothek erzwingt Länge, nicht Entropie; die Bereitstellung von Schlüsselmaterial mit hoher Entropie liegt in der Verantwortung des Integrators.
  • CRYPTO_OVERHEAD (32 Bytes) ist die feste Kosten pro Payload und wird bereits von SteganographyCapacity::calculate abgezogen.
  • Das dokumentierte since ist 3.1.0 für die aggregierte Enterprise-Oberfläche. SteganographyEncryptionException erweitert RuntimeException, sodass Aufrufstellen, die den generischen Runtime-Typ abfangen, weiterhin funktionieren.

Diese Seite dokumentiert ausschließlich das extern beobachtbare 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 Geltungsbereichs.