Ga naar inhoud
getnextpdf.com

Enterprise editie

Steganografie — Diepe referentie

Deze diepgaande referentie documenteert het NextPDF Enterprise steganografische kanaal. Het kanaal verbergt een versleutelde payload in de numerieke kerningaanpassingen van een TJ-tekstweergavearray. Het heeft vier publieke symbolen: SteganographyEncoder, SteganographyDecoder, SteganographyConfig en SteganographyCapacity. De encoder leidt een sleutel af met HKDF-SHA-256, versleutelt de payload met een AEAD-cipher en geeft kernoffsets per positie terug. De decoder keert het proces om vanuit waargenomen aanpassingen of vanuit een ruwe content-stream.

Het kanaal is ontworpen voor het traceren van interne documentlekken. Het is geen steganografie op adversarieel niveau. Gecodeerde data kan vernietigd worden door print-then-scan, PDF-conversie, herlinearisatie, het herschrijven van de content-stream, of elke bewerking die kerning normaliseert. NextPDF houdt geen certificering voor dit kanaal en verleent er geen. Deze pagina beschrijft capaciteit, geen conformiteit.

Deze mogelijkheid wordt geleverd in NextPDF Enterprise (nextpdf/enterprise) en wordt geactiveerd met een licentie-envelop op Enterprise-niveau. Een deployment zonder die entitlement laadt de klassen van deze mogelijkheid niet. Vergelijk edities en verkrijg een licentie.

Het kanaal stelt vier final classes beschikbaar. Alle entry points zijn public static, behalve de constructor van SteganographyConfig en zijn effectiveMaxOffset-accessor. De ondersteunende NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException wordt geworpen door de encoder; het is geen door de aanroeper geconstrueerd type.

SymboolParametersStandaardgedragRetourneertWerpt of faalt metOpmerkingen
SteganographyEncoder::encode$payload, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Lege $payload retourneert []; controleert sleutelsterkte; versleutelt; berekent kernoffsets per positie.array<int, float> (positie => aanpassing in 1/1000 em, AFM-conventie)InvalidArgumentException (sleutel onder de ondergrens); OverflowException (tekst onder 2 tekens, of payload boven capaciteit); SteganographyEncryptionException (AEAD-fout)Geef het resultaat door aan NextPDF\Content\TextRenderer::buildTjArrayOperator(). De API retourneert aanpassingen volgens AFM-conventie; buildTjArrayOperator() voert de PDF TJ-numerieke conversie uit (ISO 32000-2 trekt het getal af van de huidige positie). Wie handmatig content-streams schrijft, moet die tekenconventie behouden.
SteganographyEncoder::assertSecretKeyStrength$secretKeyWeigert een sleutel korter dan de ondergrens.voidInvalidArgumentException (sleutel onder de ondergrens)Gedeelde write-path-guard, gespiegeld op het read-path.
SteganographyEncoder::MIN_SECRET_KEY_LENGTHconstantDe 128-bits sleutellengte-ondergrens in bytes.int (16)Niet van toepassingDe library dwingt lengte af, geen entropie.
SteganographyDecoder::decode$observedAdjustments, $text, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Controleert sleutelsterkte; kwantiseert afwijkingen; herbouwt de blob; AEAD-ontsleutelt.`stringnull(payload, ofnull` bij verkeerde sleutel of geen payload)InvalidArgumentException (sleutel onder de ondergrens)
SteganographyDecoder::decodeFromContentStream$contentStream, $fontKey, $metrics (FontMetrics), $secretKey, $config (SteganographyConfig)Tokeniseert de stream, reconstrueert tekst en aanpassingen uit TJ-arrays, en delegeert dan naar decode.`stringnull(payload, ofnullwanneer er geenTJ`-tekst is of ontsleuteling faalt)InvalidArgumentException (sleutel onder de ondergrens, via decode)
SteganographyConfig::__construct$bitDepth, $maxAdjustmentEmRatio, $cipher, $requirePdfACompatibilityValideert het domein van elk argument; produceert een immutable value object.SteganographyConfig-instantieInvalidArgumentException (ongeldige $bitDepth, $maxAdjustmentEmRatio of $cipher)readonly class; de vier argumenten zijn publiek gepromote properties.
SteganographyConfig::effectiveMaxOffsetgeenRetourneert $maxAdjustmentEmRatio * 1000, gehalveerd wanneer PDF/A-compatibiliteit gevraagd wordt.float (offset in 1/1000 em)Niet van toepassingHet halveren verlaagt het risico op detectie van breedtemismatch.
SteganographyConfig::CRYPTO_OVERHEADconstantDe vaste encryptie-overhead per payload in bytes.int (32)Niet van toepassing4-byte lengte, 12-byte nonce, 16-byte tag.
SteganographyCapacity::calculate$text, $config (SteganographyConfig)Berekent bruikbare payload-bytes voor de tekst, na overhead.int (0 wanneer de tekst te kort is)Niet van toepassingCapaciteit is positions * bitDepth / 8 minus overhead.
SteganographyCapacity::minimumTextLength$payloadBytes, $config (SteganographyConfig)Berekent het minimum aantal UTF-8-tekens voor een payload.int (aantal tekens)Niet van toepassingInverse van calculate.

De verbatim signatures volgen, elk met bronvermelding.

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

De encoder splitst $text op in UTF-8-tekens en vormt één positie per opeenvolgend tekenpaar. Elke positie draagt $config->bitDepth bits, wat één of twee is. De payload wordt eerst versleuteld, dan geserialiseerd naar een blob, en dan omgezet naar een bitsequentie. Elke positie codeert zijn bits als een kleine niet-negatieve offset die opgeteld wordt bij de natuurlijke kernwaarde voor dat tekenpaar.

De offset is een fractie van de effectieve maximale offset. De effectieve maximale offset is $maxAdjustmentEmRatio * 1000 design units, gehalveerd wanneer $requirePdfACompatibility waar is. De natuurlijke kern wordt uit $metrics gelezen via FontMetrics::getKernPair. De geretourneerde map is spaarzaam: een positie waarvan de uiteindelijke aanpassing exact nul is, wordt weggelaten.

Encryptie gebruikt HKDF-SHA-256 om een 32-byte sleutel af te leiden. De HKDF-salt is de niet-geheime $fontKey en het info-label is een vaste constante. Daarom is de $secretKey van de aanroeper de enige vertrouwelijkheidsgrens. De AEAD-cipher is aes-256-gcm of chacha20-poly1305, geselecteerd door $config->cipher, uitgevoerd via openssl_encrypt met een verse 12-byte nonce en een 16-byte tag. De geserialiseerde blob is een 4-byte big-endian lengte, de 12-byte nonce, de ciphertext en de 16-byte tag; deze vaste overhead is CRYPTO_OVERHEAD, wat 32 bytes is.

De decoder keert de transformatie om. Hij berekent de afwijking van elke waargenomen aanpassing ten opzichte van de natuurlijke kern, normaliseert met de effectieve maximale offset en kwantiseert naar het dichtstbijzijnde niveau. Hij zet de blob weer samen, valideert de lengte-header en roept openssl_decrypt aan. Een verkeerde sleutel, een ontbrekende payload of beschadigde aanpassingen laten de AEAD-authenticatie falen, en de decoder retourneert null. decodeFromContentStream tokeniseert eerst de ruwe stream met NextPDF\Pro\Projection\ContentProjectionWriter::tokenize, reconstrueert de tekst en de numerieke aanpassingen uit elke TJ-array, en delegeert dan naar decode.

SteganographyCapacity::calculate rapporteert de bruikbare payload-grootte voor een tekst en configuratie, na aftrek van CRYPTO_OVERHEAD; het retourneert nul wanneer de tekst te kort is. SteganographyCapacity::minimumTextLength is de inverse: het kleinste aantal UTF-8-tekens dat een payload van de gevraagde grootte toelaat.

  • Een lege $payload retourneert een lege map uit encode; er worden geen bytes geschreven, en de sleutelsterkte-guard wordt niet bereikt.
  • Voor een niet-lege payload werpt een $text met minder dan twee tekens OverflowException in encode (een lege payload short-circuit naar [] vóór de lengtecontrole); dezelfde tekst levert null op in decode en nul in SteganographyCapacity::calculate.
  • Een $payload groter dan de tekstcapaciteit werpt OverflowException voordat er ook maar één aanpassing wordt uitgegeven.
  • Een $secretKey korter dan MIN_SECRET_KEY_LENGTH (16 bytes) werpt InvalidArgumentException op zowel het write- als het read-path. Dit is een contractschending, verschillend van een normale verkeerde-sleutel-misser.
  • Een verkeerde sleutel, een beschadigde aanpassingsset of een afgekapte blob laat decode null retourneren via een AEAD-authenticatiefout, geen exception.
  • Posities die afwezig zijn in een spaarzame $observedAdjustments-map worden bij extractie behandeld als een nul-afwijking.
  • decodeFromContentStream retourneert null wanneer de stream geen TJ-tekst bevat.
  • Het kanaal is broos van ontwerp. Print-then-scan, PDF-conversie, herlinearisatie, het herschrijven van de content-stream of kerningnormalisatie kunnen de gecodeerde data vernietigen. Het is ongeschikt voor adversarieel of archiefgebruik.

Het kanaal gebruikt HKDF-SHA-256 voor sleutelafleiding en één AEAD-cipher voor vertrouwelijkheid en integriteit. NextPDF houdt geen FIPS-validatie voor dit kanaal en claimt er geen. De module dwingt geen FIPS-profiel af; cipherselectie is de beslissing van de aanroeper via $config->cipher. aes-256-gcm is AES in Galois/Counter Mode, een authenticated-encryption-modus gebouwd op een goedgekeurde 128-bits block cipher waarvan de conformiteit gevalideerd wordt onder de CMVP, volgens NIST SP 800-38D §2. chacha20-poly1305 is niet gedefinieerd door een NIST mode-of-operation-aanbeveling, dus een FIPS-beperkte OpenSSL-provider weigert het; openssl_encrypt retourneert dan false en de encoder werpt SteganographyEncryptionException. Of een deployment aan een FIPS-vereiste voldoet, is de vaststelling van de operator tegen zijn gevalideerde provider, geen bewering van NextPDF.

De embedding schrijft numerieke elementen in een TJ-tekstweergavearray. Volgens ISO 32000-2:2020 §9.4.3 toont een TJ-array tekst en laat een numeriek element de glyphpositie aanpassen; het getal wordt uitgedrukt in duizendsten van een text-space unit en wordt afgetrokken van de huidige positie. Nadat een glyph is getekend, wordt de tekstmatrix verschoven met de gecombineerde verplaatsing, zodat een positioneringsgetal de plaatsing van volgende glyphs verschuift — ISO 32000-2:2020 §9.4.4. Het kanaal telt zijn offsets op bij de natuurlijke kernwaarden in dezelfde 1/1000 em (AFM)-conventie, waarbij een negatieve waarde de spatiëring verkleint.

De AEAD-grondslag is beperkt tot primitiefselectie: aes-256-gcm komt overeen met de GCM-modus van NIST SP 800-38D §2. Die referentie identificeert een algoritme; het is geen validatie van dit kanaal.

Alle clauses zijn geparafraseerd; NextPDF reproduceert geen normatieve tekst. NextPDF maakt geen steganografie-, cryptografie- of PDF-conformiteitsclaim voor dit kanaal. Structurele afstemming met het TJ-positioneringsmodel is een capaciteitsverklaring, geen certificering. De robuustheidsdisclosure blijft staan: het kanaal is bedoeld voor het traceren van interne lekken, en het is niet van adversarieel niveau.

  • Entry points zijn public static-methoden in NextPDF\Enterprise\Security\Steganography, behalve de constructor van SteganographyConfig en effectiveMaxOffset.
  • SteganographyConfig is een final readonly value object. Zijn vier properties zijn immutable na constructie, en hun argumentdomeinen worden gevalideerd in de constructor: $bitDepth is 1 of 2, $maxAdjustmentEmRatio ligt in (0, 0.05], en $cipher is aes-256-gcm of chacha20-poly1305.
  • De encode-output wordt geconsumeerd door NextPDF\Content\TextRenderer::buildTjArrayOperator. Kernparen komen van NextPDF\Typography\FontMetrics. Content-stream-decodering leest via NextPDF\Pro\Projection\ContentProjectionWriter en muteert de stream niet.
  • De sleutellengte-ondergrens wordt afgedwongen op het entry point en opnieuw geverifieerd op de private crypto-grens, zodat geen enkel intern path HKDF met een zwakke sleutel kan bereiken. De library dwingt lengte af, geen entropie; het aanleveren van sleutelmateriaal met hoge entropie is de verantwoordelijkheid van de integrator.
  • CRYPTO_OVERHEAD (32 bytes) is de vaste kost per payload en wordt al afgetrokken door SteganographyCapacity::calculate.
  • De gedocumenteerde since is 3.1.0 voor het geaggregeerde Enterprise-oppervlak. SteganographyEncryptionException breidt RuntimeException uit, dus aanroepplekken die het generieke runtime-type opvangen blijven werken.

Deze pagina documenteert alleen extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helper classes, mechanisme-tabellen, runbook-bestandsnamen en ticketprefixen vallen buiten scope.