バイナリデータが画像ピクセルに埋め込まれる仕組み
LSB 埋め込みのビットレベルの手順を具体例で解説。メッセージのバイナリ変換からピクセルの最下位ビット書き換えまで、擬似コード付きで詳しく説明します。
Basics
詳細な説明
ビットレベルで見る LSB 埋め込み
この記事では、メッセージを画像に埋め込む LSB 置換の正確なプロセスを、具体的なバイナリ例とともに解説します。
ステップ 1: メッセージの準備
文字 "A"(ASCII コード 65、バイナリ 01000001)を隠す場合を考えます。8ビット必要なので、8つのカラーチャンネル値を変更します。1ピクセルに3チャンネルあるため、約3ピクセル(9チャンネル中8つ)を使用します。
ステップ 2: ピクセルデータの読み取り
最初の3ピクセルの RGB 値が以下の通りだとします:
Pixel 0: R=148 (10010100) G=203 (11001011) B=97 (01100001)
Pixel 1: R=66 (01000010) G=219 (11011011) B=112 (01110000)
Pixel 2: R=85 (01010101) G=200 (11001000) B=150 (10010110)
ステップ 3: LSB の置換
各チャンネルの最下位ビットをメッセージのビットで上書きします:
メッセージビット: 0 1 0 0 0 0 0 1
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
Pixel 0: R=10010100 → 1001010[0] (変更なし)
G=11001011 → 1100101[1] (変更なし)
B=01100001 → 0110000[0] (1→0 に変更)
Pixel 1: R=01000010 → 0100001[0] (変更なし)
G=11011011 → 1101101[0] (1→0 に変更)
B=01110000 → 0111000[0] (変更なし)
Pixel 2: R=01010101 → 0101010[0] (1→0 に変更)
G=11001000 → 1100100[1] (0→1 に変更)
ステップ 4: 変化量の確認
| チャンネル | 元の値 | 変更後 | 変化量 |
|---|---|---|---|
| P0.R | 148 | 148 | 0 |
| P0.G | 203 | 203 | 0 |
| P0.B | 97 | 96 | −1 |
| P1.R | 66 | 66 | 0 |
| P1.G | 219 | 218 | −1 |
| P1.B | 112 | 112 | 0 |
| P2.R | 85 | 84 | −1 |
| P2.G | 200 | 201 | +1 |
各チャンネルの最大変化はわずか ±1/256 です。視覚的にはまったく区別がつきません。
擬似コード
function embedMessage(imageData, messageBits):
bitIndex = 0
for each pixel in imageData:
for each channel in [R, G, B]:
if bitIndex < messageBits.length:
channel = (channel & 0xFE) | messageBits[bitIndex]
bitIndex++
return imageData
channel & 0xFE で LSB をクリアし(0xFE = 11111110)、OR 演算でメッセージビットをセットします。
ユースケース
ツール内部のビット操作を正確に理解し、正しく動作しているか検証したい開発者や、別の言語で互換デコーダーを実装したいプログラマー向け。