Dieser Artikel erweitert die Anwendung aus Teil 1 um das Aufteilen der Nachricht auf mehrere Träger-Bitmaps.
Wenn Du richtig paranoid bist, wirst Du Deiner Mailbox nicht vertrauen. Natürlich wirst Du auch nicht dem Briefträger vertrauen. Das bedeutet, dass Du es nicht wagst, die Träger-Bitmap in einem Stück zu verschicken. Das ist kein Problem mehr, denn Du kannst eine Nachricht in mehreren Bitmaps verstecken, als würde man einen Text über mehrere Seiten schreiben. Auf diese Anwendung bezogen heisst es, die Pixel über mehrere Bilder zu verteilen.
So wie du einen Papierbrief zerschneiden und in mehrere hohle Baustämme stecken kannst…
… kannst du die Bits in mehreren Grafiken verstecken:
Du kannst jedes Bild in einer separaten eMail verschicken, in verschiedenen Postfächern hinterlegen,
oder auf verschiedenen Festplatten speichern.
Die Oberfläche erlaubt es, mehrere Träger-Bitmaps genauso wie Schlüssel-Dateien auszuwählen.
Die Auswahl wird in einem Array vom Typ CarrierImage
gespeichert.
public struct CarrierImage{ //Name des "sauberen" Bildes public String sourceFileName; //Dateiname für das neue Bild public String resultFileName; //Breite * Höhe public long countPixels; //Farbiges (false) oder monochromes (true) Rauschen in diesem Bild erzeugen public bool useGrayscale; //Anzahl der Bytes, die in diesem Bild versteckt werden - wird von HideOrExtract() gesetzt public long messageBytesToHide; public CarrierImage(String sourceFileName, String resultFileName, long countPixels, bool useGrayscale){ this.sourceFileName = sourceFileName; this.resultFileName = resultFileName; this.countPixels = countPixels; this.useGrayscale = useGrayscale; this.messageBytesToHide = 0; } }
Größere Bilder können mehr Bytes (in mehr Pixeln) fassen als kleinere Bilder. Diese Beispiel-Anwendung verwendet die einfachste mögliche Verteilung:
//Anzahl der Bytes berechnen, für die dieses Bild verwendet wird for(int n=0; n<imageFiles.Length; n++){ //pixels = Anzahl der Pixel im Bild / Anzahl verfügbarer Pixel insgesamt float pixels = (float)imageFiles[n].countPixels / (float)countPixels; //Das Bild wird (Länge der Nachricht * pixels) Bytes verstecken imageFiles[n].messageBytesToHide = (long)Math.Ceiling( (float)messageLength * pixels ); }
Jetzt beginnen wir mit der ersten Träger-Bitmap, laufen durch die Nachricht, verstecken eine bestimmte Anzahl an Bytes, wechseln zur zweiten Träger-Bitmap, und immer so weiter.
//Aktuelle Position im Träger-Bitmap //Start bei 1, weil (0,0) die Länge der Nachricht enthält Point pixelPosition = new Point(1,0); //Anzahl der Bytes, die in diesem Bild bereits versteckt wurden int countBytesInCurrentImage = 0; //Index des aktuell verwendeten Bildes int indexBitmaps = 0; //Nachricht durchlaufen und jedes Byte verstecken for(int messageIndex=0; messageIndex<messageLength; messageIndex++){ //Position des nächsten Pixels berechnen //... //Weiter zur nächsten Bitmap if(countBytesInCurrentImage == imageFiles[indexBitmaps].messageBytesToHide){ indexBitmaps++; pixelPosition.Y = 0; countBytesInCurrentImage = 0; bitmapWidth = bitmaps[indexBitmaps].Width-1; bitmapHeight = bitmaps[indexBitmaps].Height-1; if(pixelPosition.X > bitmapWidth){ pixelPosition.X = 0; } } //Ein Byte verstecken oder extrahieren //... countBytesInCurrentImage++; }
Zum Schluss müssen wir die neuen Bilder speichern. Jedes Bild kann in einem anderen Format gespeichert werden (bmp, tif oder png). Das neue Format hat nichts mit dem Format der Original-Datei zu tun. Das heisst, Du kannst eine BMP-, zwei PNG und eine TIFF-Datei als Träger-Bilder auswählen, und die Ergebnisse in drei TIFF- und einer PNG-Datei speichern.
//... for(indexBitmaps=0; indexBitmaps<bitmaps.Length; indexBitmaps++){ if( ! extract ){ //Extrations-Modus ändert keine Bilder //Entstandenes Bild speichern und Original schließen SaveBitmap( bitmaps[indexBitmaps], imageFiles[indexBitmaps].resultFileName ); } } //... private static void SaveBitmap(Bitmap bitmap, String fileName){ String fileNameLower = fileName.ToLower(); //Format anhand der Erweiterung bestimmen System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Bmp; if((fileNameLower.EndsWith("tif"))||(fileNameLower.EndsWith("tiff"))){ format = System.Drawing.Imaging.ImageFormat.Tiff; }else if(fileNameLower.EndsWith("png")){ format = System.Drawing.Imaging.ImageFormat.Png; } //Bitmap kopieren Image img = new Bitmap(bitmap); //Datei schließen bitmap.Dispose(); //Neue Bitmap speichern img.Save(fileName, format); img.Dispose(); }