Przejdź do głównej zawartości
getnextpdf.com

Enterprise edycja

Steganografia — szczegółowa referencja

Ta szczegółowa dokumentacja referencyjna opisuje steganograficzny kanał NextPDF Enterprise. Kanał ukrywa zaszyfrowany ładunek wewnątrz numerycznych korekt kerningu tablicy tekstowej TJ. Udostępnia cztery publiczne symbole: SteganographyEncoder, SteganographyDecoder, SteganographyConfig oraz SteganographyCapacity. Koder wyprowadza klucz za pomocą HKDF-SHA-256, szyfruje ładunek szyfrem AEAD i zwraca przesunięcia kerningu dla poszczególnych pozycji. Dekoder odwraca ten proces na podstawie zaobserwowanych korekt lub surowego strumienia treści.

Kanał zaprojektowano do wewnętrznego śledzenia wycieków dokumentów. Nie jest to steganografia klasy odpornej na przeciwnika. Zakodowane dane mogą zostać zniszczone przez wydruk i skan, konwersję PDF, ponowną linearyzację, przepisanie strumienia treści lub dowolną operację normalizującą kerning. NextPDF nie posiada żadnej certyfikacji dla tego kanału ani jej nie udziela. Ta strona opisuje możliwości, a nie zgodność.

Ta funkcja jest dostarczana w NextPDF Enterprise (nextpdf/enterprise) i aktywuje się przy użyciu koperty licencyjnej poziomu Enterprise. Wdrożenie bez tego uprawnienia nie ładuje klas tej funkcji. Porównaj edycje i uzyskaj licencję.

Kanał udostępnia cztery klasy final. Wszystkie punkty wejścia są public static, z wyjątkiem konstruktora SteganographyConfig oraz jego akcesora effectiveMaxOffset. Pomocniczy typ NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException jest zgłaszany przez koder; nie jest typem konstruowanym przez wywołującego.

SymbolParametryDomyślne zachowanieZwracaZgłasza lub kończy się błędemUwagi
SteganographyEncoder::encode$payload, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Puste $payload zwraca []; weryfikuje siłę klucza; szyfruje; oblicza przesunięcia kerningu dla poszczególnych pozycji.array<int, float> (pozycja => korekta w 1/1000 em, konwencja AFM)InvalidArgumentException (klucz poniżej progu); OverflowException (tekst krótszy niż 2 znaki lub ładunek przekracza pojemność); SteganographyEncryptionException (błąd AEAD)Wynik przekaż do NextPDF\Content\TextRenderer::buildTjArrayOperator(). API zwraca korekty w konwencji AFM; buildTjArrayOperator() wykonuje numeryczną konwersję PDF TJ (ISO 32000-2 odejmuje liczbę od bieżącej pozycji). Ręczne zapisywanie strumienia treści musi zachować tę konwencję znaku.
SteganographyEncoder::assertSecretKeyStrength$secretKeyOdrzuca klucz krótszy niż próg.voidInvalidArgumentException (klucz poniżej progu)Wspólne zabezpieczenie ścieżki zapisu, odzwierciedlone na ścieżce odczytu.
SteganographyEncoder::MIN_SECRET_KEY_LENGTHstałaPróg długości klucza 128-bitowego wyrażony w bajtach.int (16)Nie dotyczyBiblioteka wymusza długość, a nie entropię.
SteganographyDecoder::decode$observedAdjustments, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Weryfikuje siłę klucza; kwantyzuje odchylenia; odtwarza blob; deszyfruje AEAD.`stringnull(ładunek lubnull` przy błędnym kluczu albo braku ładunku)InvalidArgumentException (klucz poniżej progu)
SteganographyDecoder::decodeFromContentStream$contentStream, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Tokenizuje strumień, rekonstruuje tekst i korekty z tablic TJ, a następnie deleguje do decode.`stringnull(ładunek lubnull, gdy brak tekstu TJ` albo deszyfrowanie się nie powiedzie)InvalidArgumentException (klucz poniżej progu, przez decode)
SteganographyConfig::__construct$bitDepth, $maxAdjustmentEmRatio, $cipher, $requirePdfACompatibilityWaliduje dziedzinę każdego argumentu; tworzy niezmienny obiekt wartości.Instancja SteganographyConfigInvalidArgumentException (nieprawidłowe $bitDepth, $maxAdjustmentEmRatio lub $cipher)Klasa readonly; cztery argumenty to publiczne właściwości promowane.
SteganographyConfig::effectiveMaxOffsetbrakZwraca $maxAdjustmentEmRatio * 1000, zmniejszone o połowę, gdy wymagana jest zgodność z PDF/A.float (przesunięcie w 1/1000 em)Nie dotyczyZmniejszenie o połowę ogranicza ryzyko wykrycia niezgodności szerokości.
SteganographyConfig::CRYPTO_OVERHEADstałaStały narzut szyfrowania na ładunek wyrażony w bajtach.int (32)Nie dotyczy4-bajtowa długość, 12-bajtowy nonce, 16-bajtowy tag.
SteganographyCapacity::calculate$text, $config (SteganographyConfig)Oblicza użyteczne bajty ładunku dla tekstu po odjęciu narzutu.int (0, gdy tekst jest zbyt krótki)Nie dotyczyPojemność to positions * bitDepth / 8 minus narzut.
SteganographyCapacity::minimumTextLength$payloadBytes, $config (SteganographyConfig)Oblicza minimalną liczbę znaków UTF-8 dla ładunku.int (liczba znaków)Nie dotyczyOdwrotność calculate.

Poniżej znajdują się dosłowne sygnatury, każda z pochodzeniem ze źródła.

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

Koder dzieli $text na znaki UTF-8 i tworzy jedną pozycję dla każdej pary kolejnych znaków. Każda pozycja przenosi $config->bitDepth bitów, czyli jeden lub dwa. Ładunek jest najpierw szyfrowany, następnie serializowany do bloba, a potem konwertowany na sekwencję bitów. Każda pozycja koduje swoje bity jako małe nieujemne przesunięcie dodane do naturalnej wartości kerningu dla tej pary znaków.

Przesunięcie jest ułamkiem efektywnego maksymalnego przesunięcia. Efektywne maksymalne przesunięcie to $maxAdjustmentEmRatio * 1000 jednostek projektowych, zmniejszone o połowę, gdy $requirePdfACompatibility ma wartość true. Naturalny kerning odczytywany jest z $metrics przez FontMetrics::getKernPair. Zwracana mapa jest rzadka: pozycja, której ostateczna korekta wynosi dokładnie zero, zostaje pominięta.

Szyfrowanie wykorzystuje HKDF-SHA-256 do wyprowadzenia 32-bajtowego klucza. Solą HKDF jest niesekretny $fontKey, a etykietą info jest stała wartość. Dlatego $secretKey wywołującego stanowi jedyną granicę poufności. Szyfrem AEAD jest aes-256-gcm lub chacha20-poly1305, wybierany przez $config->cipher, uruchamiany przez openssl_encrypt ze świeżym 12-bajtowym nonce i 16-bajtowym tagiem. Serializowany blob to 4-bajtowa długość big-endian, 12-bajtowy nonce, szyfrogram i 16-bajtowy tag; ten stały narzut to CRYPTO_OVERHEAD, czyli 32 bajty.

Dekoder odwraca tę transformację. Oblicza odchylenie każdej zaobserwowanej korekty od naturalnego kerningu, normalizuje je względem efektywnego maksymalnego przesunięcia i kwantyzuje do najbliższego poziomu. Odtwarza blob, waliduje nagłówek długości i wywołuje openssl_decrypt. Błędny klucz, brakujący ładunek lub uszkodzone korekty powodują niepowodzenie uwierzytelnienia AEAD, a dekoder zwraca null. decodeFromContentStream najpierw tokenizuje surowy strumień za pomocą NextPDF\Pro\Projection\ContentProjectionWriter::tokenize, rekonstruuje tekst i numeryczne korekty z każdej tablicy TJ, a następnie deleguje do decode.

SteganographyCapacity::calculate podaje użyteczny rozmiar ładunku dla tekstu i konfiguracji po odjęciu CRYPTO_OVERHEAD; zwraca zero, gdy tekst jest zbyt krótki. SteganographyCapacity::minimumTextLength jest odwrotnością: najmniejszą liczbą znaków UTF-8, która dopuszcza ładunek o żądanym rozmiarze.

  • Puste $payload zwraca pustą mapę z encode; żadne bajty nie są zapisywane, a zabezpieczenie siły klucza nie zostaje osiągnięte.
  • Dla niepustego ładunku $text zawierający mniej niż dwa znaki wywołuje OverflowException w encode (pusty ładunek zwraca [] przed sprawdzeniem długości); ten sam tekst daje null w decode i zero w SteganographyCapacity::calculate.
  • $payload większy niż pojemność tekstu wywołuje OverflowException przed wyemitowaniem jakiejkolwiek korekty.
  • $secretKey krótszy niż MIN_SECRET_KEY_LENGTH (16 bajtów) wywołuje InvalidArgumentException zarówno na ścieżce zapisu, jak i odczytu. Jest to naruszenie kontraktu, odrębne od zwykłego chybienia z powodu błędnego klucza.
  • Błędny klucz, uszkodzony zestaw korekt lub obcięty blob powoduje, że decode zwraca null na skutek niepowodzenia uwierzytelnienia AEAD, a nie wyjątku.
  • Pozycje nieobecne w rzadkiej mapie $observedAdjustments są podczas ekstrakcji traktowane jako zerowe odchylenie.
  • decodeFromContentStream zwraca null, gdy strumień nie zawiera tekstu TJ.
  • Kanał jest z założenia kruchy. Wydruk i skan, konwersja PDF, ponowna linearyzacja, przepisanie strumienia treści lub normalizacja kerningu mogą zniszczyć zakodowane dane. Nie nadaje się do zastosowań w warunkach przeciwnika ani archiwalnych.

