How to Hide Data in Images Using Steganography

How to Hide Data in Images Using Steganography

Have you ever wanted to send information in images like they do it in movies? Well, now you can with this cool script.

Arpan Pandey
·Dec 7, 2021·

4 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

  • What is Steganography?
  • What is LSB (Least Significant Bit)?
  • Python Implementation
  • Wrap-Up

What is Steganography?

If one needs to define steganography, it can be simply said as a practice of hiding secret messages within or over something that is no secret. It is just a process of embedding a secret piece of text within a text, picture, or audio. The message could be a message or script within a document file or a picture file. A form of covert communication, the main purpose of steganography is concealing and deceiving. The message can be concealed through any medium. It differs from cryptography which is a science that enables privacy.

What is LSB (Least Significant Bit)?

LSB stands for Least Significant Bit. The idea behind LSB embedding is that if we change the last bit value of a pixel, there won’t be much visible change in the color. For example, 0 is black. Changing the value to 1 won’t make much of a difference since it is still black, just a lighter shade.

Python Implementation

Let's start by installing the required modules. The modules we will need are OpenCV, Numpy.

pip3 install opencv-python numpy

Now, we will import the modules.

import numpy as np
import cv2

Next, we will create a function that will take data and convert it to binary form.

def binary_convert(data):

    """This function converts our data into binary data."""

    if isinstance(data, str):
        return ''.join([format(ord(i), "08b") for i in data])

    elif isinstance(data, bytes) or isinstance(data, np.ndarray):
        return [format(i, "08b") for i in data]

    elif isinstance(data, int) or isinstance(data, np.uint8):
        return format(data, "08b")

    else:
        raise TypeError("This type is unsupported.")

The following code creates an encode() function. This function takes 2 arguments, one is the name/path of the image and the other is the data to encode. The encode function will then:

  • Read the image using cv2.imread() function.
  • It will then proceed to count the maximum bytes available to encode the data into.
  • Check if we can encode all of the data in the given image.
  • Adds a Stopping Criteria for the decoder to stop.
  • Finally, modify the data of the image by just one bit and replace it by the data bit.
def encode(image_name, secret_data):
    # Reads the image
    image_rows = cv2.imread(image_name)
    # Gives us the maximum no. of bytes to encode.
    n_bytes = image_rows.shape[0] * image_rows.shape[1] * 3 // 8
    print("Maximum bytes to encode are:", n_bytes)
    if len(secret_data) > n_bytes:
        raise ValueError(
            "Insufficient bytes,we will need a bigger image or less data.")
    print("Encoding Data to Image...")
    # This adds a stopping criteria, which is used to guess the
    secret_data += "====="
    data_index = 0
    # Converts the data to binary.
    binary_secret_data = binary_convert(secret_data)
    # Gets the size of the data to hide.
    data_len = len(binary_secret_data)

    for row in image_rows:
        for pixel in row:

            r, g, b = binary_convert(pixel)

            if data_index < data_len:

                pixel[0] = int(r[:-1] + binary_secret_data[data_index], 2)
                data_index += 1
            if data_index < data_len:

                pixel[1] = int(g[:-1] + binary_secret_data[data_index], 2)
                data_index += 1
            if data_index < data_len:

                pixel[2] = int(b[:-1] + binary_secret_data[data_index], 2)
                data_index += 1

            if data_index >= data_len:
                break
    return image_rows

The following code creates the decode() function. This function takes only 1 argument, which is the name of the image to decode. The decode function simply reads the image, gets the last bits of every pixel of the image and then keep decoding until it detects the stopping criteria.

def decode(image_name):
    print("Decoding data from Image...")
    # Reading the Image
    image_rows = cv2.imread(image_name)
    binary_data = ""
    for row in image_rows:
        for pixel in row:
            r, g, b = binary_convert(pixel)
            binary_data += r[-1]
            binary_data += g[-1]
            binary_data += b[-1]

    # Splitting the image by 8-bits
    all_bytes = [binary_data[i: i+8] for i in range(0, len(binary_data), 8)]
    # Now, we convert the bits to characters
    decoded_data = ""
    for byte in all_bytes:
        decoded_data += chr(int(byte, 2))
        if decoded_data[-5:] == "=====":
            break
    return decoded_data[:-5]

This snippet will assign the name of the input image in the input_img variable and the name of the file to be outputted in the out_img variable.

# We will assign variables as the name of the input and the output file.
input_img = "img.png" # Enter the name of your image here.
out_img = "img_out.png" # Also, update this accordingly.

This code calls the encode() function and saves the output to a variable. Then, it will use the cv2.imwrite() to save the data as an image file.

# Now we can just call the encode() function to encode the image and save the data to a variable.
enc_image = encode(input_img, "Hi Folks!") # Replace "Hi Folks!" with the data you want to encode.
cv2.imwrite(out_img, enc_image) #Using OpenCV to write the result to an actual image file.

The final step is to decode the image using the decode() function and read the data from the image.

# We can decode the image by simply calling the decode() function.
decode(out_img)

Wrap-Up

Congratulations! You are now ready to communicate secretly with this age old trick. If you want to see the full code then head over at my gist.

Did you find this article valuable?

Support Arpan Pandey by becoming a sponsor. Any amount is appreciated!

See recent sponsors Learn more about Hashnode Sponsors
 
Share this