Skip to content

Commit f6420b6

Browse files
committed
first commit
0 parents  commit f6420b6

30 files changed

+4679
-0
lines changed

2.png

14.9 KB
Loading

600.png

314 Bytes
Loading

BrVxfLaOudIoNAw.webp

10.9 KB
Binary file not shown.

Code.py

+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/usr/bin/env python
2+
# coding:UTF-8
3+
"""Code.py
4+
only for lossy files jpg and png and jpeg
5+
6+
7+
8+
9+
Usage:
10+
Code.py encode -i <input> -o <output> -f <file> -l <level>
11+
Code.py decode -i <input> -o <output> -l <level>
12+
Code.py mes -i <input> -o <output> -f <file>
13+
Code.py dmes -i <input>
14+
15+
Options:
16+
-h, --help Show this help
17+
--version Show the version
18+
-f,--file=<file> File to hide
19+
-i,--in=<input> Input image (carrier)
20+
-o,--out=<output> Output image (or extracted file)
21+
-l,--level = <level>
22+
23+
"""
24+
25+
import cv2
26+
#docopt is like argparse
27+
import docopt
28+
import numpy as np
29+
import hashlib
30+
import os
31+
32+
33+
class SteganographyException(Exception):
34+
pass
35+
36+
37+
class Code():
38+
def __init__(self, im,level):
39+
self.image = im
40+
#get height and width from the shape of image
41+
self.height, self.width, self.nbchannels = im.shape
42+
#size = width * height
43+
self.size = self.width * self.height
44+
45+
46+
if level==1:
47+
self.maskONEValues = [1,2]
48+
self.maskONE = self.maskONEValues.pop(0)
49+
self.maskZEROValues = [254,253]
50+
self.maskZERO = self.maskZEROValues.pop(0)
51+
52+
elif level==2:
53+
self.maskONEValues = [1,2,4,8]
54+
self.maskONE = self.maskONEValues.pop(0)
55+
self.maskZEROValues = [254,253,251,247]
56+
self.maskZERO = self.maskZEROValues.pop(0)
57+
58+
elif level==3:
59+
self.maskONEValues = [1,2,4,8,16,32]
60+
self.maskONE = self.maskONEValues.pop(0)
61+
self.maskZEROValues = [254,253,251,247,239,223]
62+
self.maskZERO = self.maskZEROValues.pop(0)
63+
64+
65+
66+
67+
elif level ==4:
68+
self.maskONEValues = [1,2,4,8,16,32,64,128]
69+
#Mask used to put one ex:1->00000001, 2->00000010 .. associated with OR bitwise
70+
#Bitwise operators are used to change individual bits in an operand. A single byte of computer memory-when viewed as 8 bits-can signify the true/false status of 8 flags
71+
#bchel awal 0 aa chml so btzeh + bchel awal chi b array
72+
self.maskONE = self.maskONEValues.pop(0) #Will be used to do bitwise operations
73+
74+
self.maskZEROValues = [254,253,251,247,239,223,191,127]
75+
#bze7 awal 0 aa yamen lal chml + bchel awal chi b array
76+
#Mak used to put zero ex:254->11111110, 253->11111101 .. associated with AND bitwise
77+
self.maskZERO = self.maskZEROValues.pop(0)
78+
79+
self.curwidth = 0 # Current width position
80+
self.curheight = 0 # Current height position
81+
self.curchan = 0 # Current channel position
82+
self.count = 0
83+
self.counterrr=0
84+
#channels are 3 RGB
85+
#print("first:",self.image[379,379])
86+
#print("EE:",self.curheight)
87+
#print("VV:",self.curwidth)
88+
def put_binary_value(self, bits): #Put the bits of the image
89+
#print("boss:",self.image[self.curheight,self.curwidth])
90+
for c in bits: #Iterate over all bits chml lal yamen
91+
val = list(self.image[self.curheight,self.curwidth]) #Get the pixel value as a list (val is now a 3D array)
92+
#Get the pixel value as a list
93+
#if the bit to be encoded is '0'
94+
95+
96+
97+
if int(c) == 1: #if bit is set, mark it in image
98+
#Else if bit is not set, reset it in image
99+
#print("first")
100+
#print(val[self.curchan])
101+
val[self.curchan] = int(val[self.curchan]) | self.maskONE
102+
#print(val[self.curchan])#OR with maskONE
103+
else:
104+
#print("second")
105+
#print(val[self.curchan])
106+
val[self.curchan] = int(val[self.curchan]) & self.maskZERO
107+
#print(val[self.curchan])
108+
#print("curchan:",int(val[self.curchan]))
109+
#print("mask0:",self.maskZERO)
110+
#print("sum::",val[self.curchan])
111+
#print("after222:",val[self.curchan]) #AND with maskZERO
112+
113+
#Update image
114+
self.image[self.curheight,self.curwidth] = tuple(val)
115+
#print("2:",val[self.curchan])
116+
117+
self.next_slot() #Move "cursor" to the next space
118+
119+
def next_slot(self):#Move to the next slot were information can be taken or put
120+
if self.curchan == self.nbchannels-1: #Next Space is the following channel
121+
self.curchan = 0
122+
if self.curwidth == self.width-1: #Or the first channel of the next pixel of the same line
123+
self.curwidth = 0
124+
if self.curheight == self.height-1:#Or the first channel of the first pixel of the next line
125+
self.curheight = 0
126+
if self.maskONE == int(max(self.maskONEValues)): #final mask, indicating all bits used up
127+
raise SteganographyException("No available slot remaining (image filled)")
128+
else: #Or instead of using the first bit start using the second and so on..
129+
self.maskONE = self.maskONEValues.pop(0)
130+
self.maskZERO = self.maskZEROValues.pop(0)
131+
else:
132+
self.curheight +=1
133+
else:
134+
self.curwidth +=1
135+
else:
136+
self.curchan +=1
137+
138+
#print('maskONE: ',self.maskONE)
139+
#print('maskZERO: ',self.maskZERO)
140+
#print('curwidth: ',self.curwidth)
141+
142+
#print('curheight: ',self.curheight)
143+
#print('curchan: ',self.curchan)
144+
#print('curchan: ',self.curchan)
145+
def read_bit(self): #Read a single bit int the image
146+
val = self.image[self.curheight,self.curwidth][self.curchan]
147+
val = int(val) & self.maskONE
148+
self.next_slot()
149+
#Check if corresp bitmask and val have same set bit
150+
if val > 0:
151+
return "1"
152+
else:
153+
return "0"
154+
155+
def read_byte(self):
156+
return self.read_bits(8)
157+
158+
def read_bits(self, nb): #Read the given number of bits
159+
bits = ""
160+
for i in range(nb):
161+
bits += self.read_bit()
162+
#65300
163+
return bits
164+
165+
def byteValue(self, val):
166+
return self.binary_value(val, 8)
167+
168+
def binary_value(self, val, bitsize): #Return the binary value of an int as a byte
169+
binval = bin(val)[2:]
170+
if len(binval) > bitsize:
171+
raise SteganographyException("binary value larger than the expected size")
172+
while len(binval) < bitsize:
173+
binval = "0"+binval
174+
#print(binval)
175+
return binval
176+
177+
def encode_text(self, txt):
178+
l = len(txt)
179+
#print(l)
180+
binl = self.binary_value(l, 16) #Length coded on 2 bytes so the text size can be up to 65536 bytes long
181+
#print(binl)
182+
self.put_binary_value(binl) #Put text length coded on 4 bytes
183+
for char in txt: #And put all the chars
184+
c = ord(char)
185+
#print(c)
186+
#print(self.byteValue(c))
187+
self.put_binary_value(self.byteValue(c))
188+
return self.image
189+
190+
def decode_text(self):
191+
ls = self.read_bits(16) #Read the text size in bytes
192+
l = int(ls,2)
193+
i = 0
194+
unhideTxt = ""
195+
while i < l: #Read all bytes of the text
196+
tmp = self.read_byte() #So one byte
197+
i += 1
198+
unhideTxt += chr(int(tmp,2)) #Every chars concatenated to str
199+
return unhideTxt
200+
201+
def encode_image(self, imtohide):
202+
w = imtohide.width
203+
h = imtohide.height
204+
if self.width*self.height*self.nbchannels < w*h*imtohide.channels:
205+
raise SteganographyException("Carrier image not big enough to hold all the datas to steganography")
206+
binw = self.binary_value(w, 16) #Width coded on to byte so width up to 65536
207+
binh = self.binary_value(h, 16)
208+
self.put_binary_value(binw) #Put width
209+
self.put_binary_value(binh) #Put height
210+
for h in range(imtohide.height): #Iterate the hole image to put every pixel values
211+
for w in range(imtohide.width):
212+
for chan in range(imtohide.channels):
213+
val = imtohide[h,w][chan]
214+
self.put_binary_value(self.byteValue(int(val)))
215+
return self.image
216+
217+
218+
def decode_image(self):
219+
width = int(self.read_bits(16),2) #Read 16bits and convert it in int
220+
height = int(self.read_bits(16),2)
221+
unhideimg = np.zeros((width,height, 3), np.uint8) #Create an image in which we will put all the pixels read
222+
for h in range(height):
223+
for w in range(width):
224+
for chan in range(unhideimg.channels):
225+
val = list(unhideimg[h,w])
226+
print("val:",val)
227+
val[chan] = int(self.read_byte(),2) #Read the value
228+
print("val[chan]:",val)
229+
unhideimg[h,w] = tuple(val)
230+
print("unhideimg[h,w]:",val)
231+
return unhideimg
232+
233+
def encode_binary(self, data):
234+
#file
235+
l = len(data)
236+
#print(l)
237+
#exmaple l=52598 if image 2.jpg
238+
239+
if self.width*self.height*self.nbchannels < l+64:
240+
raise SteganographyException("Carrier image not big enough to hold all the datas to steganography")
241+
self.put_binary_value(self.binary_value(l, 64)) #put bin(52598,64)
242+
for byte in data:
243+
#bhwel mn number to ascii ex: (b=>98, 1=>48)
244+
byte = byte if isinstance(byte, int) else ord(byte) # Compat py2/py3
245+
self.put_binary_value(self.byteValue(byte))
246+
return self.image
247+
248+
def decode_binary(self):
249+
l = int(self.read_bits(64), 2)
250+
output = b""
251+
for i in range(l):
252+
output += bytearray([int(self.read_byte(),2)])
253+
return output
254+
255+
256+
257+
def main():
258+
args = docopt.docopt(__doc__, version="0.2")
259+
in_f = args["--in"]
260+
out_f = args["--out"]
261+
os.system('optimize-images ' +in_f)
262+
in_img = cv2.imread(in_f)
263+
lossy_formats = ["jpeg", "jpg","png"]
264+
265+
266+
267+
268+
if args['encode']:
269+
#Handling lossy format
270+
out_f, out_ext = out_f.split(".")
271+
if out_ext in lossy_formats:
272+
out_f = out_f + ".png"
273+
print("Output file changed to ", out_f)
274+
275+
data = open(args["--file"], "rb").read()
276+
#\x1c\n\xec\xa5U\xce\t\x98N\x1c\xac\xff\xd9'
277+
level = args['--level']
278+
steg = Code(in_img,int(level))
279+
res = steg.encode_binary(data)
280+
cv2.imwrite(out_f, res)
281+
#os.system('optimize-images ' +out_f)
282+
#os.system('picopt ' +out_f)
283+
284+
elif args["decode"]:
285+
level = args['--level']
286+
steg = Code(in_img,int(level))
287+
raw = steg.decode_binary()
288+
with open(out_f, "wb") as f:
289+
f.write(raw)
290+
291+
elif args["mes"]:
292+
result = hashlib.sha512(args["--file"].encode())
293+
#result.hexdigest()
294+
test = steg.encode_text(args["--file"])
295+
cv2.imwrite(out_f, test)
296+
print("Done!")
297+
298+
elif args["dmes"]:
299+
outtext = steg.decode_text()
300+
print(outtext)
301+
302+
if __name__=="__main__":
303+
main()
304+

0 commit comments

Comments
 (0)