If you have ever explored cybersecurity, you probably know about Steganography—the art of hiding secret messages inside an image.
The most popular approach is usually the LSB (Least Significant Bit) method, where we slightly alter the pixel colors to embed text. The problem? Modern detection tools (steganalysis) are incredibly smart. Altering even a single bit can trigger an alert that the image has been manipulated.
So, what if we could hide data without changing a single pixel of the original image?
Welcome to the world of Coverless Steganography.
Academic Attribution 📚
The article and code below are the result of my independent breakdown and implementation based on an excellent academic paper titled:
"A Novel Coverless Information Hiding Method Based on the Most Significant Bit of the Cover Image" by Lina Yang, Haiyu Deng, and Xiaocui Dang (IEEE Access, 2020).
DOI: 10.1109/ACCESS.2020.3000993
Let us break down how it works and write the code in Python!
🧠 Core Concept of CIHMSB
CIHMSB stands for Coverless Information Hiding Method based on Most Significant Bit. It relies on logic matching rather than physical embedding. Here is the simple workflow based on the original paper:
-
Convert Message to Binary: Change your secret message into a sequence of
0s and1s using a 7-bit ASCII format. - Divide the Image: Cut the original grayscale image matrix into small grids or fragments, for example, 8x8 or 5x5 pixels.
- Calculate Average and Extract MSB: Instead of looking at a single random pixel, calculate the average pixel value of the entire fragment. Then, extract the Most Significant Bits from that average value.
-
The Magic Matching: Compare your message bits with the extracted image MSBs. If they match, we record a
1in a separate ledger. If they do not match, we record a0. This ledger is called the Mapping Flag. - Transmission: You send the 100% unaltered original image and the Mapping Flag file to your receiver.
Because the original image is completely untouched, error detection metrics return an Infinite value. Zero pixels are damaged!
💻 Let's Write the Code
We will use the numpy library to manipulate the image matrices. Notice how the class allows us to extract multiple MSB bits per fragment to increase the hiding capacity.
import numpy as np
class CIHMSB:
def __init__(self, fragment_size=8, msb_bits=1):
self.fragment_size = fragment_size
self.msb_bits = msb_bits
def _text_to_bin(self, text):
binary_list = []
for char in text:
bin_char = format(ord(char), '07b')
for bit in bin_char:
binary_list.append(int(bit))
return binary_list
def _bin_to_text(self, binary_list):
text = ""
for i in range(0, len(binary_list), 7):
chunk = binary_list[i:i+7]
if len(chunk) < 7: break
chunk_str = "".join(map(str, chunk))
text += chr(int(chunk_str, 2))
return text
def _extract_image_msb(self, image_array):
h, w = image_array.shape
h_trunc = h - (h % self.fragment_size)
w_trunc = w - (w % self.fragment_size)
msb_pool = []
for i in range(0, h_trunc, self.fragment_size):
for j in range(0, w_trunc, self.fragment_size):
fragment = image_array[i:i+self.fragment_size, j:j+self.fragment_size]
avg_val = int(np.mean(fragment))
bin_avg = format(avg_val, '08b')
for b in range(self.msb_bits):
msb_pool.append(int(bin_avg[b]))
return msb_pool
def embed(self, image_array, secret_text):
secret_bits = self._text_to_bin(secret_text)
msb_pool = self._extract_image_msb(image_array)
if len(secret_bits) > len(msb_pool):
raise ValueError("Kapasitas tidak cukup.")
return [1 if secret_bits[i] == msb_pool[i] else 0 for i in range(len(secret_bits))]
def extract(self, image_array, mapping_flag):
msb_pool = self._extract_image_msb(image_array)
secret_bits = [1 if mapping_flag[i] == msb_pool[i] else 0 for i in range(len(mapping_flag))]
return self._bin_to_text(secret_bits)
How to Run It
Now, let us test the code above. You will need a grayscale image loaded into a numpy array (named img_array in this example). We will configure it to use 4 bits per fragment to simulate a high-capacity scenario.
img_pil = Image.open('assets/cover.png').convert('L')
img_array = np.array(img_pil)
cihmsb = CIHMSB(fragment_size=8, msb_bits=4)
secret_message = "SECRET MESSAGE"
print(f"Original Message: {secret_message}")
mapping_flag = cihmsb.embed(img_array, secret_message)
print(f"Transmitted Mapping Flag: {mapping_flag[:10]}... (Total {len(mapping_flag)} bits)")
extracted_message = cihmsb.extract(img_array, mapping_flag)
print(f"Extracted Message: {extracted_message}")
🧪 Replicating the Paper's Experiments
To prove that this method works exactly as the IEEE paper claims, I built a complete test suite to replicate their Image Quality Assessment (IQA), Security Analysis, and Robustness parameters.
Here is the terminal output from running the master test script on a 256x256 image with 5x5 fragments:
[1] EXPERIMENT DEMO
Secret message length : 160 characters
Binary bit length : 1120 bits
Extraction Match : True
[2] HIDING CAPACITY ANALYSIS
Image Size : 256x256
Fragment Size : 5x5
Max Hiding Capacity : 2601 bits per carrier
[3] SECURITY ANALYSIS (Violent Attack)
Total Image Fragments (Fm) : 2601
Secret Bits (Cn) : 1120
Possible Attack Combos (U) : 10^3701 combinations
[4] IMAGE QUALITY ASSESSMENT (IQA)
Mean Square Error (MSE) : 0.0
PSNR (dB) : inf
SSIM : 1.0
Universal Quality (Qi) : 1.0
[5] ROBUSTNESS ANALYSIS: AWGN & JPEG
--- AWGN (Gaussian Noise) ---
Variance 0.1 -> BER: 9.73%
Variance 0.5 -> BER: 33.04%
Variance 1.0 -> BER: 45.36%
--- JPEG Compression ---
Quality 90 -> BER: 1.16%
Quality 70 -> BER: 1.96%
Quality 50 -> BER: 3.12%
Key Takeaways from the Benchmark:
-
Perfect Image Quality: Notice the PSNR is
inf(Infinite) and SSIM is1.0. Because we don't manipulate pixels, the stego image is mathematically identical to the cover image. -
Unbreakable Brute-Force: Without the Mapping Flag, an attacker trying a violent brute-force attack would face
10^3701combinations to extract just 1120 bits. -
Robustness: Even if the image is compressed and loses quality (JPEG Quality 50), the Bit Error Rate (BER) remains remarkably low at just
3.12%, meaning most of the secret text is still perfectly readable!
🎯 Conclusion
The main advantage of this Coverless method is: Your original image does not change at all. If a hacker or analyst intercepts the image and checks its MD5 hash or color histogram, they will find absolutely nothing suspicious. It is just a normal image.
The secret data will only materialize if that specific original image is paired with the Mapping Flag file we send separately. By averaging the fragment values instead of picking a single pixel, this specific algorithm also ensures better robustness against minor image distortions like JPEG compression.
I have uploaded the full source code and the complete test replication suite to my GitHub repository. Feel free to check it out, run the tests yourself, and give it a star! ⭐
👉 https://github.com/Anjasfedo/cihmsb
What do you think? Will this zero-pixel manipulation method become the data security standard of the future? Let me know in the comments below!
#Python #CyberSecurity #Steganography #MachineLearning #ResearchToCode
Top comments (0)