かつて私は自分のことを書きました
今日はもう少し深く掘り下げて LSB アルゴリズムを見ていきます。 ご興味がございましたら、ぜひ猫の下へお越しください。 (カットの下にはトラフィックが含まれています: 約 XNUMX メガバイト。)
まず最初に、簡単な紹介をする必要があります。 暗号化の目的は機密情報の読み取りを不可能にすることであることは誰もが知っています。 もちろん、暗号化には応用方法がありますが、データ保護には別のアプローチもあります。 情報を暗号化する必要はありませんが、情報を持っていないふりをします。 まさにこれがステガノグラフィーが発明された理由です。 ウィキペディアは、「ステガノグラフィー(ギリシャ語のστεγανοσ - 隠れた語と、ギリシャ語のγραφω - 私が書く、文字通り「秘密の書き込み」に由来する)は、送信の事実そのものを秘密にすることによって、情報を隠蔽して送信する科学であると保証しています。
もちろん、暗号化手法とステガノグラフィー手法の組み合わせを禁止する人はいません。 さらに、実際にはこれを行っていますが、私たちの仕事は基本を理解することです。 Wikipedia の記事を注意深く調べると、ステガノグラフィー アルゴリズムにはいわゆるステガノグラフィー アルゴリズムが含まれていることがわかります。 コンテナとメッセージ。 コンテナとは、秘密のメッセージを隠すのに役立つ情報です。
この場合、コンテナーは BMP 形式の画像になります。 まず、このファイルの構造を見てみましょう。 ファイルは、ファイル ヘッダー、画像ヘッダー、パレット、画像自体の 4 つの部分に分割できます。 この目的のためには、ヘッダーに何が書かれているかを知る必要があるだけです。
ヘッダーの最初の 4 バイトは BM 署名で、次にファイル サイズ (バイト単位) がダブルワードで書き込まれ、次の 24 バイトは予約されており、ゼロを含める必要があり、最後に別のダブルワードにヘッダーの先頭からのオフセットが含まれます。ファイルを画像の実際のバイトに変換します。 XNUMX ビット bmp ファイルでは、各ピクセルは XNUMX BGR バイトでエンコードされます。
画像にアクセスする方法はわかりましたが、そこに必要な情報を書き込む方法を理解する必要があります。 このためには、LSB 法が必要になります。 このメソッドの本質は次のとおりです。カラー エンコーディングを担当するバイトの最下位ビットを置き換えます。 秘密メッセージの次のバイトが 11001011 で、画像内のバイトが...11101100 01001110 01111100 0101100111... である場合、エンコーディングは次のようになります。 秘密メッセージのバイトを 4 つの 11 ビット部分 (00、10、11、111011) に分割し、画像の下位ビットを結果のフラグメントで置き換えます: ...XNUMX11 01001100 01111110 0101100111…。 このような置き換えは、通常、人間の目には気づきません。 さらに、多くの古い出力デバイスでは、そのような小さな変更を表示することさえできません。
最下位 2 ビットだけでなく、任意の数のビットを変更できることは明らかです。 次のパターンがあります。変更するビットが多いほど、隠せる情報が多くなり、元の画像に生じる干渉も大きくなります。 たとえば、次の XNUMX つの画像があります。
最善の努力にもかかわらず、それらの違いを見ることはできませんでしたが、それでも、説明した方法を使用した 1 番目の画像では、ルイス キャロルの詩「スナーク狩り」が隠されています。 ここまで読んだ方は、おそらく実装について知りたいと思っているでしょう。 非常に単純ですが、すべてが Delphi で行われることをすぐに警告します。 これには 2 つの理由があります。 XNUMX. Delphi は良い言語だと思います。 XNUMX. このプログラムは、コンピュータ ビジョンの基礎に関するコースを準備する過程で生まれました。そして、私がこのコースを教えている人たちは、まだ Delphi 以外のことを知りません。 構文に詳しくない人のために、XNUMX つ説明する必要があります。shl x は x による左へのビット単位のシフトであり、shr x は x による右へのビット単位のシフトです。
文字列に格納されたテキストをコンテナに書き込み、下位 XNUMX バイトを置き換えると仮定します。
録音コード:
for i:=1 から length(str) まで
始まる
l1:=byte(str[i]) shr 6;
l2:=byte(str[i]) shl 2; l2:=l2 shr 6;
l3:=byte(str[i]) shl 4; l3:=l3 shr 6;
l4:=byte(str[i]) shl 6; l4:=l4 shr 6;
f.ReadBuffer(tmp,1);
f.位置:=f.位置-1;
tmp:=((tmp shr 2) shl 2)+l1;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.位置:=f.位置-1;
tmp:=((tmp shr 2) shl 2)+l2;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.位置:=f.位置-1;
tmp:=((tmp shr 2) shl 2)+l3;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.位置:=f.位置-1;
tmp:=((tmp shr 2) shl 2)+l4;
f.WriteBuffer(tmp,1);
終わり
読み取るコード:
for i:=1 から MsgSize を実行します
始まる
f.ReadBuffer(tmp,1);
l1:=tmp shl 6;
f.ReadBuffer(tmp,1);
l2:=tmp shl 6; l2:=l2 shr 2;
f.ReadBuffer(tmp,1);
l3:=tmp shl 6; l3:=l3 shr 4;
f.ReadBuffer(tmp,1);
l4:=tmp shl 6; l4:=l4 shr 6;
str:=str+char(l1+l2+l3+l4);
終わり
さて、本当に怠け者のために -
ありがとう。
出所: habr.com