![]() |
||||||||||||
|
|
|||||||||||
Worum geht es?Dieser Artikel versucht zu erklären, wie beliebige Daten im Rauschen von Bildern versteckt werden können. Es gibt nur einen sicheren Ort für private Daten: Den Ort, an dem niemand danach sucht. Wie es funktioniertUm zu sehen, wie die Anwendung arbeitet, solltest Du den Quellcode anschauen.
Und so wieder extrahiert:
Zuerst schreibt das Programm die Länge der Nachricht ins erste Pixel. Wir brauchen diesen Wert später, um die Nachricht wieder zu extrahieren. messageLength = (Int32)messageStream.Length; //hier werden eventuelle Konflikte abgefangen //... //Länge der Nachricht ins erste Pixel schreiben int colorValue = messageLength; int red = colorValue >> 2; colorValue -= red << 2; int green = colorValue >> 1; int blue = colorValue - (green << 1); pixelColor = Color.FromArgb(red, green, blue); bitmap.SetPixel(0,0, pixelColor); Anschließend liest es ein Byte aus dem Schlüssel-Stream, um die Position des nächsten zu verwendenden Pixels zu berechnen: //mit dem zweiten Pixel anfangen
Point pixelPosition = new Point(1,0);
//Für jedes Byte der Nachricht
for(int messageIndex=0; messageIndex<messageLength; messageIndex++){
//repeat the key, if it is shorter than the message
if(keyStream.Position == keyStream.Length){
keyStream.Seek(0, SeekOrigin.Begin);
}
//Nächste Pixel-Anzahl aus dem Schlüssel lesen, "1" für 0 verwenden
currentStepWidth = keyStream.ReadByte() + 1;
//Zeile wechseln, falls aktuelle Schrittweite den Rand überschreitet
while(currentStepWidth > bitmapWidth){
currentStepWidth -= bitmapWidth;
pixelPosition.Y++;
}
//Position horizontal versetzen
if((bitmapWidth - pixelPosition.X) < currentStepWidth){
pixelPosition.X = currentStepWidth - (bitmapWidth - pixelPosition.X);
pixelPosition.Y++;
}else{
pixelPosition.X += currentStepWidth;
}
Jetzt lesen wir das Pixel und ersetzen eine Farb-Komponente mit dem Nachrichten-Byte (oder alle Komponenten, wenn schwarz/weisses Rauschen entstehen soll): //Farbe des "sauberen" Pixels lesen
pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y);
//Um etwas Verwirrung hinzuzufügen, wird das Byte mit der aktuellen Schrittweite kombiniert
int currentByte = messageStream.ReadByte() ^ currentKeyByte;
if(useGrayscale){
pixelColor = Color.FromArgb(currentByte, currentByte, currentByte);
}else{
//Eine Farb-Komponente ersetzen
SetColorComponent(ref pixelColor, currentColorComponent, currentByte);
//Für das nächste Byte eine andere Komponente verwenden
currentColorComponent = (currentColorComponent==2) ? 0 : (currentColorComponent+1);
}
} //Ende "for" - weiter zum nächsten Byte
Wenn das Programm eine versteckte Nachricht ausliest, liest es die Länge der Nachricht und die Farb-Komponenten, anstatt sie in die Pixel zu schreiben. So wird die Länge aus dem ersten Pixel gelesen: pixelColor = bitmap.GetPixel(0,0); messageLength = (pixelColor.R << 2) + (pixelColor.G << 1) + pixelColor.B; messageStream = new MemoryStream(messageLength); Die Pixel-Koordinaten werden genauso bestimmt wie bereits beschrieben. Anschließend wird das versteckte Byte aus dem Farbwert gelesen: //Farbe des geänderten Pixels lesen pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y); //Das ersteckte Nachrichten-Byte aus der Farbe extrahieren byte foundByte = (byte)(currentKeyByte ^ GetColorComponent(pixelColor, currentColorComponent)); messageStream.WriteByte(foundByte); //Für das nächste Byte eine andere Komponente verwenden currentColorComponent = (currentColorComponent==2) ? 0 : (currentColorComponent+1); } //Ende "for" - weiter zum nächsten Byte |