A Detailed Solution to Secret Announcement
You are most likely busy creating a game for the game jam and you probably know that an announcement came 2 weeks before the jam as a secret message using steganography I was one of those chaps who actually solved the secret, but didn't do anything.
The challenge can be found here. There was a solution, but that was not very explanatory.This post will explain how ~I~ solved the announcement. This post assumes basic knowledge of the binary system.
The first thing I did after seeing the newsletter was to read up on steganography.I found this on wikipedia:
Concealing messages within the lowest bits of noisy images or sound files
Then, I looked at the code.Apart from imports and loops to go through all pixels,this was the crux of the code:
secret_red = secret_pix >> shift_amt secret_green = secret_pix >> shift_amt secret_blue = secret_pix >> shift_amt public_red = public_pix & all_except_LSB_mask public_green = public_pix & all_except_LSB_mask public_blue = public_pix & all_except_LSB_mask final = ( secret_red + public_red, secret_green + public_green, secret_blue + public_blue )
& are binary operators.shift_amt was 7 and all_except_LSB_mask was 254
What does the >> operator do? It shifts the bits towards towards right.For example:
11100010101 >> 6 outputs
11100 i.e. the last 6 bits are removed.
In our case, all the 8 bit data(because 255 is the maximum in RGB color format and 255 is 8 bits) is shifted by 7 bits so that would leave only the highest bit as one or zero. This would also imply that anything greater than 127.5 (255 / 2) would leave 1 while anything lesser would leave zero.
10101010 >> 7 == 1
01010000 >> 7 == 0
So that's our secret pixel
Then, we see the
& operator with all_except_LSB_mask as 254.The & operator is called bitwise and. Basically, it returns one only if both expressions are one.Like
1&1 == 1
1&0 == 0
0&0 == 0
An important property of the & operator is that
something & all 1s = something another one is that
something & 0 = 0
254 in binary is
So,all the bits except the last one would remain intact
10011011 & 11111110 ==10011010
So,this would turn all public pixels into even numbers as the last bit is 2**0=1 and if it is absent, the number must be even. The final pixel is secret_pix + public_pix.We know that public pix is either 0 or 1.Since the last bit of public pix is always zero,The last bit of final pixel must reflect the secret image.
So here's my code:
from PIL import Image public=Image.open('out.png').convert('RGB') secret=Image.new('RGB',(600,600)) for x in range(600): for y in range(600): secret.putpixel((x,y),tuple((i%2)*255 for i in public.getpixel((x,y)))) secret.save('secret.png')
All the juicy stuff is in one line:
(i%2)*255 for i in public.getpixel((x,y) What this does is:
- take the public pixel
- compute modulo two (returns 1 if odd and 0 if even)
- multiply that by 255 because 00000001 or 00000000 show no visible difference but 11111111 and 00000000 do
- put this in the secret image, pixel by pixel
And Heres my output: