Salta ai contenuti
getnextpdf.com

Enterprise edizione

Filigrana digitale e incorporamento steganografico

NextPDF Enterprise incorpora un payload nascosto e cifrato in un PDF generato apportando piccoli aggiustamenti controllati alla spaziatura tra coppie di lettere. L’utente fornisce un payload — tipicamente un identificatore per ciascun destinatario — e una chiave segreta; l’encoder scrive il payload come deviazioni impercettibili dalla crenatura naturale del testo. Un decoder corrispondente, data la stessa chiave, recupera il payload. Questa pagina è a livello di comportamento: indica ciò che l’encoder scrive, la crittografia che usa e il confine della tecnica.

L’uso previsto è il tracciamento interno delle fughe di documenti: quando un documento controllato viene divulgato, il marcatore recuperato identifica la copia del destinatario. Non è steganografia avversariale e non garantisce la sopravvivenza attraverso un’elaborazione arbitraria.

I prerequisiti sono indicati nel front matter e ripetuti sotto Prerequisiti.

Questa capacità è inclusa in NextPDF Enterprise (nextpdf/enterprise) e si attiva con un envelope di licenza di livello Enterprise. Un deployment privo di tale titolo non carica le classi della capacità. La capacità viene eseguita interamente in-process durante la generazione del documento; nessun contenuto del documento lascia l’host. Confronta le edizioni e ottieni una licenza.

Il testo PDF disegnato con un array di crenatura trasporta un aggiustamento numerico tra i glifi. L’encoder tratta ogni posizione di aggiustamento come un carrier per alcuni bit:

  1. Cifra il payload con un cifrario di cifratura autenticata con dati associati (AEAD) — AES-256-GCM per impostazione predefinita, o ChaCha20-Poly1305. AEAD fornisce sia confidenzialità sia integrità, così che un carrier manomesso fallisca la decifratura anziché restituire silenziosamente un payload errato.
  2. Deriva la chiave di cifratura da 32 byte dalla chiave segreta e dalla chiave del font usando la funzione di derivazione delle chiavi basata su HMAC (HKDF) con SHA-256. HKDF estrae una chiave pseudocasuale di lunghezza fissa dal materiale di keying in ingresso, quindi la espande alla lunghezza richiesta, secondo RFC 5869 §2.
  3. Genera un nuovo vettore di inizializzazione (IV) casuale da 12 byte per ogni cifratura. AES-GCM richiede che l’IV sia univoco per una data chiave, altrimenti la garanzia di autenticazione viene persa, secondo NIST SP 800-38D §5.2.1.
  4. Mappa i byte cifrati su una sequenza di bit e distribuisce i bit sulle posizioni di coppia di lettere disponibili, codificando uno o due bit per posizione. La deviazione che aggiunge alla crenatura naturale è limitata da una frazione configurabile dell’em — abbastanza piccola da restare visivamente impercettibile.

Il decoder inverte il processo: legge gli aggiustamenti di crenatura da un content stream, sottrae la crenatura naturale, quantizza le deviazioni nuovamente in bit, riassembla il blob cifrato e lo decifra con la stessa chiave. Se la chiave è errata o il carrier è stato distrutto, la decifratura non restituisce nulla anziché un payload errato.

La capacità scala con la lunghezza del testo: ogni posizione di coppia di lettere trasporta uno o due bit, quindi un payload deve entrare nelle posizioni che il testo fornisce. L’encoder solleva un errore di overflow tipizzato quando il payload eccede la capacità.

Una modalità di compatibilità PDF/A dimezza la deviazione massima per restare sotto la soglia di tolleranza di larghezza di un validatore, scambiando capacità per una conformità più rigorosa.

La scelta portante è nascondere il marcatore nella crenatura anziché in un overlay visibile o in un campo di metadati. Un marcatore nei metadati è banale da rimuovere, e un timbro visibile altera la pagina. Le deviazioni di crenatura invece viaggiano dentro il testo che il destinatario deve conservare, e restano impercettibili. La cifratura autenticata è il secondo pilastro: un carrier manomesso o parziale fallisce l’autenticazione, così il decoder non restituisce nulla anziché un destinatario errato. La chiave è derivata per font con HKDF, legando il marcatore al contesto del documento, non a un mero segreto condiviso. La divulgazione onesta sulla robustezza ne consegue direttamente: il marcatore sopravvive alla redistribuzione ordinaria ma non alla riscrittura deliberata del content stream, quindi l’ambito dichiarato è il tracciamento interno delle fughe, non la steganografia avversariale.

Contesto di progettazione: La redazione non è un rettangolo nero.

  1. Installare NextPDF Core e il pacchetto Enterprise, e disporre di una licenza Enterprise attiva.
  2. Generare il documento con un font che espone le metriche delle coppie di crenatura; l’encoder legge la crenatura naturale dalle metriche del font.
  3. Fornire la chiave segreta dal proprio secret manager, non dal sorgente. La stessa chiave è richiesta per la decodifica.
  4. Decidere la profondità di bit (uno o due bit per posizione) e se è richiesta la compatibilità PDF/A, in base alle proprie esigenze di capacità e conformità.

La configurazione di codifica è immutabile e validata alla costruzione:

  • Profondità di bit — uno o due bit per posizione di coppia di lettere. Una profondità maggiore offre più capacità ma deviazioni più grandi.
  • Rapporto di aggiustamento massimo — il tetto della deviazione come frazione dell’em, entro un intervallo limitato. Valori più grandi offrono più margine ma rischiano la visibilità.
  • Cifrario — AES-256-GCM (predefinito) o ChaCha20-Poly1305. Entrambi sono AEAD.
  • Compatibilità PDF/A — quando abilitata, dimezza la deviazione massima effettiva.

Usare la stessa configurazione per la codifica e la decodifica; una mancata corrispondenza non recupera alcun payload.

  1. Leggere la chiave segreta dal proprio secret manager.
  2. Costruire la configurazione di codifica (profondità di bit, rapporto di deviazione, cifrario, flag PDF/A).
  3. Calcolare gli aggiustamenti di crenatura per il testo che si sta per renderizzare, passando il payload, il testo, la chiave del font, le metriche del font, la chiave segreta e la configurazione.
  4. Applicare gli aggiustamenti restituiti quando si scrive il run di testo, così che il marcatore venga incorporato durante la generazione.
  5. Per tracciare una copia divulgata, eseguire il decoder sul content stream del documento sospetto con la stessa chiave del font, le stesse metriche del font, la stessa chiave segreta e la stessa configurazione, e leggere il payload recuperato.
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. Codificare un payload noto in un run di testo noto, quindi decodificarlo di nuovo con la stessa chiave e configurazione; confermare che il payload recuperato corrisponda.
  2. Decodificare con una chiave deliberatamente errata e confermare che il risultato sia null, non un payload errato — questa è la garanzia di integrità AEAD all’opera.
  3. Ispezionare la pagina renderizzata e confermare che il cambiamento di spaziatura non sia visivamente percepibile al rapporto di deviazione configurato.
  4. Quando è richiesta la compatibilità PDF/A, validare l’output rispetto al proprio profilo PDF/A e confermare che la tolleranza di larghezza non venga superata.
  • Cifratura autenticata. Il payload è cifrato con AES-256-GCM o ChaCha20-Poly1305. Un carrier manomesso o troncato fallisce l’autenticazione alla decifratura; non restituisce un payload errato.
  • IV per cifratura. Un nuovo IV casuale da 12 byte è generato per ogni cifratura, soddisfacendo il requisito di unicità di AES-GCM secondo NIST SP 800-38D §5.2.1.
  • Chiave derivata. La chiave di cifratura è derivata con HKDF-SHA-256 dal proprio secret e dalla chiave del font (RFC 5869 §2). Mantenere il secret nel proprio secret manager; trattarlo come qualsiasi secret di firma.
  • Il marcatore è contenuto del documento. I byte incorporati fanno parte del contenuto della pagina, non del contenuto dei log. Non scrivere il payload o la chiave segreta nei log.

Questa pagina riguarda l’incorporamento crittografico. Ogni sorgente normativa è parafrasata; nessun testo normativo è riprodotto. ### Divulgazione sulla robustezza

Il marcatore è trasportato negli aggiustamenti di crenatura. Può essere distrutto dalla stampa e ri-scansione, da strumenti di conversione PDF, dalla ri-linearizzazione o da qualsiasi riscrittura del content stream che normalizzi la crenatura. La tecnica è più adatta al tracciamento interno delle fughe di documenti distribuiti nella loro forma generata. Non è steganografia avversariale e non sopravvive a un’elaborazione downstream arbitraria. Non farvi affidamento come unico controllo quando il modello di minaccia include una rimozione deliberata.

  • Payload troppo grande. L’encoder solleva un errore di overflow tipizzato quando il payload eccede la capacità del testo. Accorciare il payload o allungare il testo carrier.
  • Troppo poco testo carrier. Un testo più corto di due caratteri non offre alcuna posizione carrier e solleva un errore.
  • Chiave errata in decodifica. La decodifica restituisce null. Trattare null come «nessun marcatore recuperato», non come un risultato parziale.
  • Mancata corrispondenza della configurazione. La codifica e la decodifica devono usare la stessa profondità di bit, rapporto di deviazione, cifrario e flag PDF/A; una mancata corrispondenza non recupera alcun payload.

Questa pagina documenta solo il comportamento osservabile esternamente e la superficie dell’API pubblica supportata. I percorsi di namespace interni, le classi helper, le tabelle dei meccanismi, i nomi di file dei runbook e i prefissi dei ticket sono fuori ambito.