__author__ = 'chunk' import numpy as np import time import os import sys import random import re import mjsteg import jpegObj from common import * sample_key = [46812L, 20559L, 31360L, 16681L, 27536L, 39553L, 5427L, 63029L, 56572L, 36476L, 25695L, 61908L, 63014L, 5908L, 59816L, 56765L] class StegBase(object): """ This is the base class for some of the JPEG-algorithms that behave similarly such as JSteg, OutGuess and F3. """ def __init__(self): """ Constructor of the JPEGSteg class. """ self.t0 = None self.cov_jpeg = None self.cov_data = None self.hid_data = None self.key = None def _get_cov_data(self, img_path): """ Returns DCT coefficients of the cover image. """ self.cov_jpeg = jpegObj.Jpeg(img_path) self.key = self.cov_jpeg.getkey() self.cov_data = self.cov_jpeg.getCoefBlocks() return self.cov_data def _get_hid_data(self, src_hidden): """ Returnsthe secret data as byte sequence. """ raw = [0, 0, 0, 0] + np.fromfile(src_hidden, np.uint8).tolist() raw_size = len(raw) for i in xrange(4): raw[i] = raw_size % 256 raw_size /= 256 self.hid_data = np.array(raw, dtype=np.uint8) if np.size(self.hid_data) * 8 > np.size(self.cov_data): raise Exception("Cover image is too small to embed data.Cannot fit %d bits in %d DCT coefficients" % ( np.size(self.hid_data) * 8, np.size(self.cov_data))) return self.hid_data def _post_embed_actions(self, src_cover, src_hidden, tgt_stego): """ This function isn't named very accurately. It actually calls the _raw_embed function in inherited classes. """ try: cov_data = self._get_cov_data(src_cover) hid_data = self._get_hid_data(src_hidden) # print hid_data.dtype,type(hid_data),hid_data.tolist() cov_data, bits_cnt = self._raw_embed(cov_data, hid_data) if bits_cnt != np.size(hid_data) * 8: raise Exception("Expected embedded size is %db but actually %db." % ( np.size(hid_data) * 8, bits_cnt)) self.cov_jpeg.setCoefBlocks(cov_data) self.cov_jpeg.Jwrite(tgt_stego) # size_cov = os.path.getsize(tgt_stego) size_cov = np.size(cov_data) / 8 size_embedded = np.size(hid_data) self._display_stats("embedded", size_cov, size_embedded, time.time() - self.t0) except TypeError as e: raise e except Exception as expt: print "Exception when embedding!" raise def _post_extract_actions(self, src_steg, tgt_hidden): """ This function isn't named very accurately. It actually calls the _raw_extract function in inherited classes. """ try: steg_data = self._get_cov_data(src_steg) # emb_size = os.path.getsize(src_steg) emb_size = np.size(steg_data) / 8 # recovering file size header_size = 4 * 8 size_data, bits_cnt = self._raw_extract(steg_data, header_size) size_data = bits2bytes(size_data) size_hd = 0 for i in xrange(4): size_hd += size_data[i] * 256 ** i raw_size = size_hd * 8 if raw_size > np.size(steg_data): raise Exception("Supposed secret data too large for stego image.") hid_data, bits_cnt = self._raw_extract(steg_data, raw_size) if bits_cnt != raw_size: raise Exception("Expected embedded size is %db but actually %db." % ( raw_size, bits_cnt)) hid_data = bits2bytes(hid_data) # print hid_data.dtype,type(hid_data),hid_data.tolist() hid_data[4:].tofile(tgt_hidden) self._display_stats("extracted", emb_size, np.size(hid_data), time.time() - self.t0) except Exception as expt: print "Exception when extracting!" raise def _looks_like_jpeg(self, path): try: with open(path, 'r') as f: return f.read(2) == '\xff\xd8' except IOError: return False def _display_stats(self, verb, cov_size, emb_size, duration): print( "%dB %s in %.2fs (%.2f kBps), embedding ratio: %.4f" % (emb_size, verb, duration, (emb_size / duration) / 1000., float(emb_size) / cov_size)) # dummy functions to please pylint def _raw_embed(self, cov_data, hid_data): pass def _raw_extract(self, steg_data, num_bits): pass def _dummy_embed_hook(self, cov_data, hid_data): pass def _dummy_extract_hook(self, steg_data, num_bits): pass