Simple steganography with GD
Ian Malpass
Frozen Perl
February 2008
Steganography
- Hiding data within data.
- Often done with images.
- Can make small changes to colour intensities without a noticeable change in the image.
steg.pl
use GD;
use strict;
use warnings;
my $source = GD::Image->new( 'evie.png' );
my $mask = GD::Image->new( 'mask.png' ); message to hide
my $steg = GD::Image->new( $source->width, $source->height );
for my $x ( 0 .. $source->width - 1 ) {
for my $y ( 0 .. $source->height - 1 ) {
my $m_idx = $mask->getPixel( $x, $y ); # get the colour index of the corresponding pixel in the mask
my ( $int ) = $source->rgb( $source->getPixel( $x, $y ) ); # get the intensity of the pixel in the source image
# if the mask is white, set the least significant bit of the intensity
# high, otherwise set it low
$int = ( $m_idx == 0 ) ? $int & 254 : $int | 1;
my $idx = $steg->colorResolve( $int, $int, $int ); # get the new colour's index in the destination image
$steg->setPixel( $x, $y, $idx ); # and set the pixel in the destination image
}
}
open OUT, ">steg.png" || die $!;
binmode OUT;
print OUT $steg->png; # and output the file
close OUT;
Hiding the message with steg.pl
 |
+ |
 |
= |
 |
Original photo |
|
Message to hide |
|
Photos with message hidden |
desteg.pl
use GD;
use strict;
use warnings;
my $source = GD::Image->new( 'steg.png' );
my $desteg = GD::Image->new( $source->width, $source->height );
for my $x ( 0 .. $source->width - 1 ) {
for my $y ( 0 .. $source->height - 1 ) {
my $idx = $source->getPixel( $x, $y ); # get the pixel from the source image
my ( $int ) = $source->rgb( $idx ); # get its intensity
$int = 255 * ( $int & 1 ); # check its least significant bit - high is with, low is black
my $d_idx = $desteg->colorResolve( $int, $int, $int ); # get the colour index
$desteg->setPixel( $x, $y, $d_idx ); set the pixel
}
}
open OUT, ">desteg.png" || die $!;
binmode OUT;
print OUT $desteg->png; # output the file
close OUT;
Extracting the message with desteg.pl
 |
-> |
 |
Photos with message hidden |
|
Message revealed |
Notes
- I used a greyscale image, because it simplifies the number of colours in the image.
- I used a black and white message, because it simplifies the hiding process (and makes the least impact on the image).
- A full colour image will usually need to have its colours reduced before you can hide an image in it, due to palette limitations.
- I used PNG since it is a lossless format - JPEG compression will introduce errors.
- Resizing and other operations will damage or eliminate the message.
- Cropping will just crop the message.
- There are better bits of software for doing steganography!
- There are better algorithms for doing steganography!