Kanał używa HKDF-SHA-256 do wyprowadzania klucza oraz jednego szyfru AEAD dla poufności i integralności. NextPDF nie posiada walidacji FIPS dla tego kanału ani jej nie deklaruje. Moduł nie wymusza profilu FIPS; wybór szyfru jest decyzją wywołującego przez $config->cipher. aes-256-gcm to AES w trybie Galois/Counter Mode, tryb szyfrowania uwierzytelnionego oparty na zatwierdzonym 128-bitowym szyfrze blokowym, którego zgodność jest walidowana w ramach CMVP, zgodnie z NIST SP 800-38D §2. chacha20-poly1305 nie jest zdefiniowany przez rekomendację trybu działania NIST, dlatego dostawca OpenSSL ograniczony do FIPS go odrzuca; openssl_encrypt zwraca wówczas false, a koder zgłasza SteganographyEncryptionException. To, czy dane wdrożenie spełnia wymóg FIPS, jest ustaleniem operatora względem jego walidowanego dostawcy, a nie stwierdzeniem NextPDF.

Osadzanie zapisuje elementy numeryczne w tablicy tekstowej TJ. Zgodnie z ISO 32000-2:2020 §9.4.3 tablica TJ pokazuje tekst i pozwala elementowi numerycznemu skorygować pozycję glifu; liczba wyrażana jest w tysięcznych jednostki przestrzeni tekstowej i jest odejmowana od bieżącej pozycji. Po namalowaniu glifu macierz tekstu przesuwa się o złożone przemieszczenie, dlatego liczba pozycjonująca zmienia umiejscowienie kolejnych glifów — ISO 32000-2:2020 §9.4.4. Kanał dodaje swoje przesunięcia do naturalnych wartości kerningu w tej samej konwencji 1/1000 em (AFM), w której wartość ujemna zacieśnia odstępy.

Podstawa AEAD ogranicza się do wyboru prymitywu: aes-256-gcm odpowiada trybowi GCM z NIST SP 800-38D §2. Odniesienie to identyfikuje algorytm; nie jest walidacją tego kanału.

Wszystkie klauzule są parafrazowane; NextPDF nie odtwarza tekstu normatywnego. NextPDF nie formułuje żadnego oświadczenia o zgodności w zakresie steganografii, kryptografii ani PDF dla tego kanału. Strukturalna zgodność z modelem pozycjonowania TJ jest stwierdzeniem możliwości, a nie certyfikacją. Zastrzeżenie dotyczące odporności pozostaje w mocy: kanał służy do wewnętrznego śledzenia wycieków i nie jest klasy odpornej na przeciwnika.

  • Punkty wejścia to metody public static w NextPDF\Enterprise\Security\Steganography, z wyjątkiem konstruktora SteganographyConfig i effectiveMaxOffset.
  • SteganographyConfig to obiekt wartości final readonly. Jego cztery właściwości są niezmienne po konstrukcji, a dziedziny argumentów są walidowane w konstruktorze: $bitDepth wynosi 1 lub 2, $maxAdjustmentEmRatio mieści się w (0, 0.05], a $cipher to aes-256-gcm lub chacha20-poly1305.
  • Wynik kodowania jest wykorzystywany przez NextPDF\Content\TextRenderer::buildTjArrayOperator. Pary kerningu pochodzą z NextPDF\Typography\FontMetrics. Dekodowanie strumienia treści odczytuje dane przez NextPDF\Pro\Projection\ContentProjectionWriter i nie modyfikuje strumienia.
  • Próg długości klucza jest wymuszany w punkcie wejścia i ponownie weryfikowany na prywatnej granicy kryptograficznej, dzięki czemu żadna wewnętrzna ścieżka nie może dotrzeć do HKDF ze słabym kluczem. Biblioteka wymusza długość, a nie entropię; dostarczenie materiału klucza o wysokiej entropii jest odpowiedzialnością integratora.
  • CRYPTO_OVERHEAD (32 bajty) to stały koszt na ładunek i jest już odejmowany przez SteganographyCapacity::calculate.
  • Udokumentowana wartość since to 3.1.0 dla zagregowanej powierzchni Enterprise. SteganographyEncryptionException rozszerza RuntimeException, dlatego miejsca wywołań przechwytujące ogólny typ runtime nadal działają.

Ta strona dokumentuje wyłącznie zachowanie obserwowalne z zewnątrz oraz wspieraną publiczną powierzchnię API. Wewnętrzne ścieżki przestrzeni nazw, klasy pomocnicze, tabele mechanizmów, nazwy plików runbooków i prefiksy zgłoszeń są poza zakresem.