I recently rewatched Computerphile's video covering steganography, which motivated me to try it out for myself. A Google search later and I found an easy way to create steganographic images with the Python and the stegano library. If you want to follow along, go ahead and install it yourself with pip.
Pip install stegano
First, let’s create a steganographic image. In my case, I’m going to be using a really cute picture of my cat Walter. Check him out!
Here is the code we will use to encode our message.
from stegano import lsb
secret = lsb.hide("./walter.png", "Walter being really cute!")
secret.save("./walter-secret.png")
After running the code, you should be left with a new, steganographic image containing your message. It should be saved in same directory where the python file you just ran is located.
If you want to read the secret message in your image, you can do so like this.
from stegano import lsb
message = lsb.reveal('./walter-secret.png')
print(message)
Now let’s see if we can spread our image online. I will be using Reddit to do that. The first thing I want to do is check if there are other steganographic images floating around Reddit at the time of my test. While I won’t be testing for all of the different ways we can encode a message into an image, we will check if any images are using the least significant bit method. Here is the script I wrote to do that.
from PIL import Image
import urllib.request
import json
import re
from stegano import lsb
from stegano import tools
import requests
from io import BytesIO
from typing import IO, Union
import time
url = "https://api.pushshift.io/reddit/search/submission/?subreddit=aww&sort=desc&sort_type=created_utc&size=1000"
response = urllib.request.urlopen(url)
data = json.loads(response.read())
for i in data['data']:
if re.search('png', i['url']):
response = requests.get(i['url'], timeout=10)
try:
print('Trying to decode', i['url'], 'at size', Image.open(BytesIO(response.content)).size)
img = lsb.reveal(BytesIO(response.content))
if img != None:
print('WE GOT ONE!!!', img)
except:
pass
I should also note that if there are any steganographic images floating around, they are most likely encrypted as well. This means we wouldn’t get much, even if we did manage to find an image containing a secret message. It’s still a fun test though.
I wasn’t able to find any secret messages, so I will just have make one myself! I uploaded the steganographic image of my cat to the /r/aww subreddit, then ran my script again. Here are the results!
That’s right, we managed to find the image and read the message! While this implementation isn’t incredibly useful, I think it’s still a pretty cool project. If you would like to go further, you can even hide complete images inside of other images! Here is a cool article on doing that with machine learning.