C) Steganographie – Daten in Bildern verstecken

Zusammenfassung

Mehr ist zum Speichern einer geheimen Botschaft in einem Bild nicht notwendig. Das Auslesen funktioniert selbstverständlich genau in die andere Richtung. Alle Bits der Farbkanäle der Pixel des Bildes werden zu kompletten Bytes aneinander gereiht. Diese extrahierten Bytes bilden die ursprüngliche Nachricht. Da diese Vorgehensweise nun sicherlich auch für Sie kein Hexenwerk mehr ist, verzichte ich an dieser Stelle auf eine detaillierte Beschreibung, sondern beschränke mich auf den zusammengefassten Code mitsamt Kommentaren.

package de.jbb.steganographie;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;

import javax.imageio.ImageIO;

public class HideInPicture {

  public BufferedImage hideMessage(BufferedImage img, String message) {

    // Zeichen für Message-Ende hinzufügen
    message += (char)0;
    // Text in Bytes umwandeln
    byte[] b = message.getBytes();
    // Farbkanal
    Color channel = Color.RED;
    // Alle Bytes durchlaufen
    for (int i = 0, x = 0, y = 0; i < b.length; i++) {
      // Alle Bits durchlaufen
      for (int j = 7; j > -1; j--) {

        // Wert des Bits auslesen
        int bit = ((b[i] & 0xFF) >> j) & 1;
        // Farbe an der aktuellen Position auslesen
        int rgb = img.getRGB(x, y);
        // Den aktuellen Farbkanal auslesen
        int color = (rgb >> channel.getShift()) & 0xFF;
        
        // Farbkanal manipulieren
        if ((color & 1) != bit) {
          // Den ausgelesenen Farbkanal der Farbe auf 0 setzen
          rgb &= channel.getRGBManipulator();
          switch (bit) {
            case 1:
              color = color + 1;
              break;
            default:
              color = color - 1;
          }
          // Farbkanal zurückschreiben
          rgb |= color << channel.getShift();
          img.setRGB(x, y, rgb);
        }

        // nächsten Farbkanal setzen
        channel = channel.getNext();
        // Falls Farbkanal = RED => X-Position verändern
        if (channel.equals(Color.RED)) {
          x++;
          // Falls x größer als Breite des Bildes => Y-Positon verändern
          if (x >= img.getWidth()) {
            x = 0;
            y++;
            // Falls y größer als Höhe des Bildes => Fehler
            if (y >= img.getHeight()) {
              return null;
            }
          }
        }
      }
    }
    return img;
  }

  public String extractMessage(BufferedImage img) {

    // ArrayList für gelesene Bytes
    ArrayList<Byte> bytes = new ArrayList<Byte>();
    // Alle horizontalen Pixel durchlaufen
    for (int y = 0, count = 7, value = 0; y < img.getHeight(); y++) {
      // Alle vertikalen Pixel durchlaufen
      for (int x = 0; x < img.getWidth(); x++) {
        // Aktuelle Farbe auslesen
        int rgb = img.getRGB(x, y);
        // Alle Farbkanäle durchlaufen
        for (Color c : Color.values()) {
          // Aktuelles Byte befüllen
          value |= (((rgb >> c.getShift()) & 0xFF) & 1) << count--;
          // Aktuelles Byte ist voll
          if (count == -1) {
            // Byte == 0 (Nachrichtende)
            if ((byte)value == 0) {
              // Nachricht in String umwandeln und zurückgeben
              return bytesToString(bytes.toArray(new Byte[0]));
            }
            // Byte-ArrayList das aktuelle Byte hinzufügen
            bytes.add((byte)value);
            // Zählvariablen zurücksetzen
            value = 0;
            count = 7;
          }
        }
      }
    }
    return bytesToString(bytes.toArray(new Byte[0]));
  }

  private String bytesToString(Byte[] barr) {

    byte[] barrPrim = new byte[barr.length];
    for (int i = 0; i < barr.length; i++) {
      barrPrim[i] = barr[i];
    }
    return new String(barrPrim);
  }
}

Damit Sie alles beisammen haben, finden Sie hier auch noch einmal den Code unserer Color-Enumeration.

package de.jbb.steganographie;

public enum Color {

  RED(16, ( 255 << 24 ) | ( 255 << 8 ) | ( 255 << 0 )), 
  GREEN(8, ( 255 << 24 ) | ( 255 << 16 ) | ( 255 << 0 )), 
  BLUE(0, ( 255 << 24 ) | ( 255 << 16 ) | ( 255 << 8 ));

  private int shift = 0;
  private int rgbManipulator;

  private Color(int shift, int rgbManipulator) {
    this.shift = shift;
    this.rgbManipulator = rgbManipulator;
  }

  public Color getNext() {

    if (this == RED) {
      return GREEN;
    }
    else if (this == GREEN) {
      return BLUE;
    }
    else {
      return RED;
    }
  }

  public int getShift() {
    return this.shift;
  }

  public int getRGBManipulator() {
    return this.rgbManipulator;
  }
}

Die Klasse könnten Sie bspw. so testen (Vorausgesetzt, dass auf „C:\“ ein Bild mit dem Namen „test.png“ liegt):

public static void main(String[] args) throws Exception {
  HideInPicture hip = new HideInPicture();
  BufferedImage img = hip.hideMessage(ImageIO.read(new File("C:/test.PNG")), "Abc23*ß");
  ImageIO.write(img, "png", new File("C:/test2.png"));
  System.out.println(hip.extractMessage(ImageIO.read(new File("C:/test2.PNG"))));
}

Sie können eine mögliche Implementierung von diesem Algorithmus auf SoftK.de als Opensource kostenfrei herunterladen.

Ähnliche Beiträge

  • C) Bubblesort

    Der Bubblesort-Algorithmus (Blasen-Sortierung) ist ein stabiler, einfacher und vor allem sehr langsamer und daher nicht zu empfehlender Sortieralgorithmus. Durch seine Einfachheit eignet er sich aber bestens für Programmieranfänger zum Nachprogrammieren und lernen.

  • C) Brainfuck Interpreter

    Zusammenfassung package de.jbb.bf; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.LinkedList; public class BrainFucker { private InputStream inp; private OutputStream out; private int[] fields; private LinkedList<Integer> openedLoops; public BrainFucker(InputStream input, OutputStream output) { this(input, output, 32768); } public BrainFucker(InputStream input, OutputStream output, int fieldCnt) { this.inp = input; this.out = output; this.fields = new int[fieldCnt];…

  • C) Cäsar Verschlüsselung

    Die Cäsar Verschlüsselung ist eine der simpelsten Möglichkeiten einen Text zu verschlüsseln. Dabei wird ein Buchstabe um X Stellen verschoben. Setzt man für X beispielsweise die drei, wird z. B. aus dem a ein D, aus b ein E und aus z ein C. Üblicherweise besteht die unverschlüsselte Nachricht nur aus Kleinbuchstaben und die verschlüsselte…