Team Ai
Apppublic

mithril-security/NonSuspiciousImageDecoder

sourceHugging Faceupdated 4y agoView on Hugging Face
1likes
LSBSteg.py199 linesDownload Raw Back to root
1#!/usr/bin/env python2# coding:UTF-83"""LSBSteg.py4 5Usage:6  LSBSteg.py encode -i <input> -o <output> -f <file>7  LSBSteg.py decode -i <input> -o <output>8 9Options:10  -h, --help                Show this help11  --version                 Show the version12  -f,--file=<file>          File to hide13  -i,--in=<input>           Input image (carrier)14  -o,--out=<output>         Output image (or extracted file)15"""16 17import cv218import docopt19import numpy as np20 21channel_order = (2, 1, 0, 3)22 23class SteganographyException(Exception):24    pass25 26 27class LSBSteg():28    def __init__(self, im):29        self.image = im30        self.height, self.width, self.nbchannels = im.shape31        self.size = self.width * self.height32        33        self.maskONEValues = [1,2,4,8,16,32,64,128]34        #Mask used to put one ex:1->00000001, 2->00000010 .. associated with OR bitwise35        self.maskONE = self.maskONEValues.pop(0) #Will be used to do bitwise operations36        37        self.maskZEROValues = [254,253,251,247,239,223,191,127]38        #Mak used to put zero ex:254->11111110, 253->11111101 .. associated with AND bitwise39        self.maskZERO = self.maskZEROValues.pop(0)40        41        self.curwidth = 0  # Current width position42        self.curheight = 0 # Current height position43        self.curchan = 0   # Current channel position44 45    def put_binary_value(self, bits): #Put the bits in the image46        for c in bits:47            val = list(self.image[self.curheight,self.curwidth]) #Get the pixel value as a list48            if int(c) == 1:49                val[self.curchan] = int(val[self.curchan]) | self.maskONE #OR with maskONE50            else:51                val[self.curchan] = int(val[self.curchan]) & self.maskZERO #AND with maskZERO52                53            self.image[self.curheight,self.curwidth] = tuple(val)54            self.next_slot() #Move "cursor" to the next space55        56    def next_slot(self):#Move to the next slot were information can be taken or put57        if self.curchan == self.nbchannels-1: #Next Space is the following channel58            self.curchan = 059            if self.curwidth == self.width-1: #Or the first channel of the next pixel of the same line60                self.curwidth = 061                if self.curheight == self.height-1:#Or the first channel of the first pixel of the next line62                    self.curheight = 063                    if self.maskONE == 128: #Mask 1000000, so the last mask64                        raise SteganographyException("No available slot remaining (image filled)")65                    else: #Or instead of using the first bit start using the second and so on..66                        self.maskONE = self.maskONEValues.pop(0)67                        self.maskZERO = self.maskZEROValues.pop(0)68                else:69                    self.curheight +=170            else:71                self.curwidth +=172        else:73            self.curchan +=174 75    def read_bit(self): #Read a single bit int the image76        val = self.image[self.curheight,self.curwidth,channel_order[self.curchan]]77        val = int(val) & self.maskONE78        self.next_slot()79        if val > 0:80            return "1"81        else:82            return "0"83    84    def read_byte(self):85        return self.read_bits(8)86    87    def read_bits(self, nb): #Read the given number of bits88        bits = ""89        for i in range(nb):90            bits += self.read_bit()91        return bits92 93    def byteValue(self, val):94        return self.binary_value(val, 8)95        96    def binary_value(self, val, bitsize): #Return the binary value of an int as a byte97        binval = bin(val)[2:]98        if len(binval) > bitsize:99            raise SteganographyException("binary value larger than the expected size")100        while len(binval) < bitsize:101            binval = "0"+binval102        return binval103 104    def encode_text(self, txt):105        l = len(txt)106        binl = self.binary_value(l, 16) #Length coded on 2 bytes so the text size can be up to 65536 bytes long107        self.put_binary_value(binl) #Put text length coded on 4 bytes108        for char in txt: #And put all the chars109            c = ord(char)110            self.put_binary_value(self.byteValue(c))111        return self.image112       113    def decode_text(self):114        ls = self.read_bits(16) #Read the text size in bytes115        l = int(ls,2)116        i = 0117        unhideTxt = ""118        while i < l: #Read all bytes of the text119            tmp = self.read_byte() #So one byte120            i += 1121            unhideTxt += chr(int(tmp,2)) #Every chars concatenated to str122        return unhideTxt123 124    def encode_image(self, imtohide):125        w = imtohide.width126        h = imtohide.height127        if self.width*self.height*self.nbchannels < w*h*imtohide.channels:128            raise SteganographyException("Carrier image not big enough to hold all the datas to steganography")129        binw = self.binary_value(w, 16) #Width coded on to byte so width up to 65536130        binh = self.binary_value(h, 16)131        self.put_binary_value(binw) #Put width132        self.put_binary_value(binh) #Put height133        for h in range(imtohide.height): #Iterate the hole image to put every pixel values134            for w in range(imtohide.width):135                for chan in range(imtohide.channels):136                    val = imtohide[h,w][chan]137                    self.put_binary_value(self.byteValue(int(val)))138        return self.image139 140                    141    def decode_image(self):142        width = int(self.read_bits(16),2) #Read 16bits and convert it in int143        height = int(self.read_bits(16),2)144        unhideimg = np.zeros((width,height, 3), np.uint8) #Create an image in which we will put all the pixels read145        for h in range(height):146            for w in range(width):147                for chan in range(unhideimg.channels):148                    val = list(unhideimg[h,w])149                    val[chan] = int(self.read_byte(),2) #Read the value150                    unhideimg[h,w] = tuple(val)151        return unhideimg152    153    def encode_binary(self, data):154        l = len(data)155        if self.width*self.height*self.nbchannels < l+64:156            raise SteganographyException("Carrier image not big enough to hold all the datas to steganography")157        self.put_binary_value(self.binary_value(l, 64))158        for byte in data:159            byte = byte if isinstance(byte, int) else ord(byte) # Compat py2/py3160            self.put_binary_value(self.byteValue(byte))161        return self.image162 163    def decode_binary(self):164        l = int(self.read_bits(64), 2)165        output = b""166        for i in range(l):167            output += bytearray([int(self.read_byte(),2)])168        return output169 170 171def main():172    args = docopt.docopt(__doc__, version="0.2")173    in_f = args["--in"]174    out_f = args["--out"]175    in_img = cv2.imread(in_f, cv2.IMREAD_UNCHANGED)176    steg = LSBSteg(in_img)177    lossy_formats = ["jpeg", "jpg"]178 179    if args['encode']:180        #Handling lossy format181        out_f, out_ext = out_f.split(".")182        if out_ext in lossy_formats:183            out_f = out_f + ".png"184            print("Output file changed to ", out_f)185 186        data = open(args["--file"], "rb").read()187        res = steg.encode_binary(data)188        cv2.imwrite(out_f, res)189 190    elif args["decode"]:191        raw = steg.decode_binary()192        with open(out_f, "wb") as f:193            f.write(raw)194 195 196if __name__=="__main__":197    main()198 199