Vor langer Zeit schrieb ich meinen . Dieser Post war einem sehr interessanten Thema gewidmet: der Steganographie. Natürlich kann die Lösung, die in diesem alten Thema vorgeschlagen wurde, nicht als Steganographie im wahrsten Sinne des Wortes bezeichnet werden. Es handelt sich lediglich um ein Spiel mit Dateiformaten, jedoch ist es trotzdem ein recht interessantes Spiel.
Heute wollen wir etwas tiefer graben und den LSB-Algorithmus betrachten. Wenn Sie interessiert sind, lade ich Sie herzlich dazu ein. (Unter dem Artikel befindet sich etwa ein Megabyte an Daten.)
Zunächst ist es notwendig, eine kleine Einführung zu geben. Allen ist bekannt, dass das Ziel der Kryptographie darin besteht, das Lesen geheimer Informationen unmöglich zu machen. Natürlich hat die Kryptographie ihre Anwendungsbereiche, aber es gibt auch einen anderen Ansatz zum Schutz von Daten. Man kann Informationen nicht verschlüsseln, sondern einfach so tun, als hätten wir keine. Für genau dieses Ziel wurde die Steganographie entwickelt. Wikipedia versichert uns, dass „Steganographie (abgeleitet aus dem Griechischen στεγανοσ — verborgen und γραφω — schreiben, wörtlich ‚geheime Schrift‘) die Wissenschaft von der verborgenen Übertragung von Informationen ist, indem die Tatsache der Übertragung geheim gehalten wird.
Natürlich steht es niemandem im Wege, kryptografische und steganografische Methoden zu kombinieren. Tatsächlich geschieht dies häufig, doch unser Ziel ist es, die Grundlagen zu verstehen. Bei einer genauen Betrachtung des Artikels auf Wikipedia erfährt man, dass in den Algorithmen der Steganografie das sogenannte Container- und Nachrichtenkonzept eine Rolle spielt. Der Container ist jede Art von Information, die hilft, unsere geheime Nachricht zu verbergen.
In unserem Fall wird der Container ein Bild im BMP-Format sein. Zunächst betrachten wir die Struktur dieser Datei. Die Datei kann grob in vier Teile unterteilt werden: den Dateikopf, den Bildkopf, die Palette und das eigentliche Bild. Für unsere Zwecke ist es wichtig zu wissen, was im Kopf gespeichert ist.
Die ersten beiden Bytes des Kopfes sind das Signatur-BM, gefolgt von einem doppelten Wort, das die Dateigröße in Bytes angibt. Die nächsten vier Bytes sind reserviert und sollten Nullen enthalten. Schließlich gibt es in einem weiteren doppelten Wort das Offset von Anfang der Datei bis zu den eigentlichen Bildbytes. In einer 24-Bit-BMP-Datei wird jeder Pixel durch drei Bytes (BGR) codiert.
Jetzt wissen wir, wie wir auf das Bild zugreifen können, nun bleibt zu klären, wie wir die benötigten Informationen dort speichern können. Dafür nutzen wir die LSB-Methode. Das Prinzip dieser Methode besteht darin, dass wir die niedrigstwertigen Bits in den Bytes, die für die Farbcodierung verantwortlich sind, ersetzen. Angenommen, das nächste Byte unserer geheimen Nachricht ist 11001011 und die Bytes im Bild sind …11101100 01001110 01111100 0101100111…, dann würde die Kodierung so aussehen. Wir teilen das Byte der geheimen Nachricht in 4 zwei-Bit-Teile auf: 11, 00, 10, 11, und ersetzen damit die niedrigstwertigen Bits des Bildes: …11101111 01001100 01111110 0101100111…. Diese Änderung ist für das menschliche Auge im Allgemeinen nicht wahrnehmbar. Darüber hinaus werden viele ältere Ausgabegeräte solche geringfügigen Veränderungen möglicherweise nicht einmal darstellen können.
Es ist klar, dass wir nicht nur 2 niedrigstwertige Bits, sondern auch eine beliebige Anzahl davon ändern können. Hier gibt es folgendes Muster: Je mehr Bits wir ändern, desto mehr Informationen können wir verstecken, und desto mehr Störungen werden im ursprünglichen Bild verursacht. Zum Beispiel hier zwei Bilder:


So sehr ich es mir auch gewünscht habe, konnte ich den Unterschied zwischen ihnen nicht feststellen. Dennoch ist im zweiten Bild mithilfe der beschriebenen Methode das Gedicht „Die Jagd nach dem Snark“ von Lewis Carroll versteckt. Wenn Sie bis hierhin gelesen haben, sind Sie sicherlich auch an der Umsetzung interessiert. Diese ist recht einfach, doch ich warne gleich vor, dass alles in Delphi umgesetzt wurde. Dafür gibt es zwei Gründe: 1. Ich halte Delphi für eine gute Programmiersprache; 2. Dieses Programm entstand während der Vorbereitung eines Kurses über Grundlagen der maschinellen Sicht, und die Teilnehmer wissen derzeit nichts anderes als Delphi. Für diejenigen, die mit der Syntax nicht vertraut sind, sei eine Sache erklärt: shl x – bitweiser Shift nach links um x, shr x – bitweiser Shift nach rechts um x.
Wir gehen davon aus, dass wir Text in einen Container schreiben, der in einer Zeichenkette gespeichert ist, und ersetzen die niedrigeren zwei Bytes:
Code zum Schreiben:
for i:=1 to length(str) do
begin
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.Position:=f.Position-1;
tmp:=((tmp shr 2) shl 2)+l1;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Position:=f.Position-1;
tmp:=((tmp shr 2) shl 2)+l2;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Position:=f.Position-1;
tmp:=((tmp shr 2) shl 2)+l3;
f.WriteBuffer(tmp,1);
f.ReadBuffer(tmp,1);
f.Position:=f.Position-1;
tmp:=((tmp shr 2) shl 2)+l4;
f.WriteBuffer(tmp,1);
end;
Code zum Lesen:
for i:=1 to MsgSize do
begin
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);
end;
Und für die ganz Faulen – .
Danke.
Quelle: habr.com
