Commit eb8204436b7f815e43661e80208af5fc543e6cb7

Authored by Chunk
1 parent c9fdeb00
Exists in master

staged.

msteg/StegBase.py 0 → 100644
... ... @@ -0,0 +1,148 @@
  1 +"""
  2 +This module implements a common base class of the steganographic
  3 +algorithms which embed data into JPEG files.
  4 +In order to run plugins inheriting from this class
  5 +you must build the rw_dct.so library which interfaces with libjpeg.
  6 +To do so, just run
  7 +% python setup.py build
  8 +in stegotool/util and copy the rw_dct.so
  9 +library (which can be found somewhere in the build-directory to
  10 +stegotool/util.
  11 +
  12 +"""
  13 +import numpy as np
  14 +import time
  15 +import os
  16 +import sys
  17 +import random
  18 +import re
  19 +
  20 +import mjsteg
  21 +import jpegObj
  22 +from common import *
  23 +
  24 +
  25 +class StegBase(object):
  26 + """
  27 + This is the base class for some of the JPEG-algorithms that behave
  28 + similarly such as JSteg, OutGuess and F3.
  29 + """
  30 +
  31 + def __init__(self):
  32 + """
  33 + Constructor of the JPEGSteg class.
  34 + """
  35 + self.t0 = None
  36 + self.cov_jpeg = None
  37 + self.cov_data = None
  38 + self.hid_data = None
  39 +
  40 + def _get_cov_data(self, img_path):
  41 + """
  42 + Returns DCT coefficients of the cover image.
  43 + """
  44 + self.cov_jpeg = jpegObj.Jpeg(img_path)
  45 + self.cov_data = self.cov_jpeg.getCoefBlocks()
  46 + return self.cov_data
  47 +
  48 +
  49 + def _get_hid_data(self, src_hidden):
  50 + """
  51 + Returnsthe secret data as byte sequence.
  52 + """
  53 + raw = [0, 0, 0, 0] + np.fromfile(src_hidden, np.uint8).tolist()
  54 + raw_size = len(raw)
  55 + for i in xrange(4):
  56 + raw[i] = raw_size % 256
  57 + raw_size /= 256
  58 + self.hid_data = np.array(raw)
  59 +
  60 + if np.size(self.hid_data) * 8 > np.size(self.cov_data):
  61 + raise Exception("Cover image is too small to embed data.Cannot fit %d bits in %d DCT coefficients" % (
  62 + np.size(self.hid_data) * 8, np.size(self.cov_data)))
  63 + return self.hid_data
  64 +
  65 +
  66 + def _post_embed_actions(self, src_cover, src_hidden, tgt_stego):
  67 + """
  68 + This function isn't named very accurately. It actually calls the
  69 + _raw_embed function in inherited classes.
  70 + """
  71 + try:
  72 + cov_data = self._get_cov_data(src_cover)
  73 + hid_data = self._get_hid_data(src_hidden)
  74 + cov_data = self._raw_embed(cov_data, hid_data)
  75 +
  76 + self.cov_jpeg.setCoefBlocks(cov_data)
  77 + self.cov_jpeg.Jwrite(tgt_stego)
  78 +
  79 + size = os.path.getsize(tgt_stego)
  80 + size_embedded = np.size(hid_data)
  81 +
  82 + self._display_stats("embedded", size, size_embedded,
  83 + time.time() - self.t0)
  84 +
  85 + except TypeError as e:
  86 + raise e
  87 + except Exception:
  88 + raise Exception(
  89 + 'DCT coefficients exhausted. This usually means there are not enough DCT coefficients in the image in which algorithm can actually embed data. You should choose a larger image.')
  90 +
  91 + def _post_extract_actions(self, src_steg, tgt_hidden):
  92 + """
  93 + This function isn't named very accurately. It actually calls the
  94 + _raw_extract function in inherited classes.
  95 + """
  96 + try:
  97 + steg_data = self._get_cov_data(src_steg)
  98 + emb_size = os.path.getsize(src_steg)
  99 +
  100 + # recovering file size
  101 + header_size = 4 * 8
  102 + size_data = self._raw_extract(steg_data, header_size)
  103 + size_data = bits2bytes(size_data)
  104 + size_hd = 0
  105 + for i in xrange(4):
  106 + size_hd += size_data[i] * 256 ** i
  107 +
  108 + raw_size = size_hd * 8
  109 +
  110 + if raw_size > np.size(steg_data):
  111 + raise Exception("Supposed secret data too large for stego image.")
  112 +
  113 + hid_data = self._raw_extract(steg_data, raw_size)
  114 + hid_data = bits2bytes(hid_data)
  115 + hid_data[4:].tofile(tgt_hidden)
  116 +
  117 + self._display_stats("extracted", emb_size,
  118 + np.size(hid_data),
  119 + time.time() - self.t0)
  120 + except:
  121 + raise Exception('DCT coefficients exhausted.The stego image is probably corrupted.')
  122 +
  123 +
  124 + def _looks_like_jpeg(self, path):
  125 + try:
  126 + with open(path, 'r') as f:
  127 + return f.read(2) == '\xff\xd8'
  128 + except IOError:
  129 + return False
  130 +
  131 + def _display_stats(self, verb, cov_size, emb_size, duration):
  132 + print(
  133 + "%dB %s in %.2fs (%.2f kBps), embedding ratio: %.4f" %
  134 + (emb_size, verb, duration, (emb_size / duration) / 1000.,
  135 + float(emb_size) / cov_size))
  136 +
  137 + # dummy functions to please pylint
  138 + def _raw_embed(self, cov_data, hid_data, status_begin=0):
  139 + pass
  140 +
  141 + def _raw_extract(self, steg_data, num_bits):
  142 + pass
  143 +
  144 + def _dummy_embed_hook(self, cov_data, hid_data):
  145 + pass
  146 +
  147 + def _dummy_extract_hook(self, steg_data, num_bits):
  148 + pass
