Enterprise 版本
隱寫術 — 深入參考
本深度參考文件說明 NextPDF Enterprise 的隱寫術通道。此通道將加密酬載隱藏在 TJ 顯示文字陣列的數值字距調整量之中。它公開四個符號:SteganographyEncoder、SteganographyDecoder、SteganographyConfig 與 SteganographyCapacity。編碼器以 HKDF-SHA-256 衍生金鑰,用 AEAD 加密演算法加密酬載,並回傳各位置的字距偏移量。解碼器則從觀察到的調整量或原始內容串流反向還原此過程。
此通道是為內部文件外洩追蹤而設計。它並非對抗等級的隱寫術。編碼後的資料可能因列印後掃描、PDF 轉換、重新線性化、內容串流改寫,或任何會正規化字距的操作而遭到破壞。NextPDF 對此通道不持有任何認證,也不授予任何認證。本頁陳述的是能力,而非合規性。
供應與授權
標題為「供應與授權」的區段此功能隨 NextPDF Enterprise(nextpdf/enterprise)出貨,並以 Enterprise 層級的授權封套啟用。未具備該權利的部署不會載入此功能的類別。比較版本並取得授權。
公開 API 介面
標題為「公開 API 介面」的區段此通道公開四個 final 類別。所有進入點都是 public static,唯有 SteganographyConfig 建構子及其 effectiveMaxOffset 存取器例外。輔助的 NextPDF\Enterprise\Security\Steganography\SteganographyEncryptionException 由編碼器擲出,並非由呼叫端建構的型別。
| 符號 | 參數 | 預設行為 | 回傳 | 擲出或失敗於 | 附註 |
|---|---|---|---|---|---|
SteganographyEncoder::encode | $payload、$text、$fontKey、$metrics(FontMetrics)、$secretKey、$config(SteganographyConfig) | 空的 $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 | 拒絕短於下限的金鑰。 | void | InvalidArgumentException(金鑰低於下限) | 寫入路徑的共用防護,讀取路徑亦有對應。 |
SteganographyEncoder::MIN_SECRET_KEY_LENGTH | 常數 | 以位元組表示的 128 位元金鑰長度下限。 | int(16) | 不適用 | 此程式庫強制的是長度,而非熵。 |
SteganographyDecoder::decode | $observedAdjustments、$text、$fontKey、$metrics(FontMetrics)、$secretKey、$config(SteganographyConfig) | 驗證金鑰強度;量化偏差;重建 blob;以 AEAD 解密。 | `string | null(酬載,或在金鑰錯誤或無酬載時為 null`) | InvalidArgumentException(金鑰低於下限) |
SteganographyDecoder::decodeFromContentStream | $contentStream、$fontKey、$metrics(FontMetrics)、$secretKey、$config(SteganographyConfig) | 對串流進行語彙分析,從 TJ 陣列重建文字與調整量,再委派給 decode。 | `string | null(酬載,或在無 TJ文字或解密失敗時為null`) | InvalidArgumentException(金鑰低於下限,經由 decode) |
SteganographyConfig::__construct | $bitDepth、$maxAdjustmentEmRatio、$cipher、$requirePdfACompatibility | 驗證各引數的定義域;產生不可變的值物件。 | SteganographyConfig 實例 | InvalidArgumentException(無效的 $bitDepth、$maxAdjustmentEmRatio 或 $cipher) | readonly 類別;四個引數為公開的 promoted 屬性。 |
SteganographyConfig::effectiveMaxOffset | 無 | 回傳 $maxAdjustmentEmRatio * 1000,並在要求 PDF/A 相容性時減半。 | float(以 1/1000 em 表示的偏移量) | 不適用 | 減半可降低寬度不符被偵測的風險。 |
SteganographyConfig::CRYPTO_OVERHEAD | 常數 | 每個酬載固定的加密額外開銷(位元組)。 | int(32) | 不適用 | 4 位元組長度、12 位元組 nonce、16 位元組 tag。 |
SteganographyCapacity::calculate | $text、$config(SteganographyConfig) | 計算該文字在扣除額外開銷後可用的酬載位元組數。 | int(文字過短時為 0) | 不適用 | 容量為 positions * bitDepth / 8 減去額外開銷。 |
SteganographyCapacity::minimumTextLength | $payloadBytes、$config(SteganographyConfig) | 計算某酬載所需的最小 UTF-8 字元數。 | int(字元數) | 不適用 | calculate 的反函數。 |
以下為逐字簽章,各附來源出處。
public static function encode( string $payload, string $text, string $fontKey, FontMetrics $metrics, string $secretKey, SteganographyConfig $config = new SteganographyConfig(),): arraypublic static function assertSecretKeyStrength(string $secretKey): voidpublic 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(),): ?stringpublic static function decodeFromContentStream( string $contentStream, string $fontKey, FontMetrics $metrics, string $secretKey, SteganographyConfig $config = new SteganographyConfig(),): ?stringpublic function __construct( public int $bitDepth = 1, public float $maxAdjustmentEmRatio = 0.02, public string $cipher = 'aes-256-gcm', public bool $requirePdfACompatibility = false,)public function effectiveMaxOffset(): floatpublic const int CRYPTO_OVERHEAD = 32;public static function calculate( string $text, SteganographyConfig $config = new SteganographyConfig(),): intpublic 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-gcm 或 chacha20-poly1305,由 $config->cipher 選定,透過 openssl_encrypt 搭配全新的 12 位元組 nonce 與 16 位元組 tag 執行。序列化後的 blob 由 4 位元組 big-endian 長度、12 位元組 nonce、密文與 16 位元組 tag 組成;此固定額外開銷即 CRYPTO_OVERHEAD,為 32 位元組。
解碼器反向還原此轉換。它計算每個觀察到的調整量相對於自然字距的偏差,以有效最大偏移量正規化,並量化到最接近的層級。它重新組裝 blob,驗證長度標頭,並呼叫 openssl_decrypt。錯誤的金鑰、缺漏的酬載或損毀的調整量會導致 AEAD 驗證失敗,解碼器則回傳 null。decodeFromContentStream 會先以 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 轉換、重新線性化、內容串流改寫或字距正規化都可能破壞編碼後的資料。它不適合對抗性或封存用途。
FIPS 模式行為
標題為「FIPS 模式行為」的區段此通道以 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],$cipher為aes-256-gcm或chacha20-poly1305。- encode 的輸出由
NextPDF\Content\TextRenderer::buildTjArrayOperator消費。字距對來自NextPDF\Typography\FontMetrics。內容串流解碼透過NextPDF\Pro\Projection\ContentProjectionWriter讀取,且不會變更串流。 - 金鑰長度下限在進入點強制執行,並在私有密碼學邊界再次驗證,因此沒有任何內部路徑能以弱金鑰觸及 HKDF。此程式庫強制的是長度,而非熵;提供高熵金鑰材料是整合者的責任。
CRYPTO_OVERHEAD(32 位元組)是每個酬載的固定成本,且已由SteganographyCapacity::calculate事先扣除。- 就聚合後的 Enterprise 介面而言,記載的 since 為
3.1.0。SteganographyEncryptionException繼承自RuntimeException,因此捕捉通用 runtime 型別的呼叫點仍可正常運作。
另請參閱
標題為「另請參閱」的區段- 隱寫術(功能頁) — 外洩追蹤通道的任務導向概覽。
- 安全性 — 深度參考 — 姊妹的 Enterprise 安全性介面。
- 授權與啟用 — Enterprise 授權封套如何套用。
出版邊界
標題為「出版邊界」的區段本頁僅記載外部可觀察的行為與受支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表格、runbook 檔名與工單前綴皆不在範圍內。