Skip to content

VideoSteg

Enrico edited this page Feb 9, 2021 · 10 revisions

Beschreibung des Algorithmus

Damit man Nachrichten in einer Video-Datei verstecken kann, steht die Klasse VideoSteg zur Verfügung.

Eine weitere wichtige Klasse ist die Video Klasse. Diese liest mittels ffprobe alle notwendige Informationen aus dem byte array des zu enkodierendem oder dekodierendem Video und speichert diese als Attribute des Video Objekt. Diese Informationen werden später benutzt, um ein steganographisches Video zu erzeugen oder zu dekodieren.

Enkodieren

Übersicht der Enkodierung:
UML für Enkodierung

  1. Der Carrier und Payload wird als byte array ausgelesen.
  2. Ein Objekt der Klasse Video wird erstellt, dieses beinhaltet Informationen über dem Carrier.
  3. Der Decoder mittels FFmpeg dekodiert der Carrier zu unterschiedliche Streams, alle Streams außer Video und Audio Stream werden ignoriert. Audio Stream wird als temporäre Datei gespeichert.
  4. Ein Frame Consumer liest aus dem Video Stream die einzelne Frames aus und konvertiert diese zu einer Liste von BufferedImages.
  5. Die einzelnen Bilder werden von der Klasse VideoSteg steganographisch enkodiert durch der Nutzung der Klasse ImageSteg und der Methode encode.
  6. Alle steganographisch enkodierte Bilder und das originale Audio Stream werden von der Klasse Encoder zu einem Video enkodiert. Zum Enkodieren wird immer das CorePNG codec benutzt, also das entstandene Steganographic Video wird immer AVI als Format haben.

Ein mehr detailliertes Sequence Diagramm kann hier gefunden werden.

Code-Beispiel Enkodierung

Mochte man ein Video direkt enkodieren, ohne dieses auf eine Social Media zu posten, kann dieses wie folgt gemacht werden:

Config

Als Erstes sollte man die hier erwähnte Einstellungen vornehmen, ist aber nicht erforderlich.

//CONFIG
ImageIO.setUseCache(false);
videoSteg.setDebug(true);
videoSteg.setMaxDecodingThreads(MAX_NUMBER_OF_THREADS_TO_DECODE);
videoSteg.setMaxEncodingThreads(MAX_NUMBER_OF_THREADS_TO_ENCODE);

Encode

  • Carrier (Video)
  • Payload (Geheime Nachricht)
  • Seed (Password) hier deutlicher erläutert.
//CARRIER
File carrier = new File("PATH_TO_CARRIER");
//PAYLOAD
File payload = new File("PATH_TO_PAYLOAD");

VideoSteg videoSteg = new VideoSteg();
// Add Config here

//ENCODE
byte[] stegVideo;
//Option 1: With Default Seed
stegVideo = videoSteg.encode(Files.readAllBytes(carrier.toPath()), Files.readAllBytes(payload.toPath()));
//Option 2: With Custom Seed
stegVideo = videoSteg.encode(Files.readAllBytes(carrier.toPath()), Files.readAllBytes(payload.toPath()), CUSTOM_SEED_L);

//Save Result to File
FileOutputStream fileOutputStream = new FileOutputStream(new File("PATH_TO_SAVE_LOCATION/Steg-Video.avi"));
fileOutputStream.write(stegVideo);
fileOutputStream.close();

Dekodieren

Übersicht der Dekodierung:
UML für Dekodierung

  1. Der Steganographische Video wird als byte array ausgelesen.
  2. Ein Objekt der Klasse Video wird erstellt, dieses beinhaltet Informationen über dem Video.
  3. Der Decoder mittels FFmpeg dekodiert der Carrier zu unterschiedliche Streams, alle Streams außer Video werden ignoriert.
  4. Ein Frame Consumer liest aus dem Video Stream die einzelne Frames aus und konvertiert diese zu einer Liste von BufferedImages.
  5. Die einzelnen Bilder werden von der Klasse VideoSteg steganographisch dekodiert durch der Nutzung der Klasse ImageSteg und der Methode decode.
  6. Alle einzelne bytes die dekodiert wurden, werden in der richtige Reihenfolge zusammen gefügt und als Rückgabe gegeben.

Ein mehr detailliertes Sequence Diagramm kann hier gefunden werden.

Code-Beispiel Dekodierung

Mochte man ein Video direkt dekodieren, ohne dieses auf eine Social Media zu posten, kann dieses wie folgt gemacht werden:

Config

Als Erstes sollte man die hier erwähnte Einstellungen vornehmen, ist aber nicht erforderlich.

//CONFIG
ImageIO.setUseCache(false);
videoSteg.setDebug(true);
videoSteg.setMaxDecodingThreads(MAX_NUMBER_OF_THREADS_TO_DECODE);

Decode

  • stegVideo (Enkodiertes Video)
File stegVideo = new File("PATH_TO_SAVE_LOCATION/Steg-Video.avi");

//DECODE
byte[] secret;
VideoSteg videoSteg = new VideoSteg();
//Add Config here

//Option 1: If Default Seed used to Encode
secret = videoSteg.decode(Files.readAllBytes(stegVideo.toPath()));
//Option 2: If Custom Seed used to Encode
secret = videoSteg.decode(ByteArrayUtils.read(stegVideo), CUSTOM_SEED_L);

//Save Output
FileOutputStream secretOutput = new FileOutputStream(new File("SAVE_LOCATION/PAYLOAD.FORMAT"));
secretOutput.write(secret);
secretOutput.close();

Weitere wichtige Methoden

isSteganographicData()

Diese Methode kann benutzt werden um zu überprüfen, ob ein Video steganographisch enkodiert wurde. Diese Methode sollte aber nicht vor der Dekodierung aufgerufen werden da es redundant ist und nur zu einer längeren Laufzeit frühen würde. Es wird bei der Dekodierung eine Exception geworfen, falls keine Daten entschlüsselt wurden.

getVideoCapacity()

Diese Methode kann sehr hilfreich sein um zu wissen wie viele Bytes maximal in einem gegeben Video enkodiert werden können.

setFfmpegBin()

FFmpeg und FFprobe werden im Hintergrund benutzt um Videos zu dekodieren und enkodieren. Eine vor-kompiliere Version der zwei Programme ist im Projekt vorgegeben (für Windows und Linux). Falls eine andere Distribution oder eine neue Version von FFmpeg oder FFprobe benutzt sein soll, kann dieses wie folgt gemacht werden:

  1. FFmpeg oder FFprobe (oder beide) in einem Ordner kopieren
  2. Path zum neuen Order durch Aufruf dieser Methode setzen.

Unterstützte Formate

Format Algorithmus Ausgabe
AVI Henk-Algorithmus (RandomLSB) AVI
MP4 Henk-Algorithmus (RandomLSB) AVI
MPEG Henk-Algorithmus (RandomLSB) AVI

Hier sind alle unterstützte Formate aufgelistet.
Resultat des enkodieren wird immer AVI sein.

Configuration

Da das de- und enkodieren von Videos eine sehr Resourcen auffendige aufgabe sein kann, wurde eine multi-Threaded variante von encode und decode implementiert. Standardmäßig wird die Single-Threaded variante benutzt, man kann aber die multi-Threaded variante benuzten durch das setzen der nummer von Threads die beim enkodiren und dekodieren benutzt sein sollten.

VideoSteg videoSteg = new VideoSteg();
videoSteg.setMaxDecodingThreads(MAX_NUMBER_OF_THREADS_TO_DECODE);
videoSteg.setMaxEncodingThreads(MAX_NUMBER_OF_THREADS_TO_ENCODE);

Es wird nie gleichzeitig enkodiert und dekodiert, wurde aber separat gehalten um mehr kontrolle am Nutzter zu geben. Man sollte aber beachten, dass zum Beispiel beim auffruf von der methode encode() erst das Video dekodiert wird (zu einzelene Frames) dann enkodiert.

Es gibt auch die möglichkeit ausgaben auf der konsole hiermit einzuschalten:

VideoSteg videoSteg = new VideoSteg();
videoSteg.setDebug(true);

Sequence Diagramme

Encode()

Encode UML Diagramm

Decode()

Decode UML Diagramm