... ...
msteg/steganalysis/ChiSquare.py 0 → 100644
... ... @@ -0,0 +1,165 @@
  1 +"""
  2 +<p>
  3 +This module implements an algorithm described by Andreas Westfeld in [1,2],
  4 +which detects if there was data embedded into an image using JSteg.
  5 +It uses the property that JSteg generates pairs of values in the
  6 +DCT-coefficients histogram, which can be detected by a \chi^2 test.
  7 +</p>
  8 +
  9 +<pre>
  10 +[1]: Andreas Westfeld, F5 - A Steganographic Algorithm High Capacity Despite
  11 +Better Steganalysis
  12 +[2]: Andreas Westfeld, Angriffe auf steganographische Systeme
  13 +</pre>
  14 +"""
  15 +
  16 +from collections import defaultdict
  17 +import os
  18 +
  19 +import Image
  20 +import numpy
  21 +from scipy.stats import chisquare
  22 +import matplotlib.pyplot as plt
  23 +import itertools as it
  24 +
  25 +from stegotool.util.plugins import describe_and_annotate
  26 +from stegotool.util.plugins import ImagePath, NewFilePath
  27 +from stegotool.util.JPEGSteg import JPEGSteg
  28 +from stegotool.util import rw_dct
  29 +
  30 +class ChiSquare(JPEGSteg):
  31 + """
  32 + The module contains only one method, <b>detect</b>.
  33 + """
  34 +
  35 + def __init__(self, ui, core):
  36 + self.ui = ui
  37 + self.core = core
  38 +
  39 + @describe_and_annotate((None, None),
  40 + ("Source image", ImagePath),
  41 + ("Target image", NewFilePath),
  42 + ("2nd Target image", NewFilePath))
  43 + def detect(self, src, tgt, tgt2):
  44 + """
  45 + <p>
  46 + Detect if there was data embedded in the <i>source image</i> image with
  47 + JSteg algorithm.
  48 + </p>
  49 +
  50 + <p>
  51 + Parameters:
  52 + <ol>
  53 + <li><pre>Source image</pre> Image which should be tested</li>
  54 + <li><pre>Target image</pre> Image which displays a graphic with the
  55 + embedding probability</li>
  56 + <li><pre>2nd Target image</pre> Image which displays the embedding
  57 + positions in the image</li>
  58 + </ol>
  59 + </p>
  60 + """
  61 + # --------------------------- Input -----------------------------------
  62 + # If src is from the image pool, test whether the image exists encoded
  63 + # on the file system. Otherwise we can not read DCT-coefficients.
  64 + if self.core.media_manager.is_media_key(src):
  65 + src = self.core.media_manager.get_file(src)
  66 + if hasattr(src, 'tmp_file'):
  67 + src = src.tmp_file
  68 + self.ui.display_error('Trying file: %s' % src)
  69 + else:
  70 + self.ui.display_error('Can not detect anything from \
  71 + decoded images.')
  72 + return
  73 + # Test whether the file exists.
  74 + if not os.path.isfile(src):
  75 + self.ui.display_error('No such file.')
  76 + return
  77 + # Test if it is a JPEG file.
  78 + if not self._looks_like_jpeg(src):
  79 + self.ui.display_error('Input is probably not a JPEG file.')
  80 + return
  81 +
  82 + # ---------------------------- Algorithm ------------------------------
  83 + # Build DCT-histogram in steps of \approx 1% of all coefficients and
  84 + # calculate the p-value at each step.
  85 + dct_data = rw_dct.read_dct_coefficients(src)
  86 + hist = defaultdict(int)
  87 + cnt = 0
  88 + l = len(dct_data)
  89 + one_p = l / 100
  90 + result = []
  91 + for block in dct_data:
  92 + # update the histogram with one block of 64 coefficients
  93 + for c in block:
  94 + hist[c] += 1
  95 +
  96 + cnt += 1
  97 + if not cnt % one_p:
  98 + # calculate p-value
  99 + self.ui.set_progress(cnt * 100 / l)
  100 +
  101 + # ignore the pair (0, 1), since JSteg does not embed data there
  102 + hl = [hist[i] for i in range(-2048, 2049) if not i in (0, 1)]
  103 + k = len(hl) / 2
  104 + observed = []
  105 + expected = []
  106 + # calculate observed and expected distribution
  107 + for i in range(k):
  108 + t = hl[2 * i] + hl[2 * i + 1]
  109 + if t > 3:
  110 + observed.append(hl[2 * i])
  111 + expected.append(t / 2)
  112 + # calculate (\chi^2, p)
  113 + p = chisquare(numpy.array(observed), numpy.array(expected))[1]
  114 + result.append(p)
  115 +
  116 + # ----------------------------- Output --------------------------------
  117 + # Graph displaying the embedding probabilities in relation to the
  118 + # sample size.
  119 + figure = plt.figure()
  120 + plot = figure.add_subplot(111)
  121 + plot.grid(True)
  122 + plot.plot(result, color='r', linewidth=2.0)
  123 + plt.axis([0, 100, 0, 1.1])
  124 + plt.title('Embedding probability for different percentages \
  125 +of the file capacity.')
  126 + plt.xlabel('% of file capacity')
  127 + plt.ylabel('Embedding probability')
  128 +
  129 + if self.core.media_manager.is_media_key(tgt):
  130 + img = figure_to_pil(figure)
  131 + self.core.media_manager.put_media(tgt, img)
  132 + else:
  133 + plt.savefig(tgt)
  134 +
  135 + # Image displaying the length and position of the embedded data
  136 + # within the image
  137 + img2 = Image.open(src)
  138 + img2.convert("RGB")
  139 + width, height = img2.size
  140 +
  141 + for i in range(100):
  142 + result[i] = max(result[i:])
  143 +
  144 + cnt2 = 0
  145 + for (top, left) in it.product(range(0, height, 8), range(0, width, 8)):
  146 + if not cnt2 % one_p:
  147 + r = result[cnt2 / one_p]
  148 + if r >= 0.5:
  149 + color = (255, int((1 - r) * 2 * 255), 0)
  150 + else:
  151 + color = (int(r * 2 * 255), 255, 0)
  152 + cnt2 += 1
  153 + img2.paste(color, (left, top, min(left + 8, width),
  154 + min(top + 8, height)))
  155 + self.core.media_manager.put_media(tgt2, img2)
  156 +
  157 + def __str__(self):
  158 + return 'Chi-Square-Test'
  159 +
  160 +
  161 +def figure_to_pil(figure):
  162 + figure.canvas.draw()
  163 + return Image.fromstring('RGB',
  164 + figure.canvas.get_width_height(),
  165 + figure.canvas.tostring_rgb())
