跳到內容
getnextpdf.com

Enterprise 版本

隱寫術 — 深入參考

本深度參考文件說明 NextPDF Enterprise 的隱寫術通道。此通道將加密酬載隱藏在 TJ 顯示文字陣列的數值字距調整量之中。它公開四個符號:SteganographyEncoderSteganographyDecoderSteganographyConfigSteganographyCapacity。編碼器以 HKDF-SHA-256 衍生金鑰,用 AEAD 加密演算法加密酬載,並回傳各位置的字距偏移量。解碼器則從觀察到的調整量或原始內容串流反向還原此過程。

此通道是為內部文件外洩追蹤而設計。它並非對抗等級的隱寫術。編碼後的資料可能因列印後掃描、PDF 轉換、重新線性化、內容串流改寫,或任何會正規化字距的操作而遭到破壞。NextPDF 對此通道不持有任何認證,也不授予任何認證。本頁陳述的是能力,而非合規性。

此功能隨 NextPDF Enterprisenextpdf/enterprise)出貨,並以 Enterprise 層級的授權封套啟用。未具備該權利的部署不會載入此功能的類別。比較版本並取得授權

此通道公開四個 final 類別。所有進入點都是 public static,唯有 SteganographyConfig 建構子及其 effectiveMaxOffset 存取器例外。輔助的 NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException 由編碼器擲出,並非由呼叫端建構的型別。

符號參數預設行為回傳擲出或失敗於附註
SteganographyEncoder::encode$payload$text$fontKey$metricsFontMetrics)、$secretKey$configSteganographyConfig空的 $payload 回傳 [];驗證金鑰強度;加密;計算各位置的字距偏移量。array<int, float>(位置 => 以 1/1000 em 表示的調整量,AFM 慣例)InvalidArgumentException(金鑰低於下限);OverflowException(文字少於 2 個字元,或酬載超過容量);SteganographyEncryptionException(AEAD 失敗)將結果傳入 NextPDF\Content\TextRenderer::buildTjArrayOperator()。此 API 回傳 AFM 慣例的調整量;buildTjArrayOperator() 執行 PDF TJ 的數值轉換(ISO 32000-2 會從目前位置減去該數字)。手動撰寫內容串流者必須保留該正負號慣例。
SteganographyEncoder::assertSecretKeyStrength$secretKey拒絕短於下限的金鑰。voidInvalidArgumentException(金鑰低於下限)寫入路徑的共用防護,讀取路徑亦有對應。
SteganographyEncoder::MIN_SECRET_KEY_LENGTH常數以位元組表示的 128 位元金鑰長度下限。int(16)不適用此程式庫強制的是長度,而非熵。
SteganographyDecoder::decode$observedAdjustments$text$fontKey$metricsFontMetrics)、$secretKey$configSteganographyConfig驗證金鑰強度;量化偏差;重建 blob;以 AEAD 解密。`stringnull(酬載,或在金鑰錯誤或無酬載時為 null`)InvalidArgumentException(金鑰低於下限)
SteganographyDecoder::decodeFromContentStream$contentStream$fontKey$metricsFontMetrics)、$secretKey$configSteganographyConfig對串流進行語彙分析,從 TJ 陣列重建文字與調整量,再委派給 decode`stringnull(酬載,或在無 TJ文字或解密失敗時為null`)InvalidArgumentException(金鑰低於下限,經由 decode
SteganographyConfig::__construct$bitDepth$maxAdjustmentEmRatio$cipher$requirePdfACompatibility驗證各引數的定義域;產生不可變的值物件。SteganographyConfig 實例InvalidArgumentException(無效的 $bitDepth$maxAdjustmentEmRatio$cipherreadonly 類別;四個引數為公開的 promoted 屬性。
SteganographyConfig::effectiveMaxOffset回傳 $maxAdjustmentEmRatio * 1000,並在要求 PDF/A 相容性時減半。float(以 1/1000 em 表示的偏移量)不適用減半可降低寬度不符被偵測的風險。
SteganographyConfig::CRYPTO_OVERHEAD常數每個酬載固定的加密額外開銷(位元組)。int(32)不適用4 位元組長度、12 位元組 nonce、16 位元組 tag。
SteganographyCapacity::calculate$text$configSteganographyConfig計算該文字在扣除額外開銷後可用的酬載位元組數。int(文字過短時為 0)不適用容量為 positions * bitDepth / 8 減去額外開銷。
SteganographyCapacity::minimumTextLength$payloadBytes$configSteganographyConfig計算某酬載所需的最小 UTF-8 字元數。int(字元數)不適用calculate 的反函數。

以下為逐字簽章,各附來源出處。

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

編碼器將 $text 拆解為 UTF-8 字元,並對每對連續字元形成一個位置。每個位置承載 $config->bitDepth 個位元,其值為一或二。酬載先被加密,再序列化為 blob,然後轉換為位元序列。每個位置將其位元編碼為一個小的非負偏移量,加到該字元對的自然字距值上。

該偏移量是有效最大偏移量的一個分數。有效最大偏移量為 $maxAdjustmentEmRatio * 1000 設計單位,並在 $requirePdfACompatibility 為 true 時減半。自然字距透過 FontMetrics::getKernPair$metrics 讀取。回傳的映射是稀疏的:最終調整量恰為零的位置會被省略。

加密使用 HKDF-SHA-256 衍生一把 32 位元組金鑰。HKDF salt 為非機密的 $fontKey,info 標籤則是固定常數。因此呼叫端的 $secretKey 是唯一的機密性邊界。AEAD 加密演算法為 aes-256-gcmchacha20-poly1305,由 $config->cipher 選定,透過 openssl_encrypt 搭配全新的 12 位元組 nonce 與 16 位元組 tag 執行。序列化後的 blob 由 4 位元組 big-endian 長度、12 位元組 nonce、密文與 16 位元組 tag 組成;此固定額外開銷即 CRYPTO_OVERHEAD,為 32 位元組。

解碼器反向還原此轉換。它計算每個觀察到的調整量相對於自然字距的偏差,以有效最大偏移量正規化,並量化到最接近的層級。它重新組裝 blob,驗證長度標頭,並呼叫 openssl_decrypt。錯誤的金鑰、缺漏的酬載或損毀的調整量會導致 AEAD 驗證失敗,解碼器則回傳 nulldecodeFromContentStream 會先以 NextPDF\Pro\Projection\ContentProjectionWriter::tokenize 對原始串流進行語彙分析,從每個 TJ 陣列重建文字與數值調整量,再委派給 decode

SteganographyCapacity::calculate 回報某文字與組態在扣除 CRYPTO_OVERHEAD 後可用的酬載大小;文字過短時回傳零。SteganographyCapacity::minimumTextLength 則是反函數:能容納所要求大小酬載的最小 UTF-8 字元數。

  • 空的 $payload 會使 encode 回傳空映射;不寫入任何位元組,且金鑰強度防護不會被觸及。
  • 對於非空酬載,字元數少於二的 $text 會在 encode 中引發 OverflowException(空酬載會在長度檢查之前短路為 []);同一段文字在 decode 中產生 null,在 SteganographyCapacity::calculate 中產生零。
  • 大於文字容量的 $payload 會在發出任何調整量之前引發 OverflowException
  • 短於 MIN_SECRET_KEY_LENGTH(16 位元組)的 $secretKey 會在寫入與讀取兩條路徑上皆引發 InvalidArgumentException。這是合約違反,與一般的金鑰錯誤未命中不同。
  • 錯誤的金鑰、損毀的調整量集合,或截斷的 blob 會使 decode 透過 AEAD 驗證失敗而回傳 null,而非擲出例外。
  • 稀疏 $observedAdjustments 映射中缺漏的位置,在擷取時會被視為零偏差。
  • 當串流不含任何 TJ 文字時,decodeFromContentStream 回傳 null
  • 此通道在設計上就是脆弱的。列印後掃描、PDF 轉換、重新線性化、內容串流改寫或字距正規化都可能破壞編碼後的資料。它不適合對抗性或封存用途。

此通道以 HKDF-SHA-256 進行金鑰衍生,並以單一 AEAD 加密演算法提供機密性與完整性。NextPDF 對此通道不持有任何 FIPS 驗證,亦不宣稱任何驗證。 此模組不強制執行 FIPS 設定檔;加密演算法的選擇是呼叫端經由 $config->cipher 所做的決定。aes-256-gcm 是 Galois/Counter Mode 的 AES,一種建立於已核可的 128 位元區塊加密之上的驗證加密模式,其合規性依 NIST SP 800-38D §2 於 CMVP 下受到驗證。chacha20-poly1305 並非由任何 NIST 運作模式建議所定義,因此受 FIPS 約束的 OpenSSL provider 會拒絕它;openssl_encrypt 於是回傳 false,編碼器則引發 SteganographyEncryptionException。某部署是否符合 FIPS 要求,是由營運方針對其已驗證的 provider 自行判定,並非 NextPDF 的主張。

此嵌入將數值元素寫入 TJ 顯示文字陣列。依 ISO 32000-2:2020 §9.4.3,TJ 陣列顯示文字並讓數值元素調整字符位置;該數字以文字空間單位的千分之一表示,並從目前位置減去。在字符繪製後,文字矩陣會依合併位移進行平移,因此定位數字會移動後續字符的擺放位置——ISO 32000-2:2020 §9.4.4。此通道以相同的 1/1000 em(AFM)慣例將其偏移量加到自然字距值上,其中負值會收緊間距。

AEAD 的依據僅限於基元選擇:aes-256-gcm 對應 NIST SP 800-38D §2 的 GCM 模式。該參考識別的是一種演算法;它並非對此通道的驗證。

所有條款皆為改述;NextPDF 不重製規範性文字。NextPDF 對此通道不作任何隱寫術、密碼學或 PDF 合規性主張。與 TJ 定位模型的結構對齊是能力陳述,而非認證。穩健性揭露依然成立:此通道供內部外洩追蹤之用,並非對抗等級。

  • 進入點是 NextPDF\Enterprise\Security\Steganography 中的 public static 方法,唯有 SteganographyConfig 建構子與 effectiveMaxOffset 例外。
  • SteganographyConfig 是一個 final readonly 值物件。其四個屬性在建構後即不可變,且其引數定義域在建構子中受到驗證:$bitDepth 為 1 或 2,$maxAdjustmentEmRatio 位於 (0, 0.05]$cipheraes-256-gcmchacha20-poly1305
  • encode 的輸出由 NextPDF\Content\TextRenderer::buildTjArrayOperator 消費。字距對來自 NextPDF\Typography\FontMetrics。內容串流解碼透過 NextPDF\Pro\Projection\ContentProjectionWriter 讀取,且不會變更串流。
  • 金鑰長度下限在進入點強制執行,並在私有密碼學邊界再次驗證,因此沒有任何內部路徑能以弱金鑰觸及 HKDF。此程式庫強制的是長度,而非熵;提供高熵金鑰材料是整合者的責任。
  • CRYPTO_OVERHEAD(32 位元組)是每個酬載的固定成本,且已由 SteganographyCapacity::calculate 事先扣除。
  • 就聚合後的 Enterprise 介面而言,記載的 since 為 3.1.0SteganographyEncryptionException 繼承自 RuntimeException,因此捕捉通用 runtime 型別的呼叫點仍可正常運作。

本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名與工單前綴皆不在範圍內。