kotori web solutions Maren Arnhold

PHP: Daten in Bildern verstecken - Steganographie

Nicht immer sind Dateien, denen man im Netz begegnet, vollständig das, wonach sie erscheinen. Dass z. B. Trojaner und andere Schadsoftware sich gerne über Anhänge von Spam-Mails verbreiten, die auf den ersten Blick harmlos und/oder dringlich aussehen, ist inzwischen allgemein bekannt. Nicht so verbreitet allerdings ist das Wissen darüber, dass man in Multimedia-Inhalten, die im Web allgemein üblich und vertraut sind - wie Bildern oder auch Audiodateien - ebenfalls verdeckt Informationen (beispielsweise Texte oder andere Multimediadateien) transportieren kann, was für das Auge bzw. Ohr allerdings nicht oder kaum wahrnehmbar ist. Im Foto eines Kätzchens kann sich so etwa nach geeigneter Rücktransformation ein Kochrezept oder auch das Foto eines Hundewelpen verstecken.


Abb. 1: Die Spree an der Berliner Museumsinsel - ein typisches touristisches Motiv, aber im Bild steckt noch mehr Information. Nämlich der erste Akt von Shakespeares Hamlet. Wie das funktioniert, lesen Sie im Artikel.
Die Bezeichnung für die Technik, Daten in anderen Daten geschickt zu verbergen, lautet Steganographie, ein Kofferwort aus den griechischen Bestandteilen στεγανός ("bedeckt") und γράφειν ("schreiben"), im Grunde also "die Kunst des verdeckten Schreibens". Bereits in der Antike schützte man vertrauliche Botschaften dadurch, dass man sie auf Holztafeln einritzte und auf diese Tafeln eine dicke Wachsschicht aufbrachte, die wiederum einen unverfänglichen Text aufgraviert hatte. Um die Geheimnachricht zu lesen, musste man das Wachs vollständig abschaben. Andere Historiker berichten davon, dass man zu dieser Zeit Sklaven als Nachrichtenübermittler einsetzte, indem ihnen die Köpfe kahlrasiert und Mitteilungen auf die Kopfhaut tätowiert wurden. Sobald das Haar hinreichend dicht nachgewachsen war, schickte man den Kurier zum Empfänger der Information.

Zurück ins 21. Jahrhundert: Steganogramme, der Ausdruck für durch steganographische Methoden eingebettete Informationen, lassen sich in der elektronischen Datenverarbeitung mit Hilfe geeigneter Algorithmen besonders gut in Dateien einbauen, die:

  • erstens eine ausreichende Größe haben, um das Steganogramm zu beherbergen (abhängig vom Algorithmus),
  • zweitens primär zur Wahrnehmung durch Menschen und nicht zur maschinellen Weiterverarbeitung konzipiert sind,
  • somit drittens tolerant gegenüber minimalen Veränderungen sind
  • und schließlich eine hohe informationelle Heterogenität aufweisen (deutliches Grundrauschen; abwechslungsreiche, möglichst wenig gleichförmige Inhalte)

Aus diesen Gründen bieten sich z. B. Steganogramme in Grafikdateien oder auch Filmen sehr an. Wie bereits angedeutet, kann man auch Tonaufzeichnungen als Träger der zusätzlichen Information nutzen, darauf wird aber im folgenden nicht weiter Bezug genommen. Dieses Tutorial demonstriert eine eher primitive Vorgehensweise, um das Prinzip der Einbettung in Bilddateien zu illustrieren. Sie ist ohne Einsatz von Verschlüsselungsalgorithmen weder unempfindlich gegen statistische Angriffe (Steganalyse) noch in jedem Fall robust gegen nachträgliche Veränderungen des Bildes wie etwa Größenänderungen oder Farbtransformationen, soll aber ganz grundlegend zeigen, was bereits mit relativ wenigen Zeilen PHP-Code und einer Bibliothek zur pixelweisen Grafikmanipulation möglich ist.

Das Verfahren, nach dem hier vorgegangen wird, folgt der "least significant bit (LSB)"-Herangehensweise. Das bedeutet, dass die Steganogramme in jene Bits der Transportdatei kodiert werden, deren Veränderung den Gesamteindruck beim Betrachten dieser Transportdatei am wenigsten beeinflusst. Dabei nutzen wir den Umstand, dass die Farbunterscheidungsfähigkeit des menschlichen Sehsinns begrenzt ist.

In Bilddateien mit einer 24-Bit-Farbkodierung werden jeweils ein Byte Speicherplatz für die Rot-, Grün- und Blauwerte jedes einzelnen Pixels als kleinster Einheit der Bildinformation benötigt und verwendet. Entsprechend der additiven Farbmischung kodiert eine Reihe aus 24 Nullen ein absolutes Schwarz, eine Reihe aus 24 Einsen wiederum ein reines Weiß.


Abb. 2: Farbton mit dem hexadezimalen Wert #DC7315, entspricht Rotwert von #DC (dezimal 220), Grünwert von #73 (dezimal 115), Blauwert von #15 (dezimal 21).

Abb. 3: Farbton mit dem hexadezimalen Wert #DB7214, entspricht Rotwert von #DB (dezimal 219), Grünwert von #72 (dezimal 114), Blauwert von #14 (dezimal 20).
Insgesamt sind mit 24 Bit Farbinformation also 224 = 16777216 Farbtöne ansteuerbar, was bei dieser Fülle möglicher Abstufungen schon intuitiv nahelegt, dass Auge und Gehirn bei sehr ähnlichen Farbeindrücken an ihre Grenzen stoßen müssen. Neurowissenschaftler gehen davon aus, dass das Vermögen der Farbunterscheidung beim gesunden Menschen etwa 10 Millionen Farbtöne umfasst, so dass die Menge mit 24 Bit darstellbarer Farben unsere biologischen Gegebenheiten übersteigt (siehe Judd, Deane B.; Wyszecki, Günter (1975). Color in Business, Science and Industry. Wiley Series in Pure and Applied Optics (3rd ed.). New York: Wiley-Interscience. p. 388. ISBN 0-471-45212-2.). Hier ein Beispiel: Abbildung 2 zeigt einen Orangeton, der hexadezimal mit dem Wert #DC7315 kodiert wird, was einem Rotwert von #DC (dezimal 220), Grünwert von #73 (dezimal 115) und Blauwert von #15 (dezimal 21) entspricht. In Abbildung 3 sehen wir einen Orangeton mit dem Wert #DB7214 - er liegt also sowohl im Rot-, Grün- und Blauwert genau um #01 niedriger als in Abbildung 3, was analog zu einer minimalen Abdunklung ist. Können Sie die beiden Farben unterscheiden? Als menschliches Wesen ist dies sehr unwahrscheinlich.

Diese oben geschilderten Umstände soll unser steganographischer Algorithmus also ausnutzen. Gehen wir davon aus, dass wir die Rot-/Grün-/Blau-Werte jedes Pixels beim Einkodieren der Nachricht maximal um 1 modifizieren wollen, so haben wir in jedem Pixel 3 Bit Platz, um Informationen unterzubringen. Ein Bild in einer üblichen Auflösung wie 1024 x 768 Pixel umfasst z. B. 786432 Pixel, die 2359296 Bit kodieren können; bei Textinformationen in 8-Bit-Kodierung wie z. B. ISO-8859-1 können wir folglich einen Datenumfang von 294912 Byte (288 KiB) verstecken; durch geeignete Kompressionsverfahren kann der Datenumfang im Klartext noch erheblich höher liegen.

Der Grundgedanke der Kodierung selbst ist, dass in jedem beliebigen Farbkanal ein dort dezimal gerader Farbwert als binäre Null, ein ungerader Farbwert als binäre Eins aufgefasst werden und diese Binärwerte pro Pixel in der Reihenfolge Rot-Grün-Blau konkateniert werden sollen. Unsere Farbe aus Abbildung 2 hat einen dezimalen Rotwert von 220 (gerade, daher kodiert binär 0), einen Grünwert von 115 (ungerade, kodiert binär 1) und einen Blauwert von 21 (ungerade, kodiert binär 1), so dass jeder Pixel des Bildes in Abbildung 2 als Steganogramm die Binärfolge 011 beschreibt. Bei Abbildung 3 wäre die Binärfolge entsprechend 100.

In beliebigen Eingangsbildern, die als Transportmedium des Steganogramms dienen sollen, verteilen sich die Farben naturgemäß erst einmal chaotisch in gerade und ungerade Werte; also müssen wir als ganz grundlegende Vorbereitung das Bild zunächst dahingehend egalisieren, dass alle Rot-/Grün-/Blau-Kanäle in allen Pixeln nur gerade Werte beherbergen (und somit alle Pixel die binäre Folge 000 kodieren). Es wird später die Abweichung von eben diesem Normzustand sein, die die steganographische Information in sich trägt.

