コンテンツにスキップ
getnextpdf.com

Enterprise エディション

ステガノグラフィ — 詳細リファレンス

この詳細リファレンスは、NextPDF Enterprise のステガノグラフィ・チャネルを解説します。このチャネルは、TJ テキスト表示配列の数値カーン調整値の内部に暗号化ペイロードを隠します。公開シンボルは 4 つで、SteganographyEncoderSteganographyDecoderSteganographyConfigSteganographyCapacity です。エンコーダーは HKDF-SHA-256 で鍵を導出し、AEAD 暗号でペイロードを暗号化し、位置ごとのカーンオフセットを返します。デコーダーは、観測された調整値または生のコンテンツストリームからこの処理を逆にたどります。

このチャネルは社内文書の漏洩追跡を目的として設計されています。敵対的環境に耐えるレベルのステガノグラフィではありません。エンコードされたデータは、印刷してからのスキャン、PDF 変換、再リニアライズ、コンテンツストリームの書き換え、あるいはカーニングを正規化するあらゆる操作によって破壊される可能性があります。NextPDF はこのチャネルについていかなる認証も保有せず、また付与しません。このページは能力を述べるものであり、適合性を述べるものではありません。

この機能は NextPDF Enterprisenextpdf/enterprise)に含まれ、Enterprise ティアのライセンスエンベロープで有効化されます。当該エンタイトルメントを持たないデプロイでは、この機能のクラスは読み込まれません。エディションを比較してライセンスを入手

このチャネルは 4 つの 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鍵強度をアサート。偏差を量子化。ブロブを再構築。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 クラス。4 つの引数は public に昇格されたプロパティ。
SteganographyConfig::effectiveMaxOffsetなし$maxAdjustmentEmRatio * 1000 を返し、PDF/A 互換性が要求された場合は半分にする。float(1/1000 em 単位のオフセット)該当なし半減により幅不一致の検出リスクを低減します。
SteganographyConfig::CRYPTO_OVERHEAD定数ペイロードごとの固定暗号化オーバーヘッド(バイト単位)。int(32)該当なし4 バイトの長さ、12 バイトのノンス、16 バイトのタグ。
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 文字に分割し、連続する文字ペアごとに 1 つの位置を形成します。各位置は $config->bitDepth ビット(1 または 2)を担います。ペイロードはまず暗号化され、次にブロブへシリアライズされ、その後ビット列へ変換されます。各位置は、その文字ペアの自然なカーン値に加える小さな非負のオフセットとして、自らのビットをエンコードします。

オフセットは実効最大オフセットの一部分です。実効最大オフセットは $maxAdjustmentEmRatio * 1000 デザインユニットで、$requirePdfACompatibility が true のときは半分になります。自然なカーンは FontMetrics::getKernPair を通じて $metrics から読み取られます。返されるマップは疎です。最終調整値がちょうどゼロになる位置は省略されます。

暗号化は HKDF-SHA-256 を用いて 32 バイトの鍵を導出します。HKDF のソルトは非秘密の $fontKey で、info ラベルは固定の定数です。したがって呼び出し側の $secretKey が唯一の機密性境界となります。AEAD 暗号は $config->cipher で選択される aes-256-gcm または chacha20-poly1305 で、新しい 12 バイトのノンスと 16 バイトのタグを用いて openssl_encrypt を通じて実行されます。シリアライズされたブロブは、4 バイトのビッグエンディアン長、12 バイトのノンス、暗号文、16 バイトのタグで構成されます。この固定オーバーヘッドが CRYPTO_OVERHEAD であり、32 バイトです。

デコーダーはこの変換を逆にたどります。観測された各調整値と自然なカーンとの偏差を計算し、実効最大オフセットで正規化し、最も近いレベルに量子化します。ブロブを再構成し、長さヘッダーを検証し、openssl_decrypt を呼び出します。誤った鍵、欠落したペイロード、または破損した調整値は AEAD 認証を失敗させ、デコーダーは null を返します。decodeFromContentStream はまず NextPDF\Pro\Projection\ContentProjectionWriter::tokenize で生ストリームをトークン化し、各 TJ 配列からテキストと数値調整値を再構築し、その後 decode に委譲します。

SteganographyCapacity::calculate は、CRYPTO_OVERHEAD を差し引いたうえで、あるテキストと構成に対する利用可能なペイロードサイズを報告します。テキストが短すぎる場合はゼロを返します。SteganographyCapacity::minimumTextLength はその逆で、要求サイズのペイロードを収容できる最小の UTF-8 文字数です。

  • 空の $payloadencode から空のマップを返します。バイトは書き込まれず、鍵強度ガードには到達しません。
  • 空でないペイロードの場合、2 文字未満の $textencodeOverflowException を発生させます(空のペイロードは長さチェックの前に [] へ短絡します)。同じテキストは decode では null を、SteganographyCapacity::calculate では 0 を返します。
  • テキスト容量を超える $payload は、いかなる調整値も出力される前に OverflowException を発生させます。
  • MIN_SECRET_KEY_LENGTH(16 バイト)より短い $secretKey は、書き込みパスと読み取りパスの両方で InvalidArgumentException を発生させます。これは契約違反であり、通常の誤鍵によるミスとは区別されます。
  • 誤った鍵、破損した調整値集合、または切り詰められたブロブは、例外ではなく AEAD 認証失敗を通じて decodenull を返させます。
  • 疎な $observedAdjustments マップに存在しない位置は、抽出時にゼロ偏差として扱われます。
  • decodeFromContentStream は、ストリームに TJ テキストが含まれない場合に null を返します。
  • このチャネルは設計上、脆弱です。印刷してからのスキャン、PDF 変換、再リニアライズ、コンテンツストリームの書き換え、またはカーニングの正規化は、エンコードされたデータを破壊し得ます。敵対的用途やアーカイブ用途には適しません。

このチャネルは、鍵導出に HKDF-SHA-256 を、機密性と完全性に 1 つの AEAD 暗号を使用します。NextPDF はこのチャネルについて FIPS 検証を保有しておらず、それを主張しません。 モジュールは FIPS プロファイルを強制せず、暗号の選択は $config->cipher を通じた呼び出し側の判断です。aes-256-gcm は Galois/Counter Mode の AES であり、承認された 128 ビットブロック暗号の上に構築された認証付き暗号化モードで、その適合性は CMVP のもとで検証されます(NIST SP 800-38D §2)。chacha20-poly1305 は NIST の動作モード推奨で定義されていないため、FIPS 制約下の OpenSSL プロバイダーはこれを拒否します。openssl_encrypt は false を返し、エンコーダーは SteganographyEncryptionException を発生させます。あるデプロイが FIPS 要件を満たすかどうかは、その検証済みプロバイダーに照らした運用者の判断であり、NextPDF の主張ではありません。

この埋め込みは、TJ テキスト表示配列に数値要素を書き込みます。ISO 32000-2:2020 §9.4.3 によれば、TJ 配列はテキストを表示し、数値要素にグリフ位置の調整を行わせます。その数値はテキスト空間単位の 1/1000 で表現され、現在位置から減算されます。グリフが描画された後、テキスト行列は合成された変位分だけ平行移動されるため、位置調整の数値は後続のグリフの配置をずらします(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 は例外です。
  • SteganographyConfigfinal readonly の値オブジェクトです。その 4 つのプロパティは構築後は不変で、引数の定義域はコンストラクターで検証されます。$bitDepth は 1 または 2、$maxAdjustmentEmRatio(0, 0.05] の範囲、$cipheraes-256-gcm または chacha20-poly1305 です。
  • エンコード出力は NextPDF\Content\TextRenderer::buildTjArrayOperator によって消費されます。カーンペアは NextPDF\Typography\FontMetrics から得られます。コンテンツストリームのデコードは NextPDF\Pro\Projection\ContentProjectionWriter を通じて読み取り、ストリームは変更しません。
  • 鍵長の下限はエントリポイントで強制され、プライベートな暗号境界で再アサートされます。したがって、いかなる内部パスも弱い鍵で HKDF に到達できません。ライブラリは長さを強制し、エントロピーは強制しません。高エントロピーの鍵素材を供給するのはインテグレーターの責任です。
  • CRYPTO_OVERHEAD(32 バイト)はペイロードごとの固定コストで、SteganographyCapacity::calculate によって既に差し引かれています。
  • 集約された Enterprise サーフェスに対する記載上の since は 3.1.0 です。SteganographyEncryptionExceptionRuntimeException を継承するため、汎用のランタイム型を捕捉する呼び出し側は引き続き動作します。

このページは、外部から観測可能な挙動とサポート対象の公開 API サーフェスのみを記載します。内部の名前空間パス、ヘルパークラス、機構テーブル、ランブックのファイル名、およびチケットの接頭辞は対象外です。