The secret data can be data of any format like text or even a file. In a nutshell, the main motive of steganography is to hide the intended information within any file, usually an image, audio, or video, without actually changing the external appearance of the file, i.e. it should look the same as before.
In this blog, we will be focussing on learning image-based steganography, i.e. hiding secret data in an image.
But before diving a little deeper into it, let’s look at what an image comprises of.
This much information is enough to get started.
Now, let’s look at how we can encode and decode data into our image.
There are a lot of algorithms that can be used to encode data into the image, and in fact, you can also make one yourself. The one being used in this blog is easy to understand and implement, as well.
The algorithm is as follows:
Repeat this process until all the data is encoded into the image.
Suppose the message to be hidden is ‘Hii’
.
The message is of three bytes, therefore, the pixels required to encode the data are 3 x 3 = 9. Consider a 4 x 3 image with a total of 12 pixels, which are sufficient to encode the given data.
[(27, 64, 164), (248, 244, 194), (174, 246, 250), (149, 95, 232),
(188, 156, 169), (71, 167, 127), (132, 173, 97), (113, 69, 206),
(255, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]
The ASCII value of H
is 72, whose binary equivalent is 01001000
.
Read the first three pixels.
(27, 64, 164), (248, 244, 194), (174, 246, 250)
Now, change the pixel value to odd for 1 and even for 0 as in the binary equivalent of data.
For example, the first binary digit is 0
and the first RGB value is 27
, it needs to be converted to odd, which implies 26
.
Similarly, 64
gets converted to 63
because the next binary digit is 1
so the RGB value should be made odd.
So, the modified pixels are:
(26, 63, 164), (248, 243, 194), (174, 246, 250)
Since we have to encode more data, the last value should be even. Similarly, i
can be encoded in this image.
While making the pixel values odd/even by doing +1 or -1, you should take care of binary conditions. I.e., the pixel value should be more than or equal to 0 and less than or equal to 255.
The new image will look like:
[(26, 63, 164), (248, 243, 194), (174, 246, 250), (148, 95, 231),
(188, 155, 168), (70, 167, 126), (132, 173, 97), (112, 69, 206),
(254, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]
For decoding, we shall try to find how to reverse the previous algorithm that we used to encode data.
1
, otherwise it is 0
.Let’s start reading three pixels at a time.
Consider our previously encoded image.
[(26, 63, 164), (248, 243, 194), (174, 246, 250), (148, 95, 231),
(188, 155, 168), (70, 167, 126), (132, 173, 97), (112, 69, 206),
(254, 29, 213), (53, 153, 220), (246, 225, 229), (142, 82, 175)]
We first read the three pixels:
[(26, 63, 164), (248, 243, 194), (174, 246, 250)
Reading the first value: 26
, which is even, therefore the binary bit is 0
. Similarly, for 63
, the binary bit is 1
and for 164
it is 0
. This process continues until the eight RGB value.
We finally get the binary value: 01001000
after concatenating all individual binary values. The final binary data corresponds to decimal value 72, and in ASCII, it represents the character H
.
Since the ninth value is even, we repeat the above steps. We stop when the ninth value encountered is odd.
As a result, we get our original message back which was Hii
.
The Python program for the above algorithm is as follows:
# Python program implementing Image Steganography
# PIL module is used to extract
# pixels of image and modify it
from PIL import Image
# Convert encoding data into 8-bit binary
# form using ASCII value of characters
def genData(data):
# list of binary codes
# of given data
newd = []
for i in data:
newd.append(format(ord(i), '08b'))
return newd
# Pixels are modified according to the
# 8-bit binary data and finally returned
def modPix(pix, data):
datalist = genData(data)
lendata = len(datalist)
imdata = iter(pix)
for i in range(lendata):
# Extracting 3 pixels at a time
pix = [value for value in imdata.__next__()[:3] +
imdata.__next__()[:3] +
imdata.__next__()[:3]]
# Pixel value should be made
# odd for 1 and even for 0
for j in range(0, 8):
if (datalist[i][j]=='0') and (pix[j]% 2 != 0):
if (pix[j]% 2 != 0):
pix[j] -= 1
elif (datalist[i][j] == '1') and (pix[j] % 2 == 0):
pix[j] -= 1
# Eigh^th pixel of every set tells
# whether to stop ot read further.
# 0 means keep reading; 1 means the
# message is over.
if (i == lendata - 1):
if (pix[-1] % 2 == 0):
pix[-1] -= 1
else:
if (pix[-1] % 2 != 0):
pix[-1] -= 1
pix = tuple(pix)
yield pix[0:3]
yield pix[3:6]
yield pix[6:9]
def encode_enc(newimg, data):
w = newimg.size[0]
(x, y) = (0, 0)
for pixel in modPix(newimg.getdata(), data):
# Putting modified pixels in the new image
newimg.putpixel((x, y), pixel)
if (x == w - 1):
x = 0
y += 1
else:
x += 1
# Encode data into image
def encode():
img = input("Enter image name(with extension): ")
image = Image.open(img, 'r')
data = input("Enter data to be encoded : ")
if (len(data) == 0):
raise ValueError('Data is empty')
newimg = image.copy()
encode_enc(newimg, data)
new_img_name = input("Enter the name of new image(with extension): ")
newimg.save(new_img_name, str(new_img_name.split(".")[1].upper()))
# Decode the data in the image
def decode():
img = input("Enter image name(with extension) :")
image = Image.open(img, 'r')
data = ''
imgdata = iter(image.getdata())
while (True):
pixels = [value for value in imgdata.__next__()[:3] +
imgdata.__next__()[:3] +
imgdata.__next__()[:3]]
# string of binary data
binstr = ''
for i in pixels[:8]:
if (i % 2 == 0):
binstr += '0'
else:
binstr += '1'
data += chr(int(binstr, 2))
if (pixels[-1] % 2 != 0):
return data
# Main Function
def main():
a = int(input(":: Welcome to Steganography ::\n"
"1. Encode\n 2. Decode\n"))
if (a == 1):
encode()
elif (a == 2):
print("Decoded word- " + decode())
else:
raise Exception("Enter correct input")
# Driver Code
if __name__ == '__main__' :
# Calling main function
main()
The module used in the program is PILwhich stands for Python Imaging Library. It gives us the capability to perform operations on images in Python.
This program might not work as expected with JPEGimages because JPEG uses lossy compression which means that the pixels are modified to compress the image and reduce the quality, therefore data loss happens.
#python #programming