2D-Grafik Steganographie - Verschlüsselung von Dateien in Bildern - Bilder zeigen schwarze Rechtecke

chaostheory

Bekanntes Mitglied
Hallo,
ich habe ein Programm zur Steganographie geschrieben, das Dateien in Bildern verstecken kann. Akzeptiert wird jede Datei, das Bild muss ein .png sein, da nur dieses Format einen echten Alpha-Channel hat.
Verschlüsselung funktioniert so : Ein Pixel besteht ja aus 4 Bytes (Rot, Grün, Blau, Alpha). Die zu verschlüsselnde Datei wird bitweise durchgegangen, das Bild byteweise. Ist das Datei-Bit gesetzt (1) wird das Bild-Byte um 1 erhöht (bzw. um 1 subtrahiert, wenn es nicht mehr erhöht werden kann), ist das Bit nicht gesetzt (0) bleibt das Byte so.
Auf diese Weise kann man ein Byte in zwei Pixeln verschlüsseln und die Farben sollten sich eigentlich nicht sichtbar verändern, da man eine Farbkomponente ja nur um 1/255 ändert.
Inzwischen funktioniert die Verschlüsselung und Entschlüsselung wunderbar, allerdings ist der verschlüsselte Bereich des Bildes von schwarzen Pixeln durchzogen, womit die Veränderung des Bildes sofort auffällt.
Entdeckt vielleicht einer von euch den Fehler? 🙂
Ein Punkt könnte die Tatsache sein, dass Java ja nur Datentypen mit Vorzeichen kennt und deswegen eine Farbkomponente von -127 bis +128 gespeichert wird anstatt von 0 bis 255. Allerdings sollte das kein Problem darstellen, oder?
Hier sieht man das Resultat mit den falschen Pixeln am oberen Rand. Beim Uploader werden diese komischerweise weiß dargestellt.
Codierung:
Java:
public void encode(File sourceFile, BufferedImage keyImage, File targetFile) {
    	if(sourceFile == null || keyImage == null) throw new IllegalArgumentException("Arguments are not allowed to be null.");
    	if(targetFile.isDirectory()) throw new IllegalArgumentException("Target has to be a non-directory file.");
    	if(!sourceFile.exists() || sourceFile.isDirectory()) throw new IllegalArgumentException("Source has to be an existing non-directory file.");    	
    	//+ 8 for the length long and *2 because one pixel can only store a half byte
    	if((sourceFile.length() + 8) * 2 > keyImage.getWidth() * keyImage.getHeight()) throw new IllegalArgumentException("Key image is too small.");    	
    	
    	BufferedImage targetImage = new BufferedImage(keyImage.getWidth(), keyImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
    	copyImage(keyImage, targetImage);
    	
    	byte[] fileDataBytes = fileHandler.getFileBytes(sourceFile);
    	byte[] fileLengthBytes = binary.longToByteArray(sourceFile.length());
    	//Writing the file name: int for the string length, then the string bytes
    	byte[] stringBytes = sourceFile.getName().getBytes();
    	byte[] stringLengthBytes = binary.intToByteArray(stringBytes.length);
    	
    	//Writing the length as long --> 8 bytes
    	int index = 0;
    	
    	encodeBytesToImage(stringLengthBytes, targetImage, index);
    	index += stringLengthBytes.length * 2;
    	
    	encodeBytesToImage(stringBytes, targetImage, index);
    	index += stringBytes.length * 2;
    	
    	encodeBytesToImage(fileLengthBytes, targetImage, index);
    	index += fileLengthBytes.length * 2;
    	
    	encodeBytesToImage(fileDataBytes, targetImage, index);
    	
    	/*System.out.println("Encoded name: " + new String(stringBytes));
    	System.out.println("Encoded length: " + sourceFile.length());*/
    	try {
			ImageIO.write(targetImage, "png", targetFile);
		} catch (IOException e) {
			e.printStackTrace();
			gui.showErrorMessage("IO-Fehler", "Fehler beim Schreiben der Bilddatei.");
		}
    	
    	//System.out.println("Image encoding successfull");
    }
    
    private void encodeBytesToImage(byte[] data, BufferedImage image, int offset) {
    	for(int i = 0; i < data.length * 2; i += 2) {
    		encodeByteToImage(data[i / 2], image, i + offset);
    	}
    }
    
    private void encodeByteToImage(byte data, BufferedImage image, int index) {
    	Point pixel = getPointFromIndex(index, image.getWidth(), image.getHeight());
		image.setRGB(pixel.x, pixel.y, encodeHalfByteToPixel(image.getRGB(pixel.x, pixel.y), data, 0));
		pixel = getPointFromIndex(index + 1, image.getWidth(), image.getHeight());
		image.setRGB(pixel.x, pixel.y, encodeHalfByteToPixel(image.getRGB(pixel.x, pixel.y), data, 4));
    }
    
    private int encodeHalfByteToPixel(int rgb, byte value, int offset) {
    	if(offset != 0 && offset != 4) throw new IllegalArgumentException("Offset has to be 0 or 4.");
    	
    	byte[] colorBytes = binary.intToByteArray(rgb);
    	for(int i = 0; i < 4; i++) {
    		if(binary.isBitSet(value, i + offset)) colorBytes[i] = (byte) (colorBytes[i] > -128 ? colorBytes[i] + 1 : colorBytes[i] - 1);
    	}
    	
    	return binary.byteArrayToInt(colorBytes);
    }
Decodierung:
Java:
public void decode(BufferedImage sourceImage, BufferedImage keyImage, File targetDirectory) {
    	if(sourceImage == null || keyImage == null) throw new IllegalArgumentException("Arguments are not allowed to be null.");
    	if(!targetDirectory.isDirectory()) throw new IllegalArgumentException("Target has to be a directory.");
    	
    	byte[] fileDataBytes;
    	long fileLength;
    	int fileNameLength;
    	String fileName = null;
    	
    	int index = 0;
    	
    	fileNameLength = binary.byteArrayToInt(decodePixels(sourceImage, keyImage, BinaryOperations.BYTES_INT, index));
    	index += BinaryOperations.BYTES_INT * 2;
    	
    	fileName = new String(decodePixels(sourceImage, keyImage, fileNameLength, index));
    	index += fileNameLength * 2;
    	
    	fileLength = binary.byteArrayToLong(decodePixels(sourceImage, keyImage, BinaryOperations.BYTES_LONG, index));
    	index += BinaryOperations.BYTES_LONG * 2;
    	
    	fileDataBytes = decodePixels(sourceImage, keyImage, (int) fileLength, index);
    	
    	File targetFile = new File(targetDirectory.getPath() +  "/" + fileName);
    	
    	fileHandler.writeBytesToFile(targetFile, fileDataBytes);
    	
    	/*System.out.println("Decoded length: " + fileLength);
    	System.out.println("Decoded file " + targetFile);
    	System.out.println("Image decoding successfull");*/
    }
    
    private byte[] decodePixels(BufferedImage sourceImage, BufferedImage keyImage, int length, int offset) {
    	byte[] data = new byte[length];
    	for(int i = offset; i < length * 2 + offset; i += 2) {
    		Point pixel = getPointFromIndex(i, sourceImage.getWidth(), sourceImage.getHeight());
    		int firstKey, firstMessage, secondKey, secondMessage;
    		firstKey = keyImage.getRGB(pixel.x, pixel.y);
    		firstMessage = sourceImage.getRGB(pixel.x, pixel.y);
    		pixel = getPointFromIndex(i + 1, sourceImage.getWidth(), sourceImage.getHeight());
    		secondKey = keyImage.getRGB(pixel.x, pixel.y);
    		secondMessage = sourceImage.getRGB(pixel.x, pixel.y);
    		data[(i - offset) / 2] = decodeTwoPixels(firstKey, firstMessage, secondKey, secondMessage);
    	}
    	return data;
    }
    
    private byte decodeTwoPixels(int firstKey, int firstMessage, int secondKey, int secondMessage) {
    	byte[] firstKeyBytes = binary.intToByteArray(firstKey), firstMessageBytes = binary.intToByteArray(firstMessage);
    	byte[] secondKeyBytes = binary.intToByteArray(secondKey), secondMessageBytes = binary.intToByteArray(secondMessage);
    	byte result = 0;
    	for(int i = 0; i < 4; i++) {
    		result = binary.setBit(result, i, firstKeyBytes[i] != firstMessageBytes[i] ? true : false);
    	}
    	for(int i = 4; i < 8; i++) {
    		result = binary.setBit(result, i, secondKeyBytes[i - 4] != secondMessageBytes[i - 4] ? true : false);
    	}
    	return result;
    }
 
Hi,

habe mir den Code nun nicht angeschaut. Kann nur einen kleinen Tipp geben.
Inzwischen funktioniert die Verschlüsselung und Entschlüsselung wunderbar, allerdings ist der verschlüsselte Bereich des Bildes von schwarzen Pixeln durchzogen, womit die Veränderung des Bildes sofort auffällt.
[…]
Hier sieht man das Resultat mit den falschen Pixeln am oberen Rand. Beim Uploader werden diese komischerweise weiß dargestellt.
Das deutet darauf hin, dass es sich um transparente (und nicht um schwarze oder weiße) Pixel handelt.
Das eine Mal hast du das Bild nur auf schwarzem Hintergrund betrachtet (z. B. Firefox), kann das sein?
 
Ist das Datei-Bit gesetzt (1) wird das Bild-Byte um 1 erhöht (bzw. um 1 subtrahiert, wenn es nicht mehr erhöht werden kann), ist das Bit nicht gesetzt (0) bleibt das Byte so.
Auf diese Weise kann man ein Byte in zwei Pixeln verschlüsseln und die Farben sollten sich eigentlich nicht sichtbar verändern, da man eine Farbkomponente ja nur um 1/255 ändert.
Die Verwendung des Alphakanals ist viel zu auffällig. Grund: Die meisten "unverdächtigen" Bilder haben auf ihrem jeweiligen Alphakanal eine viel zu niedrige Entropie, um darin irgendetwas zu verstecken. Bei praktisch allen Fotos beträgt sie sogar 0, sprich: Wenn bei einem Foto, das eigentlich vollständig opak sein müsste, auch nur ein Pixel nur ein kleines bisschen transparent ist, fällt das auf, und zwar richtig.

Darüber hinaus verstehe ich nicht so ganz, wie du mit dem von dir gewählten Verfahren eindeutig (de-)kodieren willst. Nehmen wir mal an, der Decoder bekommt auf dem Rot-Kanal die Zahl 254 vorgesetzt. War das ursprüngliche Bit gesetzt, und der Encoder subtrahierte deshalb 1 von 255? Oder war das ursprüngliche Bit gelöscht, und der Encoder behielt den Wert 254 deshalb bei?

Dieses Entscheidungsproblem könnte man damit lösen, dass Sender und Empfänger das ursprüngliche Bild kennen. Aber dann kannst du jedes Bild nur einmal verwenden, weil es zu auffällig wäre, wenn sich zwei Kommunikationspartner die ganze Zeit das scheinbar immer gleiche Bild zuspielen. 😉 Und wenn du jedes Bild doppelt schickst (einmal das Original und einmal das Bild mit der Nachricht), fällt das ja ebenso auf.

Ein Ansatz für einen Ausweg aus diesem Dilemma wäre z.B., das Bild in zwei verschiedenen Ausführungen zu senden: Einmal das "Originalbild" und einmal eine skalierte Version, z.B. als Skizze ("Thumbnail"), wobei nur eines der beiden Bilder (wahrscheinlich die Skizze) die Nachricht enthält, und der Empfänger erst das Originalbild auf Thumbnail-Größe herunterskalieren muss, um beide Bilder vergleichen und so die Nachricht extrahieren zu können.

Aber das macht das alles nur ein kleines bisschen unauffälliger und kann bei größeren Nachrichten viele Bilder erfordern. Da wäre es wohl viel einfacher, eine geeignetere Kodierung zu wählen.

Ark
 
Zuletzt bearbeitet:
Den Alphakanal zu nutzen ist nicht perfekt, ich weiß, aber zum einen kann man so sehr komfortabel ein Byte in exakt zwei Pixel codieren und zum anderen fällt eine Veränderung von 1/265 in einem von Millionen Pixeln doch wohl nicht auf.
In diesem Bild habe ich ich ein 131kb großes Word-Dokument verschlüsselt, erkennst du irgendetwas auffälliges? Man sieht allenfalls bei sehr starkem Zoom, das oben ein leichtes Rauschen vorhanden ist.

Problematisch wird es bei Schwarzwerten, wie dieses Bild belegt:
4aac2w7py9iy.png

Grundsätzlich funktioniert die Methode nur bei Fotos und nicht bei erstellten Grafiken, die echte Schwarzwerte aufweisen.

Zu deiner Frage: Beim Entschlüsseln (Wofür natürlich beide Bilder benötigt werden) wird lediglich ein != Vergleich durchgeführt. Die Unterscheidung +1 oder -1 beim Codieren ist lediglich um zu vermeiden, dass bei einem Wert von 255 noch mal addiert wird, was ja nicht geht.
Bei einer Skalierung würdest du wahrscheinlich die Daten zerstören, es sei denn du besitzt einen Skalierfilter, der auch nach Rundungen perfekte Umkehrfunktionen bietet. Und den gibt es doch nicht, oder?
Die Sache mit dem einen Bild ständig hin und her schicken kann man sehr leicht lösen. Du kannst deinem Freund einfach einen ganzen USB-Stick voller Bilder geben und ihm die codierten Pendants per Internet schicken. Da die Namen ja gleich bleiben kann er sofort den passenden Schlüssel suchen und niemand merkt etwas.
Noch mal zum Alphakanal: Das ganze habe ich auch mit jpegs getestet. Obwohl die ja keine Transparenz unterstützen schreibt Javas ImageIO das irgendwo mit rein. Somit werden nur noch die Farbänderungen angezeigt, die vom Menschen wohl kaum zu sehen sind- solange man nicht explizit danach sucht.
 
Grundsätzlich funktioniert die Methode nur bei Fotos und nicht bei erstellten Grafiken, die echte Schwarzwerte aufweisen.
Macht dies das Verfahren nicht hinfällig?
Wenn ich das richtig verstanden habe, geht es bei Steganografie darum, dass man keine Kenntnis über die verschlüsselte Nachricht hat. Ein Foto im PNG-Format ist allerdings verdächtig genug.
 
Macht dies das Verfahren nicht hinfällig?
Wenn ich das richtig verstanden habe, geht es bei Steganografie darum, dass man keine Kenntnis über die verschlüsselte Nachricht hat. Ein Foto im PNG-Format ist allerdings verdächtig genug.

Bei Steganographie geht es darum, dass man noch nicht einmal merkt, dass überhaupt etwas verschlüsselt wurde und nicht darum die verschlüsselte Nachricht unlesbar zu machen (Kryptographie).
In meinem letzten Post habe ich übrigens geschrieben, dass es auch mit .jpegs klappt. Zudem kann man ja auch jede beliebige Grafik nehmen, die nicht echte schwarze Pixel hat (Cartoons, Screenshots, Bilder von 3D-Modelle usw.).
 
Afaik macht ma das ganze so: Man hat einen bestimmten Schlüssel und dieser bestimmt die Abstände der manipulierten Pixel (eventuell sogar noch den Farbkanal). Bei den manipulierten Pixeln wird das LSB mit einem Bit der Nachricht überschrieben. Hat man jetzt den Schlüssel kann man sich aus diesen Bits die Nachricht zusammenbasteln.
 
Afaik macht ma das ganze so: Man hat einen bestimmten Schlüssel und dieser bestimmt die Abstände der manipulierten Pixel (eventuell sogar noch den Farbkanal). Bei den manipulierten Pixeln wird das LSB mit einem Bit der Nachricht überschrieben. Hat man jetzt den Schlüssel kann man sich aus diesen Bits die Nachricht zusammenbasteln.

Das ist so ziemlich exakt das was ich mache, nur dass ich keine Abstände zwischen den Pixeln lasse.
 
Den Alphakanal zu nutzen ist nicht perfekt, ich weiß, aber zum einen kann man so sehr komfortabel ein Byte in exakt zwei Pixel codieren und zum anderen fällt eine Veränderung von 1/265 in einem von Millionen Pixeln doch wohl nicht auf.
Na, und wie die auffällt. Schau dir mal das Alpha-Histogramm an, da gibt's bei 254 eine Erhöhung, die da nicht sein dürfte; allein dass dieses Bild einen Alpha-Kanal mitbringt, ist schon seltsam. Und schon mit simplen Werkzeugen wie GIMP (Layer → Transparency → Threshold Alpha → Threshold: 254) hat man ganz schnell ein verdächtiges da regelmäßiges Muster am Anfang des Bildes sichtbar gemacht.

Problematisch wird es bei Schwarzwerten, wie dieses Bild belegt:
4aac2w7py9iy.png

Grundsätzlich funktioniert die Methode nur bei Fotos und nicht bei erstellten Grafiken, die echte Schwarzwerte aufweisen.
Das sieht sehr nach einem Unterlauf aus.

Mein Tipp: Rechne nicht +1 oder -1, sondern setz oder lösch das jeweils unterste Bit entsprechend der Nachricht. (Ich sehe gerade, dass bERt0r das schon geschrieben hat.) Dann braucht der Empfänger auch kein Vergleichsbild. Die Nachricht solltest du vor dem Einbetten außerdem noch komprimieren und/oder (symmetrisch) verschlüsseln, um die Entropie der Nachricht zu erhöhen. Denn die regelmäßigen Strukturen sind verdammt auffällig! Auch das abrupte Ende des Musters fällt auf, du solltest also noch die verbleibenden Pixel, die nicht zur Nachricht gehören, mit starken Zufallszahlen bearbeiten, als wären diese Zufallszahlen Teil der Nachricht.
Bei einer Skalierung würdest du wahrscheinlich die Daten zerstören, es sei denn du besitzt einen Skalierfilter, der auch nach Rundungen perfekte Umkehrfunktionen bietet. Und den gibt es doch nicht, oder?
Ich meinte das so, dass die Nachricht in das bereits skalierte Bild eingebettet werden sollte. Wenn dann der Empfänger das große Originalbild mit dem gleichen Algorithmus auf die gleiche Größe skaliert, hat er dann ein perfektes Vergleichsbild.

Die Sache mit dem einen Bild ständig hin und her schicken kann man sehr leicht lösen. Du kannst deinem Freund einfach einen ganzen USB-Stick voller Bilder geben und ihm die codierten Pendants per Internet schicken. Da die Namen ja gleich bleiben kann er sofort den passenden Schlüssel suchen und niemand merkt etwas.
Das wäre natürlich eine Möglichkeit.

Noch mal zum Alphakanal: Das ganze habe ich auch mit jpegs getestet. Obwohl die ja keine Transparenz unterstützen schreibt Javas ImageIO das irgendwo mit rein. Somit werden nur noch die Farbänderungen angezeigt, die vom Menschen wohl kaum zu sehen sind- solange man nicht explizit danach sucht.
Ich weiß nicht, ob JPEG irgendwie Alpha unterstützt, aber selbst dann fällt es womöglich auf, dass ein Alpha-Kanal eingebettet ist, den niemand auswertet.

BTW: Ich überlege gerade, ob vielleicht ein anderes Farbmodell geeignet sein könnte. Also z.B. Änderungen bei Cb und Cr (Farbmodell YCbCr) sind fürs menschliche Auge noch schlechter wahrnehmbar. Allerdings könnte es problematisch werden, wenn bei der Umrechnung in RGB (damit man nicht gleich das Farbmodell sieht, auf dem die Kodierung basiert) die Quantisierung die Nachricht zerstört. Außerdem könnte es aufgrund dieser Quantisierung "Lücken" im Histogramm geben, die dann wiederum darauf hindeuten, dass das Bild eigentlich mit YCbCr beschrieben wird. Hm … vielleicht was im Frequenzraum ändern? Das könnte sich wegen der Quantisierung im Ortsraum als schwierig erweisen. *rumspinn*

Ark
 
Falls du mich nicht verstanden hast, es geht darum einen Algorithmus zu finden, der abhängig von einem Schlüssel die Bits quer über das Bild verteilt, nicht nacheinander. Kommt natürlich drauf an wie deine Ansprüche sind.
 
Na, und wie die auffällt. Schau dir mal das Alpha-Histogramm an, da gibt's bei 254 eine Erhöhung, die da nicht sein dürfte; allein dass dieses Bild einen Alpha-Kanal mitbringt, ist schon seltsam. Und schon mit simplen Werkzeugen wie GIMP (Layer → Transparency → Threshold Alpha → Threshold: 254) hat man ganz schnell ein verdächtiges da regelmäßiges Muster am Anfang des Bildes sichtbar gemacht.
Damit sprichst du einen Punkt an, um den ich mich so erst mal gar nicht gekümmert habe- das Verstecken vor maschineller Erkennung. Bisher wollte ich nur eine Unterscheidung durch das menschliche Auge vermeiden. Ich habe eben zwei Bilder mit 5000% Zoom verglichen und man erkennt im Himmel nur absolut minimale Unterschiede (Und das auch nur weil der Himmel ja recht gleichfarbig ist), also habe ich das Ziel schon mal erreicht.

Mein Tipp: Rechne nicht +1 oder -1, sondern setz oder lösch das jeweils unterste Bit entsprechend der Nachricht. (Ich sehe gerade, dass bERt0r das schon geschrieben hat.) Dann braucht der Empfänger auch kein Vergleichsbild.
Die Möglichkeit mit den niederwertigsten Bits finde ich nicht so gut. Jeder der sich ein bisschen mit Bild-Steganographie beschäftigt kennt die und kann sie auch direkt auslesen, da sie ja ohne Schlüssel funktioniert.

Die Nachricht solltest du vor dem Einbetten außerdem noch komprimieren und/oder (symmetrisch) verschlüsseln, um die Entropie der Nachricht zu erhöhen. Denn die regelmäßigen Strukturen sind verdammt auffällig!
Vielleicht stehe ich jetzt etwas auf dem Schlauch, aber was ist da denn regelmäßig bzw. auffällig im Vergleich zu einem normalen Bild (Mal vom Alpha-Kanal abgesehen)? Und wie sollte das eine Komprimierung oder Verschlüsselung ändern?

Auch das abrupte Ende des Musters fällt auf, du solltest also noch die verbleibenden Pixel, die nicht zur Nachricht gehören, mit starken Zufallszahlen bearbeiten, als wären diese Zufallszahlen Teil der Nachricht.
Daran hatte ich auch schon gedacht. Allerdings fällt das Ende (zumindest dem menschlichen Auge) nur bei sehr eintönigen Bildern auf. Man könnte allerdings die Informationen mit bERt0r s Lösung auf das ganze Bild ausbreiten und immer wieder Abstände zwischen den codierten Pixeln lassen- so verschleiert man auch die Codierung stärker.
Kennt jemand zufällig einen Algorithmus, der mir Pixel innerhalb eines Bildes gibt, die nicht linear hintereinander angeordnet sind?

Ich meinte das so, dass die Nachricht in das bereits skalierte Bild eingebettet werden sollte. Wenn dann der Empfänger das große Originalbild mit dem gleichen Algorithmus auf die gleiche Größe skaliert, hat er dann ein perfektes Vergleichsbild.
Das ginge natürlich. Ich würde aber trotzdem die USB-Stick Variante vorziehen oder einen anderen Weg Schlüssel und Codierung getrennt voneinander zu verschicken.
 
Die Möglichkeit mit den niederwertigsten Bits finde ich nicht so gut. Jeder der sich ein bisschen mit Bild-Steganographie beschäftigt kennt die und kann sie auch direkt auslesen, da sie ja ohne Schlüssel funktioniert.
Steganographie schließt die Verwendung von Verschlüsselung (Kryptographie) ja nicht aus: Während Kryptographie verschleiert, was kommuniziert wird, verschleiert Steganographie, dass kommuniziert wird. Beides kann man nach Belieben kombinieren.

Vielleicht stehe ich jetzt etwas auf dem Schlauch, aber was ist da denn regelmäßig bzw. auffällig im Vergleich zu einem normalen Bild (Mal vom Alpha-Kanal abgesehen)? Und wie sollte das eine Komprimierung oder Verschlüsselung ändern?
Ich hole mal gerade etwas aus, versuche aber dabei, möglichst anschaulich zu bleiben, ohne allzu sehr zu vereinfachen:

Einfarbige Flächen sind "Stille", regelmäßige Strukturen sind "Musik" und alles andere (anscheinend oder nur scheinbar unregelmäßige Strukturen) sind "Rauschen". (Was du hier mit einer Bilddatei machst, ließe sich auch z.B. mit einer Audiodatei umsetzen, und da würde sich das dann wie beschrieben anhören.)

Nun gibt es eine gewisse Erwartungshaltung beim Empfänger bzw. Angreifer. Wenn du z.B. ein künstliches Bild wie etwa ein Screenshot von diesem Forum benutzen würdest, würde man erwarten, dass sehr viel Stille, ein bisschen sehr künstliche Musik und ansonsten so gut wie gar kein Rauschen auftritt.

Unkomprimiertes wie ausführbare Dateien, Textdateien, (unkomprimierte) Audiodateien usw. sind sehr häufig Musik (in diesem Sinne).

Wenn du nun Musik in Stille unterzubringen versuchst, dann "hört" man das, ganz egal, wie "leise" diese Musik ist.

Komprimiertes Material ist praktisch immer Rauschen (in diesem Sinne), genauso wie (brauchbar) verschlüsseltes. (Deshalb kann man verschlüsselte Dateien nie sinnvoll komprimieren.) Wenn du also das Material komprimierst und/oder verschlüsselst, hast du aus Musik Rauschen gemacht. Wie hilft dieses Rauschen nun? Denn bei Stille (wie dem oben genannten Screenshot, aber auch praktisch immer der Alphakanal) fallen sowohl Musik als auch Rauschen auf.

Der Trick besteht darin, dass du als Material, in das du die Nachricht einbetten willst, nur solches verwendest, das quasi auf natürliche Weise verrauscht ist, wo also der Angreifer und/oder Empfänger von sich aus mit einem gewissen Rauschen rechnet (wieder die Erwartungshaltung). Dann kann der Angreifer nämlich nicht mehr erkennen, ob das Rauschen tatsächlich nur rein zufällig auftritt, oder ob dahinter System steckt. Geeignetes Material wären dann z.B. solche Landschaftsbilder.

Um sicherzugehen, dass das ganze Bild verrauscht ist (damit die zu versteckende Nachricht auch wirklich im Rauschen untergehen kann), solltest du deshalb auch immer noch das ganze Bild mit Rauschen versehen (indem du z.B. einfach zufällig alle LSBs manipulierst).

Ich hoffe, diese Ausführungen waren einigermaßen verständlich. ^^ Wenn nicht, einfach nachfragen. 😉

Man könnte allerdings die Informationen mit bERt0r s Lösung auf das ganze Bild ausbreiten und immer wieder Abstände zwischen den codierten Pixeln lassen- so verschleiert man auch die Codierung stärker.
Kennt jemand zufällig einen Algorithmus, der mir Pixel innerhalb eines Bildes gibt, die nicht linear hintereinander angeordnet sind?
AES. 😉 Verschlüssel einfach deine Daten (vorher eventuell komprimieren), bette das Kryptogramm in ein Bild ein, wo man 1-Bit-Rauschen als normal ansiehen würde, und verrausch den Rest des Bildes, falls es noch nicht von sich aus hinreichend verrauscht ist. Als Schlüssel kannst/solltest du einen möglichst zufälligen wählen, etwa aus /dev/random. Mit der Verschlüsselung ist es dann für den Angreifer so gut wie unmöglich, System dahinter (also im Rauschen) zu erkennen.

Ark
 
Zuletzt bearbeitet:
Danke für die ausführliche Erklärung des Rauschens, das habe ich jetzt verstanden 🙂
Das LSB ist aber denke ich doch auffälliger als eine Addition bzw. Subtraktion von 1, wie dieses Dokument auf Seite 15 zeigt.
Dann werde ich mich mal daran begeben das Bild zu verrauschen und die Daten noch zu verschlüsseln 🙂
 

Neue Themen


Zurück
Oben