画像の見た目をまったく変えずに、テキストやパスワードを隠しておきたい──そんなニーズ、意外とありませんか?
たとえば「暗号化したパスワードを安全に保管しておきたい」「メモをこっそり画像に埋めたい」「秘密の文章を一枚の画像に入れておきたい」など。
そこで今回、画像のアルファチャンネル(透明度)を使って、肉眼ではほぼ判別できない形で文章を埋め込めるステガノグラフィ(情報隠蔽)ツールを作りました。
しかもこれ、完全にHTML単体で動く1ファイル完結型ツールです。
ブラウザで開くだけで使え、保存データも一切残りません(localStorage / IndexedDB も未使用)。
安全にオフライン利用できます。
1920 × 1080 px の画像なら、約 360853 文字を格納できます。
公開中のデモ & ソースコード
Qiita記事内にはコード全文を掲載していません。
以下の公開ページまたは GitHub から利用・ダウンロードできます。
-
GitHub ソースコード
https://github.com/uni928/TestYou/blob/main/index38.html
旧版は index38 を index37 に変えて下さい。(旧版で出力した方が解析難易度は低めです)
この HTML を保存するだけで、そのままオフラインで使用できます。
※是非、コードをダウンロードして ChatGPT などで不審な処理(情報を抜き取る処理など)が含まれていないか確認してからご利用ください。
どんな仕組みなのか(概要)
このツールの特徴は 「画像の透明度(アルファ値)をわずかに変えるだけで、画像の見た目を変えずにデータを格納できる」 ことです。
RGBの色は一切変更しません。
アルファ値(0〜255)を 255 → 255〜248(=0〜7低下) の範囲で利用し、
1ピクセルあたり3bit(8値) の情報を埋め込みます。
元の画像が完全不透明(全α=255)なら、
人間の目ではこの“7の差”はまず見分けられません。
つまり「隠された情報があるように見えない画像」を自然に作れます。
入力画像の条件:全ピクセル α=255 のみ許可
ツールでは、画像を読み込んだ際に 全ピクセルのアルファ値が255かどうかを全スキャン します。
1つでも 255 以外を見つけた場合は、
「透明度が完全不透明(255)でないため使用できません」
とエラーを出して処理を中止します。
これにより、
アルファ値の変化=情報埋め込みとして安全に扱えるようになります。
データ埋め込みの構造
ツールは、以下のように画像ピクセルを使って情報を分割して埋め込みます。
1. 最初の7ピクセルは “文字数情報”
- 7ピクセル × 3bit = 21bit
- 21bit で 0〜2097151 を表現(最大2097151文字)
先頭7ピクセルは必ずヘッダ領域として予約し、
そこに文章の 文字数(UTF-16ベース) を格納します。
2. 残りのピクセルで本文を埋め込む
文章は 1文字=16bit(UTF-16) として扱います。
1ピクセルあたり3bitなので、
文章が長いほど多くのピクセルが必要になります。
必要なピクセル数
→ (7px + ceil(文字数 × 16bit / 3bit))
この計算で足りない場合は
「画像に文章を格納しきれません」
というエラーダイアログを表示します。
1920 × 1080 px の画像なら、約 360853 文字を格納できます。
具体的にどんな使い道がある?
● 暗号化したパスワードの隠し収納
暗号化した文字列を画像に埋め込み、
見た目はただの写真に見せかけて保存できます。
普通の人が見ても、データが入っているとは気づきません。
● ちょっとしたメモや秘密のメッセージを隠す
- メールで画像を送る
- SNS にアップする
- 画像だけUSBに入れて渡す
こんなとき、文章を“見えない場所”に仕込めます。
● 特定の人だけ復元できる仕組みに
同じツールを持っていないと復元は不可能なので
“ちょっとした秘密共有”に向いています。
(本格的なセキュリティ用途というより、
「隠す仕掛け」として利用する想定です)
● 普通のステガノグラフィより解析されにくい
一般的なステガノグラフィは「RGBのLSB(最下位ビット)を書き換える」手法が主流ですが、
RGB は色情報そのものを持つため、微小な変化でも解析ツールに検出されやすいという弱点があります。
一方、本ツールは RGB には一切触れず、
アルファ値(透明度)を “最大7 だけ下げる” という、あまり一般的でない手法を採用しています。
アルファ値をわずかに変えるステガノグラフィは利用例が少なく、
既存の解析ツールにも引っかかりにくいため、
解析されにくいという利点があります。
RGB の下位 1 bit を書き換える方法は劣化が少ないものの、
下位 1 bit の変化には意味があると推測されやすく、解析の手掛かりになりやすいという欠点があります。
また、RGB の下位 1 bit と透明度(254 / 255 の切り替え)を併用する手法も、
一見すると解析されにくい方法ではあります。
しかし実際には、
- LSB 解析
- カラー統計解析
- 画像処理系のステガ検出手法
といった既存のステガノグラフィ検出アルゴリズムにより、ステガノグラフィが施されていること自体は比較的容易に判定されてしまいます。
その点、A(アルファ)値のみを変更する方式は、従来の検出手法の想定外であるため、より解析が困難で安全性が高いと言えるでしょう。
解析をさらに困難にしたい場合は、247 や 246 といった“有効範囲内のダミー値”を意図的に混ぜる手法が考えられます。
たとえば、文字データの保存に 100 ピクセルを使用している場合、その間にランダムで 247 や 246 を挿入しておき、これらはデコード時には 無視する値 として扱います。
本来 3bit の範囲であれば解析される可能性はありますが、そこから 規則的なビット幅(3bit)をわざと崩すことで、第三者にとっては法則性が読み取りにくくなります。
さらに、データ領域の外側にも 246〜255 の同様の値を散りばめておく ことで、どこからどこまでが有効データなのか判断しにくくなり、解析難度を大きく引き上げることができます。
可能であれば、247 や 246 を有効な値として利用しつつ、
無視する値を 249 や 252 などに変更することで、解析をさらに困難にする工夫を加えることができます。
無効な値を挿入する際は、全体の分布が不自然にならないよう、他の値と同程度の頻度になるよう調整することが重要です。
また、挿入する無効な値が同じ数にならないようにすることで、解析されにくい状態を保てます。
● RGB で隠ぺいする既存の方法の場合
RGB の LSB(最下位ビット)を利用して隠ぺいする一般的な手法では、
次の 8 通りのビットパターンが利用できます。
- (r, g, b) = (0, 0, 0)
- (r, g, b) = (1, 0, 0)
- (r, g, b) = (0, 1, 0)
- (r, g, b) = (1, 1, 0)
- (r, g, b) = (0, 0, 1)
- (r, g, b) = (1, 0, 1)
- (r, g, b) = (0, 1, 1)
- (r, g, b) = (1, 1, 1)
この 8 パターンのうち不規則な 4 パターンをダミー用として確保しておき、
まずヘッダー部分に「要素数(データ長)」の正規データを埋め込み、
その後に本文の間へ 自然に見えるようダミーを混ぜていく と解析されにくくなります。
また、ヘッダーで指定した要素数より後方には、
ダミーパターンを除いて解析するとランダムな文字列が浮かび上がるような配置になるようダミーデータを挿入しておくと、
データ領域とダミー領域の境界が分かりにくくなり、さらに秘匿性が高まります。
※混ぜ方の一例としては、まず 4 パターンのダミーをランダムに挿入し、
そのうえで 1 パターン目の約 2.3% を 2 パターン目へ置き換える、
さらに 3 パターン目の約 3.2% を 4 パターン目に置き換える といった手順にすると、
分布が自然になり、実装も比較的容易だと思います。
使い方(エンコード=埋め込み)
ツール画面には2つの操作パネルがあります。
- テキストエリアに埋め込みたい文章を入力
- 画像をアップロード
- ツールが透明度チェック(全α=255)を実施
- 問題なければ「文章を埋め込む」をクリック
- 生成された画像を PNG としてダウンロード
文章量が多くても、キャンバスに容量が足りなければエラーダイアログで止まります。
使い方(デコード=文章抽出)
- 埋め込み済み画像を読み込む
- 「文章を抽出」ボタンを押す
- テキストエリアに復元された文章が表示される
- 「コピー」ボタンでクリップボードにコピー可能
このように、1ファイルでエンコード・デコード両方に対応しています。
実装詳細は GitHub & 公開ページへ
Qiita側にはコード全文を載せません。
実際のUIやコードは以下で確認できます。
-
公開URL(動作デモ)
https://uni928.github.io/TestYou/index38.html -
ソースコード(GitHub)
https://github.com/uni928/TestYou/blob/main/index38.html
旧版は index38 を index37 に変えて下さい。(旧版で出力した方が解析難易度は低めです)
HTML単体で動作し、
特別なサーバも不要なので、
「ちょっとしたステガノグラフィツール」を作りたい方にも参考になると思います。
※是非、コードをダウンロードして ChatGPT などで不審な処理(情報を抜き取る処理など)が含まれていないか確認してからご利用ください。
類似的な実装
PNG では、先頭の「シグネチャ+チャンク列」が正しければ画像として認識され、
IEND チャンクの後ろに余分なバイトがあっても基本的には無視されるという仕様があります。
この性質を利用すれば、PNG の末尾に任意のデータをそのまま“つなげる”ことができます。
ただし、この手法は厳密には「ステガノグラフィ」というより 単にファイルの後ろに荷物をぶら下げているだけ であり、以下のようなデメリットがあります。
- バイナリエディタで見ればすぐに分かる(暗号化すれば多少マシになります)
- PNG 最適化ツールや再保存時に、末尾の余分データがすべて削除される可能性がある
- 厳しめのチェックツールでは、「末尾に不要なデータがある」と警告される場合がある
このように、簡単に実装できる反面、「隠す」目的では弱点も多い手法となっています。
まとめ
- 画像の見た目をほぼ変えずに文章を埋め込める
- アルファチャンネルの微小な変化(0〜7)だけを利用
- 1ピクセル3bit、UTF-16で最大2097151文字まで対応
- 純粋なHTML1ファイルで完結・オフライン動作
- パスワードやメモなど“人に気付かれずに隠したい情報”に向く
- デモページとソースコードも公開中
必要最小限のステガノグラフィとして、
扱いやすさ・安全性・視認性のバランスを重視したツールになっています。
興味があれば、ぜひ触ってみてください!
追記
この記事は ChatGPT で添削しております。
また、このツールは ChatGPT で作成したツールです。
生成 AI による文章・ツールが苦手な方は申し訳ありません。