... ...
msteg/steganography/StegBase.py
... ... @@ -1,148 +0,0 @@
1   -"""
2   -This module implements a common base class of the steganographic
3   -algorithms which embed data into JPEG files.
4   -In order to run plugins inheriting from this class
5   -you must build the rw_dct.so library which interfaces with libjpeg.
6   -To do so, just run
7   -% python setup.py build
8   -in stegotool/util and copy the rw_dct.so
9   -library (which can be found somewhere in the build-directory to
10   -stegotool/util.
11   -
12   -"""
13   -import numpy as np
14   -import time
15   -import os
16   -import sys
17   -import random
18   -import re
19   -
20   -import mjsteg
21   -import jpegObj
22   -from common import *
23   -
24   -
25   -class StegBase(object):
26   - """
27   - This is the base class for some of the JPEG-algorithms that behave
28   - similarly such as JSteg, OutGuess and F3.
29   - """
30   -
31   - def __init__(self):
32   - """
33   - Constructor of the JPEGSteg class.
34   - """
35   - self.t0 = None
36   - self.cov_jpeg = None
37   - self.cov_data = None
38   - self.hid_data = None
39   -
40   - def _get_cov_data(self, img_path):
41   - """
42   - Returns DCT coefficients of the cover image.
43   - """
44   - self.cov_jpeg = jpegObj.Jpeg(img_path)
45   - self.cov_data = self.cov_jpeg.getCoefBlocks()
46   - return self.cov_data
47   -
48   -
49   - def _get_hid_data(self, src_hidden):
50   - """
51   - Returnsthe secret data as byte sequence.
52   - """
53   - raw = [0, 0, 0, 0] + np.fromfile(src_hidden, np.uint8).tolist()
54   - raw_size = len(raw)
55   - for i in xrange(4):
56   - raw[i] = raw_size % 256
57   - raw_size /= 256
58   - self.hid_data = np.array(raw)
59   -
60   - if np.size(self.hid_data) * 8 > np.size(self.cov_data):
61   - raise Exception("Cover image is too small to embed data.Cannot fit %d bits in %d DCT coefficients" % (
62   - np.size(self.hid_data) * 8, np.size(self.cov_data)))
63   - return self.hid_data
64   -
65   -
66   - def _post_embed_actions(self, src_cover, src_hidden, tgt_stego):
67   - """
68   - This function isn't named very accurately. It actually calls the
69   - _raw_embed function in inherited classes.
70   - """
71   - try:
72   - cov_data = self._get_cov_data(src_cover)
73   - hid_data = self._get_hid_data(src_hidden)
74   - cov_data = self._raw_embed(cov_data, hid_data)
75   -
76   - self.cov_jpeg.setCoefBlocks(cov_data)
77   - self.cov_jpeg.Jwrite(tgt_stego)
78   -
79   - size = os.path.getsize(tgt_stego)
80   - size_embedded = np.size(hid_data)
81   -
82   - self._display_stats("embedded", size, size_embedded,
83   - time.time() - self.t0)
84   -
85   - except TypeError as e:
86   - raise e
87   - except Exception:
88   - raise Exception(
89   - 'DCT coefficients exhausted. This usually means there are not enough DCT coefficients in the image in which algorithm can actually embed data. You should choose a larger image.')
90   -
91   - def _post_extract_actions(self, src_steg, tgt_hidden):
92   - """
93   - This function isn't named very accurately. It actually calls the
94   - _raw_extract function in inherited classes.
95   - """
96   - try:
97   - steg_data = self._get_cov_data(src_steg)
98   - emb_size = os.path.getsize(src_steg)
99   -
100   - # recovering file size
101   - header_size = 4 * 8
102   - size_data = self._raw_extract(steg_data, header_size)
103   - size_data = bits2bytes(size_data)
104   - size_hd = 0
105   - for i in xrange(4):
106   - size_hd += size_data[i] * 256 ** i
107   -
108   - raw_size = size_hd * 8
109   -
110   - if raw_size > np.size(steg_data):
111   - raise Exception("Supposed secret data too large for stego image.")
112   -
113   - hid_data = self._raw_extract(steg_data, raw_size)
114   - hid_data = bits2bytes(hid_data)
115   - hid_data[4:].tofile(tgt_hidden)
116   -
117   - self._display_stats("extracted", emb_size,
118   - np.size(hid_data),
119   - time.time() - self.t0)
120   - except:
121   - raise Exception('DCT coefficients exhausted.The stego image is probably corrupted.')
122   -
123   -
124   - def _looks_like_jpeg(self, path):
125   - try:
126   - with open(path, 'r') as f:
127   - return f.read(2) == '\xff\xd8'
128   - except IOError:
129   - return False
130   -
131   - def _display_stats(self, verb, cov_size, emb_size, duration):
132   - print(
133   - "%dB %s in %.2fs (%.2f kBps), embedding ratio: %.4f" %
134   - (emb_size, verb, duration, (emb_size / duration) / 1000.,
135   - float(emb_size) / cov_size))
136   -
137   - # dummy functions to please pylint
138   - def _raw_embed(self, cov_data, hid_data, status_begin=0):
139   - pass
140   -
141   - def _raw_extract(self, steg_data, num_bits):
142   - pass
143   -
144   - def _dummy_embed_hook(self, cov_data, hid_data):
145   - pass
146   -
147   - def _dummy_extract_hook(self, steg_data, num_bits):
148   - pass
res/embeded
1 1 this is to be embeded.
  2 +//0216
  3 +vim of clang - https://github.com/JBakamovic/yavide
  4 +# Usage overview
  5 +Category | Shortcut | Description
  6 +--------------------------------- | --------------------------------- | ---------------------------------
  7 +**Project management** | |
  8 + | `<Ctrl-s>n` | Create new project
  9 + | `<Ctrl-s>i` | Import project with already existing code base
  10 + | `<Ctrl-s>o` | Open project
  11 + | `<Ctrl-s>c` | Close project
  12 + | `<Ctrl-s>s` | Save project
  13 + | `<Ctrl-s>d` | Delete project
  14 +**Buffer management** | |
  15 + | `<Ctrl-c>` | Close current buffer
  16 + | `<Ctrl-s>` | Save current buffer
  17 + | `<Ctrl-Tab>` | Go to next buffer
  18 + | `<Ctrl-Shift-Tab>` | Go to previous buffer
  19 + | `<Ctrl-Down>` | Scroll buffer by one line (down)
  20 + | `<Ctrl-Up>` | Scroll buffer by one line (up)
  21 +**Buffer modes** | |
  22 + | `<ESC>` | Enter the `normal` mode
  23 + | `<a>` | Enter the `insert` mode (append after cursor)
  24 + | `<i>` | Enter the `insert` mode (insert before cursor)
  25 + | `<Shift-v>` | Enter the `visual` mode (line mode)
  26 + | `<v>` | Enter the `visual` mode (character mode)
  27 +**Buffer editing** | |
  28 + | `<Ctrl-a>` | Select all
  29 + | `<Ctrl-x>` | Cut
  30 + | `<Ctrl-c>` | Copy
  31 + | `<Ctrl-v>` | Paste
  32 + | `<Ctrl-z>` | Undo
  33 + | `<Ctrl-r>` | Redo
  34 + | `<Shift-s>` | Delete the whole line
... ...
res/extracted
1 1 Binary files a/res/extracted and b/res/extracted differ
... ...
res/steged.jpg

50.3 KB | W: | H:

43.7 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin