Commit 8cfc1a2373c0fb2aa9b6fcbd6a4e795f3ac76320
1 parent
033d3b0d
Exists in
master
F5 half-finished.
Showing
13 changed files
with
278 additions
and
203 deletions
Show diff stats
jpegObj/__init__.pyc
No preview for this file type
msteg/StegBase.py
... | ... | @@ -102,6 +102,10 @@ class StegBase(object): |
102 | 102 | # recovering file size |
103 | 103 | header_size = 4 * 8 |
104 | 104 | size_data, bits_cnt = self._raw_extract(steg_data, header_size) |
105 | + if bits_cnt < header_size: | |
106 | + raise Exception("Expected embedded size is %db but actually %db." % ( | |
107 | + header_size, bits_cnt)) | |
108 | + | |
105 | 109 | size_data = bits2bytes(size_data) |
106 | 110 | size_hd = 0 |
107 | 111 | for i in xrange(4): | ... | ... |
msteg/StegBase.pyc
No preview for this file type
msteg/steganography/F3.pyc
No preview for this file type
... | ... | @@ -0,0 +1,101 @@ |
1 | +__author__ = 'chunk' | |
2 | + | |
3 | +""" | |
4 | +<p>This module implements a slight variant of the F4 steganography algorithm | |
5 | +invented by Andreas Westfeld. It embeds a secret message in JPEG | |
6 | +DCT coefficients.</p> | |
7 | +It differs from F3 in that even negative and odd positive DCT | |
8 | +coefficients represent a 1 and odd negative and even positive | |
9 | +DCT coefficients represent a 0. It also supports permutative strattling | |
10 | +which is not included in the original description of F4. | |
11 | +""" | |
12 | +import time | |
13 | +import numpy as np | |
14 | +from msteg.StegBase import StegBase | |
15 | +from common import * | |
16 | + | |
17 | + | |
18 | +class F4(StegBase): | |
19 | + """ This module has two methods: <i>embed_raw_data</i> to embed data | |
20 | + with the F3 algorithm and <i>extract_raw_data</i> to extract data | |
21 | + which was embedded previously. """ | |
22 | + | |
23 | + def __init__(self): | |
24 | + """ | |
25 | + Constructor of the F3 class. | |
26 | + """ | |
27 | + StegBase.__init__(self) | |
28 | + | |
29 | + def embed_raw_data(self, src_cover, src_hidden, tgt_stego): | |
30 | + """ This method embeds arbitrary data into a cover image. | |
31 | + The cover image must be a JPEG. | |
32 | + | |
33 | + src_cover - A valid pathname to an image file which serves as cover image | |
34 | + (the image which the secret image is embedded into). | |
35 | + | |
36 | + src_hidden - A valid pathname to an arbitrary file that is supposed to be | |
37 | + embedded into the cover image. | |
38 | + | |
39 | + tgt_stego - Target pathname of the resulting stego image. You should save to a | |
40 | + PNG or another lossless format, because many LSBs don't survive | |
41 | + lossy compression. | |
42 | + """ | |
43 | + self.t0 = time.time() | |
44 | + StegBase._post_embed_actions(self, src_cover, src_hidden, tgt_stego) | |
45 | + | |
46 | + def extract_raw_data(self, src_steg, tgt_hidden): | |
47 | + """ This method extracts secret data from a stego image. It is | |
48 | + (obviously) the inverse operation of embed_raw_data. | |
49 | + | |
50 | + src_stego - A valid pathname to an image file which serves as stego image. | |
51 | + | |
52 | + tgt_hidden - A pathname denoting where the extracted data should be saved to. | |
53 | + """ | |
54 | + self.t0 = time.time() | |
55 | + StegBase._post_extract_actions(self, src_steg, tgt_hidden) | |
56 | + | |
57 | + def _raw_embed(self, cov_data, hid_data, status_begin=0): | |
58 | + """ | |
59 | + cov_data - 4-D numpy.int32 array | |
60 | + hid_data - 1-D numpy.uint8 array | |
61 | + """ | |
62 | + hid_data = bytes2bits(hid_data) | |
63 | + i = 0 | |
64 | + cnt = -1 | |
65 | + for x in np.nditer(cov_data, op_flags=['readwrite']): | |
66 | + cnt = cnt + 1 | |
67 | + if x == 0 or cnt % 64 == 0: continue | |
68 | + | |
69 | + m = (hid_data[i] & 1) | |
70 | + if x > 0 and x & 1 != m: | |
71 | + x[...] -= 1 | |
72 | + elif x < 0 and x & 1 == m: | |
73 | + x[...] += 1 | |
74 | + if x == 0: continue | |
75 | + i += 1 | |
76 | + if i == hid_data.size: break | |
77 | + | |
78 | + return cov_data | |
79 | + | |
80 | + def _raw_extract(self, steg_data, num_bits): | |
81 | + """ | |
82 | + Just a small helper function to extract hidden data. | |
83 | + """ | |
84 | + hid_data = np.zeros(num_bits, np.uint8) | |
85 | + j = 0 | |
86 | + cnt = -1 | |
87 | + for x in np.nditer(steg_data): | |
88 | + cnt = cnt + 1 | |
89 | + if x == 0 or cnt % 64 == 0: continue | |
90 | + if j >= num_bits: break | |
91 | + if x > 0: | |
92 | + hid_data[j] = x & 1 | |
93 | + else: | |
94 | + hid_data[j] = (x & 1) ^ 1 | |
95 | + | |
96 | + j = j + 1 | |
97 | + | |
98 | + return hid_data | |
99 | + | |
100 | + def __str__(self): | |
101 | + return "F4'" | ... | ... |
msteg/steganography/F4.py
... | ... | @@ -74,6 +74,10 @@ class F4(StegBase): |
74 | 74 | # recovering file size |
75 | 75 | header_size = 4 * 8 |
76 | 76 | size_data, bits_cnt = self._raw_extract(steg_data, header_size) |
77 | + if bits_cnt < header_size: | |
78 | + raise Exception("Expected embedded size is %db but actually %db." % ( | |
79 | + header_size, bits_cnt)) | |
80 | + | |
77 | 81 | size_data = bits2bytes(size_data) |
78 | 82 | |
79 | 83 | size_hd = 0 |
... | ... | @@ -120,6 +124,7 @@ class F4(StegBase): |
120 | 124 | if x == 0: continue |
121 | 125 | i += 1 |
122 | 126 | if i == hid_data.size: break |
127 | + | |
123 | 128 | return cov_data, i |
124 | 129 | |
125 | 130 | def _raw_extract(self, steg_data, num_bits): |
... | ... | @@ -127,6 +132,7 @@ class F4(StegBase): |
127 | 132 | Just a small helper function to extract hidden data. |
128 | 133 | steg_data - 1-D numpy.int16 array (permunated) |
129 | 134 | """ |
135 | + | |
130 | 136 | hid_data = np.zeros(num_bits, np.uint8) |
131 | 137 | j = 0 |
132 | 138 | for x in steg_data: | ... | ... |
msteg/steganography/F4.pyc
No preview for this file type
msteg/steganography/F5.py
1 | +__author__ = 'chunk' | |
2 | + | |
1 | 3 | """ |
2 | 4 | <p>This module implements the rather sophisticated F5 algorithm which was |
3 | 5 | invented by Andreas Westfeld.</p> |
... | ... | @@ -35,118 +37,134 @@ class F5(StegBase): |
35 | 37 | with the F5 algorithm and <i>extract_raw_data</i> to extract data |
36 | 38 | which was embedded previously. """ |
37 | 39 | |
38 | - def __init__(self, key=sample_key): | |
40 | + def __init__(self, key=sample_key, k=None): | |
39 | 41 | """ |
40 | 42 | Constructor of the F5 class. |
41 | 43 | """ |
42 | 44 | StegBase.__init__(self, key) |
43 | 45 | self._embed_fun = None |
44 | 46 | self.default_embedding = True |
45 | - self.steg_ind = -1 | |
46 | - self.excess_bits = None | |
47 | + | |
47 | 48 | # needed because k is embedded separately |
48 | - self.cov_ind = -1 | |
49 | - self.k_coeff = -1 | |
50 | - | |
51 | - @describe_annotate_convert((None, None, ident), | |
52 | - ("cover image", ImagePath, str), | |
53 | - ("hidden data", FilePath, str), | |
54 | - ("stego image", NewFilePath, str), | |
55 | - ("seed", int, int), | |
56 | - ("embedding behavior", | |
57 | - ['Default', 'F3', 'JSteg'], str)) | |
58 | - def embed_raw_data(self, src_cover, src_hidden, tgt_stego, seed, | |
59 | - embed_fun): | |
60 | - """<p>This method embeds arbitrary data into a cover image. | |
61 | - The cover image must be a JPEG.</p> | |
62 | - | |
63 | - <p>Parameters: | |
64 | - <ol> | |
65 | - <li><pre>src_cover</pre> | |
66 | - A valid pathname to an image file which serves as cover image | |
67 | - (the image which the secret image is embedded into).</li> | |
68 | - | |
69 | - <li><pre>src_hidden</pre> | |
70 | - A valid pathname to an arbitrary file that is supposed to be | |
71 | - embedded into the cover image.</li> | |
72 | - | |
73 | - <li><pre>tgt_stego</pre> | |
74 | - Target pathname of the resulting stego image. You should save to | |
75 | - a PNG or another lossless format, because many LSBs don't survive | |
76 | - lossy compression.</li> | |
77 | - | |
78 | - <li><pre>seed</pre> | |
79 | - A seed for the random number generator that is responsible scattering | |
80 | - the secret data within the cover image.</li> | |
81 | - | |
82 | - <li><pre>param embed_fun</pre> | |
49 | + self.k_coeff = k | |
50 | + | |
51 | + | |
52 | + def _get_cov_data(self, img_path): | |
53 | + """ | |
54 | + Returns DCT coefficients of the cover image. | |
55 | + """ | |
56 | + self.cov_jpeg = jpegObj.Jpeg(img_path, key=self.key) | |
57 | + | |
58 | + cov_data = self.cov_jpeg.getsignal(channel='Y') | |
59 | + self.cov_data = np.array(cov_data, dtype=np.int16) | |
60 | + return self.cov_data | |
61 | + | |
62 | + def embed_raw_data(self, src_cover, src_hidden, tgt_stego, embed_fun='Default'): | |
63 | + """This method embeds arbitrary data into a cover image. | |
64 | + The cover image must be a JPEG. | |
65 | + | |
66 | + @param embed_fun: | |
83 | 67 | Specifies which embedding function should be used. Must be one of |
84 | 68 | 'Default', 'F3', 'Jsteg'. If 'Default' is selected, the algorithm uses |
85 | 69 | the same behavior as Westfeld's implementation, i.e. decrementing |
86 | 70 | absolute values for n > 1 (F3) and using F4 in the special case n = 1. |
87 | - Selecting F3 or JSteg results in using that scheme for all n.</li> | |
88 | - </ol> | |
89 | - </p> | |
71 | + Selecting F3 or JSteg results in using that scheme for all n. | |
90 | 72 | """ |
91 | 73 | self.t0 = time.time() |
92 | - self.seed = seed | |
74 | + | |
93 | 75 | if embed_fun == 'F3': |
94 | 76 | self._embed_fun = self._f3_embed |
95 | 77 | self.default_embedding = False |
96 | - elif embed_fun == 'JSteg': | |
78 | + elif embed_fun == 'JSteg' or embed_fun == 'LSB': | |
97 | 79 | self._embed_fun = self._jsteg_embed |
98 | 80 | self.default_embedding = False |
99 | - elif embed_fun == 'Default': | |
81 | + else: | |
100 | 82 | self._embed_fun = self._f3_embed |
101 | 83 | self.default_embedding = True |
102 | 84 | |
103 | - self.cov_ind = -1 | |
104 | - JPEGSteg._post_embed_actions(self, src_cover, src_hidden, tgt_stego) | |
85 | + try: | |
86 | + cov_data = self._get_cov_data(src_cover) | |
87 | + hid_data = self._get_hid_data(src_hidden) | |
88 | + # print hid_data.dtype,type(hid_data),hid_data.tolist() | |
105 | 89 | |
106 | - @describe_annotate_convert((None, None, ident), | |
107 | - ("stego image", ImagePath, str), | |
108 | - ("hidden data", NewFilePath, str), | |
109 | - ("seed", int, int), | |
110 | - ("embedding behavior", ['Default', 'F3/JSteg'], | |
111 | - str)) | |
112 | - def extract_raw_data(self, src_steg, tgt_hidden, seed, embed_fun): | |
113 | - """<p>This method extracts secret data from a stego image. It is | |
114 | - (obviously) the inverse operation of embed_raw_data.</p> | |
90 | + cov_data, bits_cnt = self._raw_embed(cov_data, hid_data) | |
115 | 91 | |
116 | - <p>Parameters: | |
117 | - <ol> | |
118 | - <li><pre>src_stego</pre> | |
119 | - A valid pathname to an image file which serves as stego image.</li> | |
92 | + if bits_cnt < np.size(hid_data) * 8: | |
93 | + raise Exception("Expected embedded size is %db but actually %db." % ( | |
94 | + np.size(hid_data) * 8, bits_cnt)) | |
120 | 95 | |
121 | - <li><pre>tgt_hidden</pre> | |
122 | - A pathname denoting where the extracted data should be saved to.</li> | |
96 | + self.cov_jpeg.setsignal(cov_data, channel='Y') | |
97 | + self.cov_jpeg.Jwrite(tgt_stego) | |
123 | 98 | |
124 | - <li><pre>param seed</pre> | |
125 | - A seed for the random number generator that is responsible scattering | |
126 | - the secret data within the cover image.</li> | |
99 | + # size_cov = os.path.getsize(tgt_stego) | |
100 | + size_cov = np.size(cov_data) / 8 | |
101 | + size_embedded = np.size(hid_data) | |
127 | 102 | |
128 | - <li><pre>param embed_fun</pre> | |
129 | - Specifies which embedding function should be used. Must be one of | |
130 | - 'Default', 'F3', 'JSteg'. If 'Default' is selected, the algorithm uses | |
131 | - the same behavior as Westfeld's implementation, i.e. decrementing | |
132 | - absolute values for n > 1 (F3) and using F4 in the special case n = 1. | |
133 | - Selecting F3 or JSteg results in using that scheme for all n.</li> | |
134 | - </ol></pre> | |
135 | - """ | |
103 | + self._display_stats("embedded", size_cov, size_embedded, | |
104 | + time.time() - self.t0) | |
136 | 105 | |
106 | + except TypeError as e: | |
107 | + raise e | |
108 | + except Exception as expt: | |
109 | + print "Exception when embedding!" | |
110 | + raise | |
111 | + | |
112 | + | |
113 | + def extract_raw_data(self, src_steg, tgt_hidden, embed_fun='Default'): | |
137 | 114 | self.t0 = time.time() |
138 | - self.seed = seed | |
139 | - self.steg_ind = -1 | |
140 | - if embed_fun == 'F3/JSteg': | |
115 | + | |
116 | + if embed_fun == 'F3': | |
117 | + self._embed_fun = self._f3_embed | |
118 | + self.default_embedding = False | |
119 | + elif embed_fun == 'JSteg' or embed_fun == 'LSB': | |
120 | + self._embed_fun = self._jsteg_embed | |
141 | 121 | self.default_embedding = False |
142 | - elif embed_fun == 'Default': | |
122 | + else: | |
123 | + self._embed_fun = self._f3_embed | |
143 | 124 | self.default_embedding = True |
144 | 125 | |
145 | - # excess bits occur when the size of extracted data is not a multiple | |
146 | - # of k. if excess bits are available, they are prepended to hidden data | |
147 | - self.excess_bits = None | |
126 | + try: | |
127 | + steg_data = self._get_cov_data(src_steg) | |
128 | + # emb_size = os.path.getsize(src_steg) | |
129 | + emb_size = np.size(steg_data) / 8 | |
130 | + | |
131 | + # recovering file size | |
132 | + header_size = 4 * 8 | |
133 | + size_data, bits_cnt = self._raw_extract(steg_data, header_size) | |
134 | + | |
135 | + if bits_cnt < header_size: | |
136 | + raise Exception("Expected embedded size is %db but actually %db." % ( | |
137 | + header_size, bits_cnt)) | |
138 | + | |
139 | + size_data = bits2bytes(size_data[:header_size]) | |
140 | + print size_data | |
141 | + | |
142 | + size_hd = 0 | |
143 | + for i in xrange(4): | |
144 | + size_hd += size_data[i] * 256 ** i | |
145 | + | |
146 | + raw_size = size_hd * 8 | |
147 | + | |
148 | + if raw_size > np.size(steg_data): | |
149 | + raise Exception("Supposed secret data too large for stego image.") | |
150 | + | |
151 | + hid_data, bits_cnt = self._raw_extract(steg_data, raw_size) | |
152 | + | |
153 | + if bits_cnt < raw_size: | |
154 | + raise Exception("Expected embedded size is %db but actually %db." % ( | |
155 | + raw_size, bits_cnt)) | |
156 | + | |
157 | + hid_data = bits2bytes(hid_data) | |
158 | + # print hid_data.dtype,type(hid_data),hid_data.tolist() | |
159 | + hid_data[4:].tofile(tgt_hidden) | |
160 | + | |
161 | + self._display_stats("extracted", emb_size, | |
162 | + np.size(hid_data), | |
163 | + time.time() - self.t0) | |
164 | + except Exception as expt: | |
165 | + print "Exception when extracting!" | |
166 | + raise | |
148 | 167 | |
149 | - JPEGSteg._post_extract_actions(self, src_steg, tgt_hidden) | |
150 | 168 | |
151 | 169 | def _embed_k(self, cov_data, hid_data): |
152 | 170 | np.random.seed(self.seed) |
... | ... | @@ -218,153 +236,89 @@ class F5(StegBase): |
218 | 236 | |
219 | 237 | def _jsteg_embed(self, cov_data, ind): |
220 | 238 | m = 1 ^ (cov_data[ind] & 1) |
221 | - cov_data[ind] = (cov_data[ind] & 0xffffe) | m | |
239 | + cov_data[ind] = (cov_data[ind] & 0xfffffffe) | m | |
222 | 240 | |
223 | - def _raw_embed(self, cov_data, hid_data, status_begin=0): | |
241 | + def _raw_embed(self, cov_data, hid_data): | |
224 | 242 | k = self.k_coeff |
225 | 243 | n = (1 << k) - 1 |
244 | + | |
226 | 245 | if n == 1 and self.default_embedding: |
227 | - # in case k = n = 1, Westfeld's implementation uses F4 for | |
228 | - # embedding. Therefore, if 'default' embedding has been selected | |
229 | - # we will do the same | |
230 | - f4 = F4(self.ui, self.core) | |
231 | - f4.seed = self.seed | |
232 | - f4.dct_p = self.dct_p | |
233 | - f4.cov_ind = self.cov_ind | |
234 | - cov_data = f4._raw_embed(cov_data, hid_data, 30) | |
235 | - return cov_data | |
236 | - | |
237 | - cov_ind = self.cov_ind # preventing RSI by writing 'self' less often | |
238 | - hid_ind = 0 | |
239 | - remaining_bits = hid_data.size | |
240 | - hid_size = float(hid_data.size) | |
241 | - dct_p = self.dct_p | |
242 | - | |
243 | - update_cnt = int(hid_size / (70.0 * k)) | |
244 | - while remaining_bits > 0: | |
245 | - if update_cnt == 0: | |
246 | - self._set_progress(30 + int((( | |
247 | - hid_size - remaining_bits) / hid_size) * 70)) | |
248 | - update_cnt = int(hid_size / (70.0 * k)) | |
249 | - update_cnt -= 1 | |
250 | - msg_chunk_size = min(remaining_bits, k) | |
251 | - msg_chunk = np.zeros(k, np.int8) | |
252 | - cov_chunk = np.zeros(n, np.int32) | |
253 | - msg_chunk[0:msg_chunk_size] = hid_data[hid_ind:hid_ind + | |
254 | - msg_chunk_size] | |
255 | - hid_ind += k | |
256 | - | |
257 | - # get n DCT coefficients | |
258 | - for i in xrange(n): | |
259 | - cov_ind += 1 | |
260 | - while cov_data[dct_p[cov_ind]] == 0 \ | |
261 | - or dct_p[cov_ind] % 64 == 0: | |
262 | - cov_ind += 1 | |
263 | - cov_chunk[i] = dct_p[cov_ind] | |
246 | + # in case k = n = 1, Westfeld's implementation uses F4 for embedding. | |
247 | + f4 = F4(key=self.key) | |
248 | + return f4._raw_embed(cov_data, hid_data) | |
249 | + | |
250 | + hid_data = bytes2bits(hid_data) | |
251 | + if len(hid_data) % k != 0: | |
252 | + hid_data = list(hid_data) + [0 for x in range(k - len(hid_data) % k)] | |
253 | + | |
254 | + ind_nonzero = np.nonzero(cov_data)[0] | |
255 | + | |
256 | + if np.size(ind_nonzero) * k < len(hid_data) * n: | |
257 | + raise Exception("Supposed secret data too large for stego image.") | |
258 | + | |
259 | + ind_cov = 0 | |
260 | + for ind_hid in range(0, len(hid_data), k): | |
261 | + msg_chunk = hid_data[ind_hid:ind_hid + k] | |
262 | + cov_chunk = ind_nonzero[ind_cov:ind_cov + n] | |
263 | + ind_cov += n | |
264 | 264 | |
265 | 265 | success = False |
266 | - while not success: # loop necessary because of shrinkage | |
266 | + while not success: | |
267 | 267 | h = 0 |
268 | 268 | for i in xrange(n): |
269 | 269 | h ^= ((cov_data[cov_chunk[i]] & 1) * (i + 1)) |
270 | 270 | scalar_x = 0 |
271 | 271 | for i in xrange(k): |
272 | - scalar_x = (scalar_x << 1) + msg_chunk[i] | |
272 | + scalar_x = (scalar_x << 1) + msg_chunk[ | |
273 | + i] # N.B. hid_data[0]:high (that is x2), hid_data[1]:low (that is x1) | |
273 | 274 | s = scalar_x ^ h |
274 | 275 | if s != 0: |
275 | 276 | self._embed_fun(cov_data, cov_chunk[s - 1]) |
276 | 277 | else: |
277 | 278 | break |
278 | 279 | |
279 | - if cov_data[cov_chunk[s - 1]] == 0: # test for shrinkage | |
280 | - cov_chunk[s - 1:-1] = cov_chunk[s:] # adjusting | |
281 | - cov_ind += 1 | |
282 | - while cov_data[dct_p[cov_ind]] == 0 or \ | |
283 | - dct_p[cov_ind] % 64 == 0: | |
284 | - cov_ind += 1 | |
285 | - cov_chunk[n - 1] = dct_p[cov_ind] | |
280 | + if cov_data[cov_chunk[s - 1]] == 0: # shrinkage | |
281 | + cov_chunk[s - 1:-1] = cov_chunk[s:] | |
282 | + cov_chunk[-1] = ind_nonzero[ind_cov] | |
283 | + ind_cov += 1 | |
286 | 284 | else: |
287 | 285 | success = True |
288 | 286 | |
289 | - remaining_bits -= k | |
290 | - | |
291 | - self.k_coeff = -1 # prevent k being read from this instance | |
292 | - return cov_data | |
287 | + return cov_data, ind_hid + k | |
293 | 288 | |
294 | - def _raw_extract(self, num_bits): | |
289 | + def _raw_extract(self, steg_data, num_bits): | |
295 | 290 | k = self.k_coeff |
296 | 291 | n = (1 << k) - 1 |
297 | - if self.is_header == None: | |
298 | - self.is_header = True | |
299 | - if n == 1 and self.default_embedding: | |
300 | - f4 = F4(self.ui, self.core) | |
301 | - f4.seed = self.seed | |
302 | - f4.dct_p = self.dct_p | |
303 | - f4.steg_data = self.steg_data | |
304 | - f4.is_header = self.is_header | |
305 | - f4.steg_ind = self.steg_ind | |
306 | - hid_data = f4._raw_extract(num_bits) | |
307 | - self.steg_ind = f4.steg_ind | |
308 | - self.is_header = False | |
309 | - return hid_data | |
310 | - remaining_bits = num_bits | |
311 | - hid_data = np.zeros(num_bits, np.uint8) | |
312 | - hid_ind = 0 | |
313 | - | |
314 | - dct_p = self.dct_p | |
315 | - | |
316 | - is_header = False # signals whether or not extracting header | |
317 | - | |
318 | - if self.excess_bits != None: | |
319 | - hid_data[hid_ind:hid_ind + self.excess_bits.size] = \ | |
320 | - self.excess_bits | |
321 | - hid_ind += self.excess_bits.size | |
322 | - remaining_bits -= self.excess_bits.size | |
323 | - | |
324 | - curr_chunk = np.zeros(k, np.uint8) | |
325 | - | |
326 | - update_cnt = int(num_bits / (100.0 * k)) | |
327 | - | |
328 | - while remaining_bits > 0: | |
329 | 292 | |
330 | - if update_cnt == 0 and not is_header: | |
331 | - self._set_progress(int(((float(num_bits) \ | |
332 | - - remaining_bits) / num_bits) * 100)) | |
333 | - update_cnt = int(num_bits / (100.0 * k)) | |
293 | + if n == 1 and self.default_embedding: | |
294 | + f4 = F4(key=self.key) | |
295 | + return f4._raw_extract(steg_data, num_bits) | |
334 | 296 | |
335 | - update_cnt -= 1 | |
297 | + num_bits_ceil = num_bits | |
298 | + if num_bits % k != 0: | |
299 | + num_bits_ceil = k * (num_bits / k + 1) | |
336 | 300 | |
337 | - steg_chunk = [0 for i in xrange(n)] | |
338 | - for i in xrange(n): | |
339 | - self.steg_ind += 1 | |
340 | - while self.steg_data[dct_p[self.steg_ind]] == 0 or \ | |
341 | - dct_p[self.steg_ind] % 64 == 0: | |
342 | - self.steg_ind += 1 | |
343 | - steg_chunk[i] = self.steg_data[dct_p[self.steg_ind]] | |
301 | + hid_data = np.zeros(num_bits_ceil, np.uint8) | |
302 | + curr_chunk = np.zeros(k, np.uint8) | |
303 | + steg_data = steg_data[np.nonzero(steg_data)] | |
304 | + ind_hid = 0 | |
305 | + for ind_cov in range(0, len(steg_data), n): | |
306 | + steg_chunk = steg_data[ind_cov:ind_cov + n] | |
344 | 307 | |
345 | 308 | h = 0 # hash value |
346 | 309 | for i in xrange(n): |
347 | 310 | h ^= ((steg_chunk[i] & 1) * (i + 1)) |
348 | 311 | |
349 | 312 | for i in xrange(k): |
350 | - curr_chunk[k - i - 1] = h % 2 | |
351 | - h /= 2 | |
352 | - | |
353 | - l = min(k, remaining_bits) | |
354 | - for i in xrange(l): | |
355 | - hid_data[hid_ind] = curr_chunk[i] | |
356 | - hid_ind += 1 | |
313 | + curr_chunk[k - i - 1] = h & 1 # N.B. hid_data[0]:high (that is x2), hid_data[1]:low (that is x1) | |
314 | + h >>= 1 | |
357 | 315 | |
358 | - # save excess bits (for later calls) | |
359 | - if k > remaining_bits: | |
360 | - self.excess_bits = curr_chunk[remaining_bits:] | |
361 | - else: | |
362 | - self.excess_bits = None | |
316 | + hid_data[ind_hid:ind_hid + k] = curr_chunk[0:k] | |
317 | + ind_hid += k | |
363 | 318 | |
364 | - remaining_bits -= k | |
319 | + if ind_hid >= num_bits_ceil: break | |
365 | 320 | |
366 | - self.is_header = False | |
367 | - return hid_data | |
321 | + return hid_data, num_bits_ceil | |
368 | 322 | |
369 | 323 | def __str__(self): |
370 | 324 | return 'F5' | ... | ... |
msteg/steganography/F5.pyc
No preview for this file type
msteg/steganography/LSB.pyc
No preview for this file type
res/steged.jpg
test_jpeg.py
... | ... | @@ -17,7 +17,9 @@ sample = [[7, 12, 14, -12, 1, 0, -1, 0], |
17 | 17 | [0, 0, 0, 0, 0, 0, 0, 0], |
18 | 18 | [0, 0, 0, 0, 0, 0, 0, 0]] |
19 | 19 | |
20 | -sample_key = [46812L, 20559L, 31360L, 16681L, 27536L, 39553L, 5427L, 63029L, 56572L, 36476L, 25695L, 61908L, 63014L, 5908L, 59816L, 56765L] | |
20 | +sample_key = [46812L, 20559L, 31360L, 16681L, 27536L, 39553L, 5427L, 63029L, 56572L, 36476L, 25695L, 61908L, 63014L, | |
21 | + 5908L, 59816L, 56765L] | |
22 | + | |
21 | 23 | |
22 | 24 | def diffblock(c1, c2): |
23 | 25 | diff = False |
... | ... | @@ -32,6 +34,7 @@ def diffblock(c1, c2): |
32 | 34 | |
33 | 35 | def diffblocks(a, b): |
34 | 36 | diff = False |
37 | + cnt = 0 | |
35 | 38 | for comp in range(a.image_components): |
36 | 39 | xmax, ymax = a.Jgetcompdim(comp) |
37 | 40 | for y in range(ymax): |
... | ... | @@ -39,7 +42,8 @@ def diffblocks(a, b): |
39 | 42 | if a.Jgetblock(x, y, comp) != b.Jgetblock(x, y, comp): |
40 | 43 | print("blocks({},{}) in component {} not match".format(y, x, comp)) |
41 | 44 | diff = True |
42 | - return diff | |
45 | + cnt += 1 | |
46 | + return diff, cnt | |
43 | 47 | |
44 | 48 | |
45 | 49 | def test_setblocks(): |
... | ... | @@ -131,17 +135,18 @@ def test_rawfile(): |
131 | 135 | raw[i] = raw_size % 256 |
132 | 136 | raw_size /= 256 |
133 | 137 | raw = np.array(raw) |
134 | - print raw.shape,raw | |
138 | + print raw.shape, raw | |
135 | 139 | # print raw.size |
136 | 140 | # print bytes2bits(raw) |
137 | 141 | |
142 | + | |
138 | 143 | def test_bitbyte(): |
139 | 144 | timer.mark() |
140 | 145 | raw = np.fromfile("res/test4.jpg", np.uint8) |
141 | 146 | timer.report() |
142 | 147 | print raw |
143 | 148 | |
144 | - bitsraw = bytes2bits(raw) | |
149 | + bitsraw = bytes2bits(raw) | |
145 | 150 | # bitsraw = bitsraw[:24] |
146 | 151 | timer.report() |
147 | 152 | print bitsraw |
... | ... | @@ -150,6 +155,7 @@ def test_bitbyte(): |
150 | 155 | timer.report() |
151 | 156 | print bytesraw |
152 | 157 | |
158 | + | |
153 | 159 | def test_iter(): |
154 | 160 | imb = jpegObj.Jpeg("res/test4.jpg") |
155 | 161 | blocks = imb.getCoefBlocks(channel='Y') |
... | ... | @@ -186,12 +192,12 @@ if __name__ == '__main__': |
186 | 192 | |
187 | 193 | # test_bitbyte() |
188 | 194 | |
189 | - ima = jpegObj.Jpeg("res/test3.jpg",key=sample_key) | |
195 | + ima = jpegObj.Jpeg("res/test3.jpg", key=sample_key) | |
190 | 196 | # imb = jpegObj.Jpeg("res/new.jpg",key=sample_key) |
191 | - imc = jpegObj.Jpeg("res/steged.jpg",key=sample_key) | |
197 | + imc = jpegObj.Jpeg("res/steged.jpg", key=sample_key) | |
192 | 198 | print ima.Jgetcompdim(0) |
193 | - print ima.getkey(),imc.getkey() | |
194 | - diffblocks(ima, imc) | |
199 | + print ima.getkey(), imc.getkey() | |
200 | + print diffblocks(ima, imc) | |
195 | 201 | |
196 | 202 | # c1 = ima.getCoefBlocks() |
197 | 203 | # c2 = imb.getCoefBlocks() | ... | ... |
test_steg.py
... | ... | @@ -7,7 +7,7 @@ import pylab as plt |
7 | 7 | import mjpeg |
8 | 8 | import mjsteg |
9 | 9 | import jpegObj |
10 | -from msteg.steganography import F3, F4, LSB | |
10 | +from msteg.steganography import LSB, F3, F4, F5 | |
11 | 11 | from common import * |
12 | 12 | |
13 | 13 | |
... | ... | @@ -22,13 +22,17 @@ sample = [[7, 12, 14, -12, 1, 0, -1, 0], |
22 | 22 | [0, 0, 0, 0, 0, 0, 0, 0], |
23 | 23 | [0, 0, 0, 0, 0, 0, 0, 0]] |
24 | 24 | |
25 | -sample_key = [46812L, 20559L, 31360L, 16681L, 27536L, 39553L, 5427L, 63029L, 56572L, 36476L, 25695L, 61908L, 63014L, 5908L, 59816L, 56765L] | |
25 | +sample_key = [46812L, 20559L, 31360L, 16681L, 27536L, 39553L, 5427L, 63029L, 56572L, 36476L, 25695L, 61908L, 63014L, | |
26 | + 5908L, 59816L, 56765L] | |
26 | 27 | |
27 | 28 | txtsample = [116, 104, 105, 115, 32, 105, 115, 32, 116, 111, 32, 98, 101, 32, 101, 109, 98, 101, 100, 101, 100, 46, 10] |
28 | 29 | |
29 | 30 | if __name__ == '__main__': |
30 | - f3test = F4.F4() | |
31 | + # f3test = F4.F4(sample_key) | |
32 | + f3test = F5.F5(sample_key, 3) | |
31 | 33 | f3test.embed_raw_data("res/test3.jpg", "res/embeded", "res/steged.jpg") |
34 | + | |
35 | + # f3test2 = F4.F4(sample_key) | |
32 | 36 | f3test.extract_raw_data("res/steged.jpg", "res/extracted") |
33 | 37 | print f3test.get_key() |
34 | 38 | pass | ... | ... |