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;
    }
 

xehpuk

Top Contributor
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?
 

Ark

Top Contributor
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:

chaostheory

Bekanntes Mitglied
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.
 

xehpuk

Top Contributor
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.
 

chaostheory

Bekanntes Mitglied
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.).
 

bERt0r

Top Contributor
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.
 

chaostheory

Bekanntes Mitglied
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.
 

Ark

Top Contributor
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
 

bERt0r

Top Contributor
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.
 

chaostheory

Bekanntes Mitglied
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.
 

Ark

Top Contributor
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:

chaostheory

Bekanntes Mitglied
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 :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Java Dateien kopieren mit Fortschrittsbalken AWT, Swing, JavaFX & SWT 13
frager2345 Bild aus Dateien lesen und als Hintergrund verwenden AWT, Swing, JavaFX & SWT 2
N Dateien einlesen und in GUI immernoch auswählbar AWT, Swing, JavaFX & SWT 1
MiMa File Dateien im ListView als Name anzeigen? AWT, Swing, JavaFX & SWT 6
H JavaFX Media Dateien zu VideoPlayerController senden AWT, Swing, JavaFX & SWT 10
VPChief Gibt es eine möglichkeit Dateien aus der jar datei zu kopieren? AWT, Swing, JavaFX & SWT 46
F Output Stream / File Dateien / Speichern AWT, Swing, JavaFX & SWT 13
Z Bearbeitung von csv Dateien AWT, Swing, JavaFX & SWT 13
J JavaFX Wie verhindere ich das gleichzeitige Spielen von Dateien bei Mediaplayer JavaFX? AWT, Swing, JavaFX & SWT 3
E JavaFX Umgang mit SVG-Dateien AWT, Swing, JavaFX & SWT 0
S Swing JFileChooser best. Ordner wie Dateien behandeln AWT, Swing, JavaFX & SWT 4
D Dateien öffnen AWT, Swing, JavaFX & SWT 16
S Swing txt Dateien öffnen mit JFilleChooser AWT, Swing, JavaFX & SWT 4
B Swing Dateien im Swing-GUI anzeigen AWT, Swing, JavaFX & SWT 3
H RCP(SWT) Browser-Widget zeigt keine locale HTML-Dateien an AWT, Swing, JavaFX & SWT 1
E 2D-Grafik Speicherprobleme große Tiff-Dateien AWT, Swing, JavaFX & SWT 50
M Swing Dateien auf Muster analysieren AWT, Swing, JavaFX & SWT 30
J Auf Dateien in JTree zugreifen AWT, Swing, JavaFX & SWT 15
MiMa Dateien aus Ordner in einer JList Ausgeben AWT, Swing, JavaFX & SWT 32
Daniel_L Drop von Dateien auf Frame - welche Drop-Location? AWT, Swing, JavaFX & SWT 2
H * Einlesen von Text-Dateien & Zeichensatz bestimmen AWT, Swing, JavaFX & SWT 2
K JFileChooser mehrere Dateien markieren ohne STRG AWT, Swing, JavaFX & SWT 4
N verschieben von Dateien auf der Festplatte über TreePaths funktioniert nicht AWT, Swing, JavaFX & SWT 10
F AWT DnD von Dateien mit Sonderzeichen funktioniert unter Linux nicht AWT, Swing, JavaFX & SWT 3
B ImageIO gif Dateien laden AWT, Swing, JavaFX & SWT 7
D LayoutManager Main layout auf andere Class Dateien verweisen? AWT, Swing, JavaFX & SWT 17
R Windows-Dateien auf GUI ziehen AWT, Swing, JavaFX & SWT 3
M Swing JTable Drag'n'Drop von Dateien AWT, Swing, JavaFX & SWT 3
S Dateien kopieren mit ProgressBar AWT, Swing, JavaFX & SWT 6
T SWT Wie Bilder aus JAR-Dateien einbinden? AWT, Swing, JavaFX & SWT 12
Developer_X Java BMP-Dateien laden AWT, Swing, JavaFX & SWT 2
T Compiler erzeugt mehrere .class Dateien AWT, Swing, JavaFX & SWT 2
K Per ComboBox Dateien einlesen AWT, Swing, JavaFX & SWT 23
G JFileChooser - erkennen v. existierenden Dateien ohne Endung AWT, Swing, JavaFX & SWT 1
I Dateien durchsuchen AWT, Swing, JavaFX & SWT 7
P Dateien per Drag&Drop ins Java-Fenster ziehen AWT, Swing, JavaFX & SWT 8
A Dateien in TextArea ausgeben AWT, Swing, JavaFX & SWT 6
G Dynamische Menüs mit Liste von MRU Dateien AWT, Swing, JavaFX & SWT 2
J Dateien einlesen AWT, Swing, JavaFX & SWT 3
E JList und Drag&Drop von Dateien AWT, Swing, JavaFX & SWT 1
H JFileChooser für alle Dateien und Directories unterhalb AWT, Swing, JavaFX & SWT 7
K SystemIcons v. Dateien & Verz. im TreeView anzeigen AWT, Swing, JavaFX & SWT 2
A JFileChooser - Mehrere Dateien per Maus markieren (nokeys) AWT, Swing, JavaFX & SWT 7
S Probleme beim Laden und Speichern von Dateien AWT, Swing, JavaFX & SWT 6
J Word/Excel-Dateien mit Button öffnen AWT, Swing, JavaFX & SWT 5
O Dateien aus Verzeichnis filtern und in JTable darstellen AWT, Swing, JavaFX & SWT 3
G JFileChooser: nur *.gif-Dateien anzeigen AWT, Swing, JavaFX & SWT 5
EagleEye GUI in mehrere Dateien aufteilen AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben