Steganography 101

Alright, the description of what they were doing was pretty basic, so I wondered if I should do the exercise - itching to get to Course 2 you see 😊 And, it paid off big time. I would have been happy to do just the hidden image recovery - but, ended up whacking out the encoder and decoder in a decent time.

Okay, what is it in a nutshell? Each R,G,B pixel has eight bits. Retain the four MSBs (Most Significant Bits) and use the four LSBs (Least SBs) to store the MSBs of your message. Neat, eh?

Of course, you can only store an image of same or smaller size, so the first thing you do is a crop..

So, starting with :

hilton.jpg 140x210

As the "cloak" image, you want to hide this one, the "data" :

usain.jpg(300x300)
Cropping : 

function crop( img_cloak, img_data ){
var cropped_data = new SimpleImage(width=Math.min(img_cloak.getWidth(),img_data.getWidth() ),
height=Math.min(img_cloak.getHeight(), img_data.getHeight() ) );
var p;
for( p of cropped_data.values() ){
cropped_data.setPixel( p.getX(), p.getY(), img_data.getPixel(p.getX(),p.getY()) );
}
return cropped_data;
}

gives you :


Then, what does the composite look like?

function encode( img_cloak, img_data){ // both SimpleImage objects

// each pixel (if used) in img_cloak will have lower nibble substituted

// with higher nibble of img_data

var out_img = new SimpleImage(width=img_cloak.getWidth(), height=img_cloak.getHeight());

var cropped_data = crop( img_cloak, img_data);

print(cropped_data);

var wd = cropped_data.getWidth();

var hd = cropped_data.getHeight();

var p,x,y,po,pc;

for ( p of img_cloak.values() ){

x = p.getX();

y = p.getY();

if( x >= wd || y >= hd ){

// then keep original unchanged

out_img.setPixel(x,y,img_cloak.getPixel(x,y));

} else {

po = out_img.getPixel(x,y);

pc = cropped_data.getPixel(x,y);

po.setRed( (p.getRed() & 240) | (pc.getRed() >> 4 ) );

po.setGreen( (p.getGreen() & 240) | (pc.getGreen() >> 4 ) );

po.setBlue( (p.getBlue() & 240) | (pc.getBlue() >> 4) );

}

}

return out_img;

}



It looks tampered with, doesn't it? The one on the right is with an empty (all 0's) image. Left is with Usain.

And when you recover the original message?

function decode( message ){ // SimpleImage object

// returns a SimpleImage with each pixel left-shifted by 4

var out_img = new SimpleImage( width=message.getWidth(), height=message.getHeight() );

var p,po;

for( p of message.values() ){

po = out_img.getPixel(p.getX(),p.getY());

po.setRed( (p.getRed() & 15 ) << 4 );

po.setGreen( (p.getGreen() & 15) << 4 );

po.setBlue( (p.getBlue() & 15) << 4 );

}

return out_img;

}


Impressive huh?

cloak = new SimpleImage( 'hilton.jpg');

print(cloak);

data = new SimpleImage( 'usain.jpg');

print(data.getWidth());

var message = encode(cloak, data);

print( message );

var recovery = decode( message );

print(recovery);

 

Comments

Popular posts from this blog

How Should You Put Your Text in a Box?

Tricks : Getting Image URL When Page Doesn't Want You To!

A Web Interface to Try Dual Key Caesar Cipher Encryption and Decryption