🐤
PDFから「存在を消す」Forensic Deep Purgeと、肉眼で見えない透かしStealth Watermarkの実装開発日誌 #6
開発日誌 #6 です。前回はMagic Pipelineの設計について書きました。
※検証環境は8年前のMacBook Airです。
今回は「見えないセキュリティ」を2つ紹介します。
- Forensic Deep Purge:PDFからメタデータや隠しデータを物理的に抹消する
- Stealth Watermark:肉眼では見えないが、流出経路を特定できる透かしを埋め込む
Forensic Deep Purge:「削除」では足りない
PDFを「名前を付けて保存」しても、元のファイルの痕跡が残ることがあります。
具体的には:
- 作成者名・ソフトウェア名・作成日時などのメタデータ
- 削除されたはずのテキストや画像(PDFの構造上、「隠れているだけ」のことがある)
- XMPメタデータ(Adobeが策定した拡張メタデータ規格)
- 非表示レイヤー・注釈の残骸
これらを「削除」するのではなく、必要な要素だけで新しいPDFを再構築することで物理的に排除します。
これが Zero-Trust Reconstruction の考え方です。
pub fn deep_purge(input: &[u8]) -> Result, PurgeError> {
let mut doc = Document::load_mem(input)?;
// 1. メタデータを完全削除
doc.trailer.remove(b"Info");
// 2. XMPメタデータストリームを削除
if let Ok(catalog) = doc.catalog_mut() {
catalog.remove(b"Metadata");
}
// 3. 全オブジェクトを走査して不要な情報を除去
for (_, object) in doc.objects.iter_mut() {
if let Ok(dict) = object.as_dict_mut() {
for key in &[b"Author", b"Creator", b"Producer", b"CreationDate", b"ModDate"] {
dict.remove(*key);
}
}
}
// 4. PDFを完全に再シリアライズ(構造ごと再構築)
let mut output = Vec::new();
doc.save_to(&mut output)?;
Ok(output)
}
単純にメタデータを書き換えるだけでなく、再シリアライズによって構造ごとクリーンにするのがポイントです。
Stealth Watermark:見えないけど追跡できる
Layer 1: マイクロスタンプ(テキストレイヤー)
透明度を極限まで下げたテキストを各ページに埋め込みます。
pub fn embed_stealth_text(
doc: &mut Document,
page_id: ObjectId,
stamp_text: &str,
) -> Result<(), lopdf::Error> {
let content_stream = format!(
"q\nBT\n/F1 1 Tf\n0.01 g\n100 100 Td\n({}) Tj\nET\nQ\n",
stamp_text // 例: "COPY-2024-USER-0042"
);
append_content_to_page(doc, page_id, content_stream.as_bytes())?;
Ok(())
}
Layer 2: Forensic Ghost-Mark(メタデータ深部への電子署名)
pub fn embed_ghost_mark(
doc: &mut Document,
seal: &str,
) -> Result<(), lopdf::Error> {
let catalog = doc.catalog_mut()?;
catalog.set(b"HiyokoSeal", Object::string_literal(seal));
Ok(())
}
通常のPDFビューアでは表示されませんが、lopdfで構造を見れば検出できます。
現在の状況(dev版)

次回
次回は Ollamaを使ったオフラインAIチャット の実装について書きます。
Hiyoko PDF Vault(日本語) → https://hiyokoko.gumroad.com/l/HiyokoPDFVault_jp
X → @hiyoyok
Discussion