So weit, so gut. Wie lösen wir das nun in PHP? Wichtigstes Hilfsmittel ist hier zunächst einmal die GD-Library (siehe auch http://de.wikipedia.org/wiki/GD_Library), die mit PHP seit Version 4.3 bereits standardmäßig gebündelt vertrieben wird und es gestattet, Bilddateien als Objekte umfangreichen und sehr spezifischen Eingriffen zu unterziehen. Für gegebenenfalls gewünschte Komprimierung und/oder Verschlüsselung der Eingangstexte sind weiterhin die Libraries zlib, mcrypt und mhash nützlich.

Es bietet sich weiterhin an, die steganographische Funktionalität als eigene Klasse zu formulieren, die entsprechende Methoden zur Eingabe und Ausgabe von Bilddateien sowie der Kodierung und Dekodierung von Steganogrammen zur Verfügung stellt. Eine Klasse, die diese Anforderungen erfüllt, können Sie hier herunterladen oder im folgenden Codeabschnitt auch ansehen. Einzelne Methoden der Klasse werden dann im weiteren Verlauf noch näher besprochen.

Download kotoristegano-0.67.inc.php:     Quellcode - 12 KiB     .tar.gz - 3,5 KiB     .zip - 3,5 KiB

Die Verwendung von Steganographie und Kryptographie ist nach deutscher Gesetzgebung legal, was aber nicht 
für alle Staaten gleichermaßen zutreffen muss. Informieren Sie sich vor dem Einsatz der hier geschilderten 
Kenntnisse bitte über Ihre lokale Rechtslage. kotori web solutions Maren Arnhold übernimmt in keiner Form die 
Haftung für Folgen jedweder Art, die Ihnen oder anderen Personen durch die Verwendung dieser 
Steganographieklasse entstehen. Mit Download und Anwendung des Codes erklären Sie sich mit diesen 
Bedingungen ausdrücklich als einverstanden.

Diese Klasse (Stand: Version 0.67, 19. Oktober 2012) lässt sich per include in bestehende PHP-Programme einbinden und stellt zwei öffentliche Methoden zur Verfügung, die jeweils zum Kodieren und Dekodieren von Steganogrammen dienen. Als Eingangsdaten für das Kodieren werden JPEG- und PNG-Dateien akzeptiert, die Ausgabe des Steganogramms erfolgt in PNG, auch die Eingabedateien zum Zweck des Dekodierens müssen PNG-Format haben. Hier die Encode-Methode:

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
<?php
 
include "kotoristegano-0.67.inc.php";
 
/*
 
Parameters:
 
$ciphertext	string				Dateiname inkl. Pfad des Eingangstextes
$masterImage	string				Dateiname inkl. Pfad des Eingangsbildes
$visualize	0=false (Standard), 1=true	Diagnostikmodus
$compress	0=false (Standard), 1=true	Komprimieren des Eingangstextes
$encrypt	0=false (Standard), 1=true	AES-256-Verschlüsselung des Eingangstextes
$passphrase	string				Schlüsselphrase
$vertical	0=false (Standard), 1=true	Wenn true, kodiere spaltenweise; wenn false, zeilenweise
 
*/
 
$ko = new KotoriStegano();
$ko->encode($cipherText,$masterImage,$visualize,$compress,$encrypt,$passphrase,$vertical);
 
?>

Die Decode-Methode nimmt etwas unterschiedliche Parameter an:

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
<?php
 
include "kotoristegano-0.67.inc.php";
 
/*
 
Parameters:
 
$decodeImage	string				Dateiname inkl. Pfad des Eingangsbildes
$verbose	0=false (Standard), 1=true	Direkte Ausgabe der Dekodierung auf der Konsole
$compress	0=false (Standard), 1=true	Dekomprimieren des Ausgangstextes
$encrypt	0=false (Standard), 1=true	AES-256-Entschlüsselung des Ausgangstextes
$passphrase	string				Schlüsselphrase
$vertical	0=false (Standard), 1=true	Wenn true, dekodiere spaltenweise; wenn false, zeilenweise
 
*/
 
$ko = new KotoriStegano();
$outputText = $ko->decode($decodeImage,$verbose,$compress,$decrypt,$passphrase,$vertical);
 
?>

Intern rufen beide Methoden nach ihrem Aufruf weitere klassen- und kindklasseninterne (protected) Methoden auf, die schrittweise die eigentliche Arbeit übernehmen. Elementar für die Kodierung ist dabei die hideText()-Methode, die fast dieselben Parameter wie die nach außen sichtbare encode()-Methode verwendet. Sie bezieht die eigentlichen Bilddaten aus der protected Objektvariable $img_data. hideText() übernimmt dann gegebenenfalls zunächst die Verschlüsselung des Eingangstextes gemäß AES-256 und/oder die gz-Komprimierung, bevor überprüft wird, ob die modifizierte oder auch unmodifizierte Nachricht überhaupt, abhängig von der Größe des Bildes, in diesem Platz finden kann. Anschließend wird das Bild mittels makeEvenPixels(), wie oben beschrieben, auf rein gerade Farbwerte egalisiert.

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
protected function hideText($msg,$visualize,$compress,$encrypt,$passphrase,$vertical) {
 
/* Hide text in picture */
$img = $this->img_data;
 
/* Encrypt string with AES-256 and passphrase SHA256 hash, if applicable */
if ($encrypt == 1) { 
 
	$encrypt_key = mhash(MHASH_SHA256,$passphrase); 
	$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
	$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
	$msg = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $encrypt_key, $msg, MCRYPT_MODE_ECB, $iv);
 
};
 
/* Compress string if appropriate flag is set. */
if ($compress == 1) { $msg = gzdeflate($msg,9);	};
 
/* Is it possible to fit the ciphertext into this image? If not, stop here. */
$pixel_sum = ($this->img_size_width)*($this->img_size_height);
 
/* Three channels per pixel. */
$pixel_sum = $pixel_sum * 3;
 
/* 8 bit per character. */
$text_length_binary = strlen($msg)*8;
 
/* Exit if image is too small */
if ( $pixel_sum < $text_length_binary ) { die ("Image too small for ciphertext. Exiting."); } 
 
/* Equalize pic */
$this->makeEvenPixels();

Die Nachricht muss nun binär kodiert werden. Dafür wird sie zeichenweise durchlaufen und mittels der ord()-Funktion seriell konvertiert. Da decbin führende Nullen standardmäßig nicht ausgibt, müssen wir diese außerdem noch auffüllen, bevor das Ergebnis an den Ausgabebinärstring angehängt wird - sonst bekommen wir beim Dekodieren Probleme mit dem Abgrenzen der einzelnen Bytes.

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
$msgcounter = 0;
$msg_bin = "";
 
/* Go through ciphertext, converting each char to its binary value */
while (isset($msg[$msgcounter])){
 
	$binary_value = decbin(ord($msg[$msgcounter]));
 
	/* Preserve leading zeroes */
 
	$binary_value = substr("00000000",0,8 - strlen($binary_value)) . $binary_value;
 
	$msg_bin .= $binary_value;
 
	$msgcounter++;
 
}


Abbildung 4: Aktivierter Diagnostikmodus beim spaltenweisen Einbetten mittels des visualize-Parameters. Keine Verschlüsselung oder Kompression, wie an den gelben horizontalen Linienartefakten abzulesen ist. Beim zeilenweisen Einbetten verlaufen sie vertikal; ihr Entstehen ist in der ASCII-Kodierung und dem daraus folgenden Umstand begründet, dass alle neun Pixel mit deutlich erhöhter Wahrscheinlichkeit die Bitfolge 110 (gelb) einkodiert wird.
Abhängig davon, ob der Kodierungsvorgang spalten- oder zeilenweise durchlaufen werden soll, findet nun das eigentliche Einbetten der Nachricht statt. Pixel für Pixel wird zunächst der Rot-, dann der Grün- und der Blauwert isoliert (binäres Rechtsschieben um 16, 8 oder 0 Bit, danach AND-Verknüpfung mit binär 11111111) und je nach der aktuellen Stelle im Binäreingabestring modifiziert (genauer gesagt, um 1 inkrementiert).

Der visualize-Parameter erlaubt es außerdem für demonstrative oder diagnostische Zwecke, keine wirkliche Einbettung vorzunehmen, sondern eine direkte farbliche Repräsentation der Binärdaten anzuzeigen, so dass etwa die Binärfolge 100 ein Rot, 010 ein Grün, 110 ein Gelb etc. ergibt. Auf diese Weise kann man z. B. ermitteln, wie groß der Anteil des Bildes ist, der von der Einbettung des Textes bereits in Anspruch genommen wird, sprich: der benutzte und verbleibende Speicherplatz.

In Abbildung 4 ist der Fall zu sehen, dass bereits etwa 72 Prozent der Kapazität des Bildes benutzt worden sind (der Steganotext ist übrigens diesmal Goethes Werther). In diesem Beispiel wurden die Daten spaltenweise einkodiert und weder Verschlüsselung noch Kompression eingesetzt, wie an den gelben horizontalen Linienartefakten abzulesen ist. Beim zeilenweisen Einbetten verlaufen sie vertikal; ihr Entstehen ist in der ASCII-Kodierung und dem daraus folgenden Umstand begründet, dass alle neun Pixel mit deutlich erhöhter Wahrscheinlichkeit die Bitfolge 110 (gelb) einkodiert wird. Wenn wir die Daten verschlüsseln oder packen, verschwinden die Linien augenblicklich und weichen einer diffusen Farbverteilung (Abbildung 5).

Hier die Fortsetzung des Codes:

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
$msgcounter = 0;
 
if ($vertical == 0) { 
 
	$axis_1 = $this->img_size_height;
	$axis_2 = $this->img_size_width;
 
} else { 
 
	$axis_1 = $this->img_size_width;
	$axis_2 = $this->img_size_height;
 
};
 
for($y=0;$y<$axis_1;$y++){
 
	for($x=0;$x<$axis_2;$x++){
 
 
		if ($visualize != 1) {
 
			/* Standard mode. Don't visualize encoding. */
 
			if ($vertical == 0) { $img_original_color = imagecolorat($img,$x,$y); };
			if ($vertical == 1) { $img_original_color = imagecolorat($img,$y,$x); };
 
			$r = ($img_original_color >> 16) & 0xFF;
			$g = ($img_original_color >> 8) & 0xFF;
			$b = $img_original_color & 0xFF;
 
			/* Increment this pixel's red byte by the current value from the binary string */
			if (isset($msg_bin[$msgcounter])) { $r += $msg_bin[$msgcounter]; };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Increment this pixel's green byte by the current value from the binary string */
			if (isset($msg_bin[$msgcounter])) { $g += $msg_bin[$msgcounter]; };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Increment this pixel's blue byte by the current value from the binary string */
			if (isset($msg_bin[$msgcounter])) { $b += $msg_bin[$msgcounter]; };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Modify pixel now */
			$img_modified_color = imagecolorallocate($img, $r, $g, $b);
			if ($vertical == 0) { imagesetpixel($img, $x, $y, $img_modified_color); };
			if ($vertical == 1) { imagesetpixel($img, $y, $x, $img_modified_color); };
 
		} else {
 
			/* Do visualize encoding for diagnostic and demonstrative purposes */
 
			if ($vertical == 0) { $img_original_color = imagecolorat($img,$x,$y); };
			if ($vertical == 1) { $img_original_color = imagecolorat($img,$y,$x); };
 
			$r = ($img_original_color >> 16) & 0xFF;
			$g = ($img_original_color >> 8) & 0xFF;
			$b = $img_original_color & 0xFF;
 
			/* Set pixel's red byte to &#FF if binary digit is 1, else set to &#00. */
			if (isset($msg_bin[$msgcounter])) { if ($msg_bin[$msgcounter] == "1") { $r = 255; } 
			else { $r = 0; };  };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Set pixel's green byte to &#FF if binary digit is 1, else set to &#00. */
			if (isset($msg_bin[$msgcounter])) { if ($msg_bin[$msgcounter] == "1") { $g = 255; } 
			else { $g = 0; };  };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Set pixel's blue byte to &#FF if binary digit is 1, else set to &#00. */
			if (isset($msg_bin[$msgcounter])) { if ($msg_bin[$msgcounter] == "1") { $b = 255; }
			else { $b = 0; };  };
 
			/* Advance to next binary digit */
			$msgcounter++;
 
			/* Modify pixel now */
			$img_modified_color = imagecolorallocate($img, $r, $g, $b);
			if ($vertical == 0) { imagesetpixel($img, $x, $y, $img_modified_color); };
			if ($vertical == 1) { imagesetpixel($img, $y, $x, $img_modified_color); };
 
		}
 
	}
 
}
 
$this->img_data = $img;
 
}


Abbildung 5: Dieselbe Nachricht wie in Abbildung 4, mit dem Key testschluessel verschlüsselt. Die Linienartefakte sind verschwunden.
Mit der exportPng()-Methode kann das Steganogramm anschließend im PNG-Format direkt im Browserfenster ausgegeben werden.

Die Dekodierung eines Steganogramms findet intern hauptsächlich über die extractText()-Funktion statt. Diese tut wieder nichts anderes, als gemäß der ursprünglichen Kodierungsrichtung - spalten- oder zeilenweise - den Modulo 2 aller Farbwerte pro Pixel zu errechnen, was genau der Binärkodierung des Eingangstextes entspricht, diese Bits in einem großen String aneinanderzureihen und diesen String schließlich als Rückgabewert zu liefern. Gegebenenfalls wird die Zeichenkette vorher noch entpackt und dann entschlüsselt (die umgekehrte Reihenfolge der Vorgehensweise beim Einbetten). Auf den Output kann von außen entweder über den Rückgabewert der decode()-Methode zugegriffen werden, oder er wird über den verbose-Parameter direkt auf die Konsole ausgegeben.

Die extractText()-Methode im Überblick:

01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
protected function extractText($compress,$decrypt,$passphrase,$vertical){
 
	/* Extract text from picture */
 
	$img = $this->img_data;
 
	$decoded_text_ascii = "";
	$decoded_text_bin = "";
 
	if ($vertical == 0) { 
 
		$axis_1 = $this->img_size_height;
		$axis_2 = $this->img_size_width;
 
	} else { 
 
		$axis_1 = $this->img_size_width;
		$axis_2 = $this->img_size_height;
 
	};
 
	for($y=0;$y<$axis_1;$y++){
 
		for($x=0;$x<$axis_2;$x++){
 
			if ($vertical == 0) { $img_original_color = imagecolorat($img,$x,$y); };
			if ($vertical == 1) { $img_original_color = imagecolorat($img,$y,$x); };
			$r = ($img_original_color >> 16) & 0xFF;
			$g = ($img_original_color >> 8) & 0xFF;
			$b = $img_original_color & 0xFF;
 
			$decoded_text_bin .= ($r % 2);
			$decoded_text_bin .= ($g % 2);
			$decoded_text_bin .= ($b % 2);
 
		}
 
	}
 
	$decoded_text_ascii_array = str_split ( $decoded_text_bin, 8 );
 
	foreach ($decoded_text_ascii_array as $da) {
 
		$decoded_text_ascii .= chr(bindec($da));
 
	}
 
 
	/* If compressed flag is set, decompress message */
	if ($compress == 1){ $decoded_text_ascii = gzinflate($decoded_text_ascii); };
 
	/* If decrypt flag is set, decrypt message */
	if ($decrypt == 1){ 
 
		$encrypt_key = mhash(MHASH_SHA256,$passphrase); 
		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
		$decoded_text_ascii = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $encrypt_key, 
						$decoded_text_ascii, MCRYPT_MODE_ECB, $iv);
 
	};
 
	return $decoded_text_ascii;
 
}

Die vorliegende Klasse kann natürlich theoretisch noch um vieles erweitert werden: verschiedene Verschlüsselungsverfahren und Kodierungsrichtungen, Unterstützung für weitere Bildformate oder auch um ein überhaupt gegen Bildmanipulationen robusteres Einbettungsverfahren. Einiges davon steht bereits auf der Liste für spätere Versionen, es gibt aber sicherlich noch viele denkbare nützliche Features, so dass sich die Klasse als Anregung und Startpunkt für eigene Programmiertätigkeit versteht.

Noch einmal: Die Verwendung von Steganographie und Kryptographie ist nach deutscher Gesetzgebung legal, was aber nicht für alle Staaten gleichermaßen zutreffen muss. Informieren Sie sich vor dem Einsatz der hier geschilderten Kenntnisse bitte über Ihre lokale Rechtslage. kotori web solutions Maren Arnhold übernimmt in keiner Form die Haftung für Folgen jedweder Art, die Ihnen oder anderen Personen durch die Verwendung dieser Steganographieklasse entstehen. Mit Download und Anwendung des Codes erklären Sie sich mit diesen Bedingungen ausdrücklich als einverstanden.

Autorin: Maren Arnhold



ANZEIGE
kotori web solutions Maren Arnhold bietet einen Komplettservice rund um Webdesign, Webprogrammierung und Webhosting. Suchen Sie nach einer Lösung für Ihre private Homepage? Möchten Sie ein eigenes Blog betreiben und suchen dafür ein geeignetes CMS und entsprechenden Webspace? Oder interessieren Sie sich für E-Commerce und benötigen einen Webshop? Dann sollten wir uns kennenlernen - eine kostenlose Erstberatung ist selbstverständlich!
© 2025 kotori web solutions Maren Arnhold. Alle Rechte vorbehalten/All rights reserved.