バイナリデータが画像ピクセルに埋め込まれる仕組み

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 演算でメッセージビットをセットします。

ユースケース

ツール内部のビット操作を正確に理解し、正しく動作しているか検証したい開発者や、別の言語で互換デコーダーを実装したいプログラマー向け。

試してみる — Invisible Watermark

フルツールを開く