patternpythonMinor
Steganographic message hiding
Viewed 0 times
messagehidingsteganographic
Problem
This code hides a message in an image by altering the blue values in the top left part. This is just for fun as I think it would be easy for a cryptographer to find and decrypt this.
Original
With message
As you can (cannot) see, as long as the message is short enough, the naked eye has difficulty noticing the difference. Zooming in the top left corner will reveal the trick though.
```
from PIL import Image
from itertools import zip_longest
import doctest
def read_and_write_after_tranformation(infile, outfile, transformation):
# Based on a StackOverflow answer.
im = Image.open(infile)
list_of_pixels = list(im.getdata())
im2 = Image.new(im.mode, im.size)
im2.putdata(transformation(list_of_pixels))
im2.save(outfile)
def read_rgb(infile):
return list(Image.open(infile).getdata())
def steganographic_encrypt(message, rgb_tuples):
"""
Encodes a message in the blue values of the pixels on the top left corner of the image.
>>> steganographic_encrypt("Hello, World!", [(a, b, c, luminosity) for a, b, c, luminosity in zip(range(12, 30), range(20, 48), range(100, 128), range(100, 128))])
[(12, 20, 72, 100), (13, 21, 101, 101), (14, 22, 108, 102), (15, 23, 108, 103), (16, 24, 111, 104), (17, 25, 44, 105), (18, 26, 32, 106), (19, 27, 87, 107), (20, 28, 111, 108), (21, 29, 114, 109), (22, 30, 108, 110), (23, 31, 100, 111), (24, 32, 33, 112), (25, 33, 113, 113), (26, 34, 114, 114), (27, 35, 115, 115), (28, 36, 116, 116), (29, 37, 117, 117)]
"""
return [(red, green, blue if ascii_val is None else ascii_val, luminosity)
for (red, green, blue, luminosity), ascii_val in zip_longest(rgb_tuples, map(ord, message))]
def steganographic_decrypt(rgb_tuples):
"""
Decodes a message from the blue values of the pixels on the top left corner of the image.
>>> steganographic_decrypt([(12, 20, 72, 100), (13, 21, 101, 101), (14, 22, 108, 102), (15, 23, 108, 103), (16, 24, 1
Original
With message
We will meet at London bridge at dawnAs you can (cannot) see, as long as the message is short enough, the naked eye has difficulty noticing the difference. Zooming in the top left corner will reveal the trick though.
```
from PIL import Image
from itertools import zip_longest
import doctest
def read_and_write_after_tranformation(infile, outfile, transformation):
# Based on a StackOverflow answer.
im = Image.open(infile)
list_of_pixels = list(im.getdata())
im2 = Image.new(im.mode, im.size)
im2.putdata(transformation(list_of_pixels))
im2.save(outfile)
def read_rgb(infile):
return list(Image.open(infile).getdata())
def steganographic_encrypt(message, rgb_tuples):
"""
Encodes a message in the blue values of the pixels on the top left corner of the image.
>>> steganographic_encrypt("Hello, World!", [(a, b, c, luminosity) for a, b, c, luminosity in zip(range(12, 30), range(20, 48), range(100, 128), range(100, 128))])
[(12, 20, 72, 100), (13, 21, 101, 101), (14, 22, 108, 102), (15, 23, 108, 103), (16, 24, 111, 104), (17, 25, 44, 105), (18, 26, 32, 106), (19, 27, 87, 107), (20, 28, 111, 108), (21, 29, 114, 109), (22, 30, 108, 110), (23, 31, 100, 111), (24, 32, 33, 112), (25, 33, 113, 113), (26, 34, 114, 114), (27, 35, 115, 115), (28, 36, 116, 116), (29, 37, 117, 117)]
"""
return [(red, green, blue if ascii_val is None else ascii_val, luminosity)
for (red, green, blue, luminosity), ascii_val in zip_longest(rgb_tuples, map(ord, message))]
def steganographic_decrypt(rgb_tuples):
"""
Decodes a message from the blue values of the pixels on the top left corner of the image.
>>> steganographic_decrypt([(12, 20, 72, 100), (13, 21, 101, 101), (14, 22, 108, 102), (15, 23, 108, 103), (16, 24, 1
Solution
Working with resources
In
Don't believe everything you read on Stack Overflow =)
You can wrap those in a
Usability
This is a nice script.
It would be great to make it more usable,
with command line parameters:
You probably already know this, but
In
read_and_write_after_tranformation you didn't bother to close any of the image resources:# Based on a StackOverflow answer.
im = Image.open(infile)
list_of_pixels = list(im.getdata())
im2 = Image.new(im.mode, im.size)
im2.putdata(transformation(list_of_pixels))
im2.save(outfile)Don't believe everything you read on Stack Overflow =)
You can wrap those in a
with ... as. And while at it,im and im2 are not great names.with Image.open(infile) as in_img:
list_of_pixels = list(in_img.getdata())
with Image.new(in_img.mode, in_img.size) as out_img:
out_img.putdata(transformation(list_of_pixels))
out_img.save(outfile)Usability
This is a nice script.
It would be great to make it more usable,
with command line parameters:
- hide sub-command: message to hide, input file, output file
- show sub-command: file
You probably already know this, but
argparse would be a good tool for this job.Code Snippets
# Based on a StackOverflow answer.
im = Image.open(infile)
list_of_pixels = list(im.getdata())
im2 = Image.new(im.mode, im.size)
im2.putdata(transformation(list_of_pixels))
im2.save(outfile)with Image.open(infile) as in_img:
list_of_pixels = list(in_img.getdata())
with Image.new(in_img.mode, in_img.size) as out_img:
out_img.putdata(transformation(list_of_pixels))
out_img.save(outfile)Context
StackExchange Code Review Q#103856, answer score: 4
Revisions (0)
No revisions yet.