Steganography

Rahul Kumar Patro
6 min readJan 18, 2021

Learn how to hide Information within Images.

Steganography is a process of hiding a secret message within a larger one in such a way that someone can not know the presence or contents of the hidden message.

The purpose of Steganography is to maintain secret communication between two parties. Unlike cryptography, which conceals the contents of a secret message, steganography conceals the very fact that a message is communicated.

Although steganography differs from cryptography, there are many analogies between the two, and some authors classify steganography as a form of cryptography since hidden communication is a type of secret message.

The secret can be in the form of a text or in the form of an image(i.e Hiding texts inside an Image or hiding an Image inside an Image).

In this blog, we will be focussing on both text-based steganography.

Prerequisites you should know about:-

  1. An image is made up of pixels. The pixels are the building blocks of an image.
  2. For a color image, 3 channels are there per pixel (i.e Red, Green, and Blue).
  3. And every RGB value lies between 0–255. That is in binary an 8-bit number (as 2 to the power of 8 is 256).

Text Steganography

Hiding Text Inside an Image.

As our goal is to hide the texts inside the image, one way we can do this is by converting the texts to binary and then store the converted binary bits using the Least Significant Bit Steganography.

Least Significant Bit Steganography

We can describe a digital image as a finite set of digital values, called pixels. Pixels are the smallest individual element of an image, holding values that represent the brightness of a given color at any specific point. So we can think of an image as a matrix (or a two-dimensional array) of pixels that contains a fixed number of rows and columns.

The Least Significant Bit (LSB) is a technique in which the last bits of each pixel are modified and replaced with the secret message’s data bit.

So from this, we can infer that change in bits is minimal when we change the least significant bits of an 8-bit binary number. Otherwise, if we change MSB it will have a larger impact on the final value and the original image’s content will be somehow lost. So we use the Least Significant Bit Steganography.

So let’s proceed to the code part: —

Step-1:

Function for the conversion of the message you want to encode to Binary.

def message2binary(message):
if type(message) == str:
result= ''.join([ format(ord(i), "08b") for i in message ])

elif type(message) == bytes or type(message) == np.ndarray:
result= [ format(i, "08b") for i in message ]

elif type(message) == int or type(message) == np.uint8:
result=format(message, "08b")

else:
raise TypeError("Input type is not supported")

return result

Here we are using 08b as we require the 8-bit representation of binary digits.

If we use only b then it will not add 0 to convert it into 8 bits and returns the binary converted value..

Step-2:

Import the image inside which you want to hide your message.

Step-3:

Following is the Encoder Function that helps to encode your message inside the image:

def encode_data(img):
data=input("Enter the data to be Encoded:")
if (len(data) == 0):
raise ValueError('Data is empty')

filename = input("Enter the name of the New Image after Encoding(with extension): ")

no_bytes=(img.shape[0] * img.shape[1] * 3) // 8

print("Maximum bytes to encode:", no_bytes)

if(len(data)>no_bytes):
raise ValueError("Error encountered Insufficient bytes, Need Bigger Image or give Less Data !!")

# Using the below as delimeter
data +='*****'

data_binary=message2binary(data)
print(data_binary)
data_len=len(data_binary)

print("The Length of Binary data",data_len)

data_index = 0

for i in img:
for pixel in i:

r, g, b = message2binary(pixel)
# print(r)
# print(g)
# print(b)
# print(pixel)
if data_index < data_len:
# hiding the data into LSB(Least Significant Bit) of Red Pixel
# print("Original Binary",r)
# print("The old pixel",pixel[0])
pixel[0] = int(r[:-1] + data_binary[data_index], 2) #changing to binary after overwrriting the LSB bit of Red Pixel
# print("Changed binary",r[:-1] + data_binary[data_index])

data_index += 1
list1.append(pixel[0])

if data_index < data_len:
# hiding the data into LSB of Green Pixel
pixel[1] = int(g[:-1] + data_binary[data_index], 2) #changing to binary after overwrriting the LSB bit of Green Pixel
data_index += 1
list1.append(pixel[1])

if data_index < data_len:
# hiding the data into LSB of Blue Pixel
pixel[2] = int(b[:-1] + data_binary[data_index], 2) #changing to binary after overwrriting the LSB bit of Blue pixel
data_index += 1
list1.append(pixel[2])

# if data is encoded, just breaking out of the Loop
if data_index >= data_len:
break



cv2.imwrite(filename,img)

print("Encoded the data successfully and the image is successfully saved as ",filename)

First, we are checking whether the total bits that are to be encoded is not exceeding the total number of bits in the image. We will add a delimiter to identify the end of the message and then convert it to binary.

After that, we will iterate through pixels of the image and get r,g,b separate binary values. Once we are done with this we can replace the pixel values like this:

pixel[0] = int(r[:-1] + data_binary[data_index], 2)

We will do that for the total length of encoded binary bits.

After passing all the information through this function you will get an output like this:

Step-4:

As we have encoded the data to the image, now its time for the retrieval of the message from the image, So the following is the Decoder Function:-

def decode_data(img):

binary_data = ""
for i in img:
for pixel in i:

# print(pixel)
r, g, b = message2binary(pixel)
binary_data += r[-1] #Extracting Encoded data from the LSB bit of Red Pixel as we have stored in LSB bit of every pixel.
binary_data += g[-1] #Extracting Encoded data from the LSB bit of Green Pixel
binary_data += b[-1] #Extracting Encoded data from LSB bit of Blue Pixel

# splitting by 8-bits
all_bytes = [ binary_data[i: i+8] for i in range(0, len(binary_data), 8) ]

# Converting the bits to Characters
decoded_data = ""
for byte in all_bytes:
decoded_data += chr(int(byte, 2))
if decoded_data[-5:] == "*****": #Checking if we have reached the delimeter which is "*****"
break


print("The Encoded data was :--",decoded_data[:-5])

Now the reverse process will go on. As we had replaced the binary bits of the encoded message with the last bits of the 8-bit binary number we will decode the encoded message by looping over the pixel bits by adding the last bit i.e the Least Significant Bit.

binary_data += r[-1]  #Extracting Encoded data from the LSB bit of Red Pixel as we have stored in LSB bit of every pixel.

We will continue to do that till we find the delimiter we will continue to go through the loop and convert the binary string to the character string.

After decoding the data you will get an output like this:

So on the left side, we can see the images before and after encoding the data.

Can you identify any difference between the two images???

Yahoo, we are done with Text Steganography.

Hope you liked it.

If you are interested in the code, you can find my notebook on Github.

To visit the next part of this series i.e Image Steganography please visit this link.

Hope you enjoyed the article!!

--

--