Continuing with the part 2 of this homework, here i will show the code used for hide the messages of the last entry and how it works.
Searching info about how achive this homework, i find the LSB(Least Significant Bit) algorithm and image manipulates could works. The part of the image are relacionaded with:
- Some images has three colors for each pixel (RGB images).
- The color of the pixel are composing of three values, one for each color (red, green, blue).
- This pixels has 3 bytes of length, each byte has 8bits (necesary for store one number from 0 to 255).
The algorithm basically do this:
- Modifies the least significant bit of each color of each pixel, resulting in a number wich changes only one unit, positive or negative, for example: from 120 to 119 or 121.
- This is very useful, because the human eye can´t find the difference between one color with value(120, 130, 140) and other color with value(121, 129, 141).
The values that replace the original values of each pixel of the image come from the ASCII code of each character in the message to hide. But as each character uses 7 or 8 bits, are required at least three pixels for store the code of one character.
All this is explained in the next example(taken from wikipedia ):
Hiding the letter "A". If one part of one images with pixels in RGB format (3 bytes), the original representation could be the following (3 pixels, 9 bytes):
(1 1 0 1 1 0 1 0) (0 1 0 0 1 0 0 1) (0 1 0 0 0 0 1 1)
(0 0 0 1 1 1 1 0) (0 1 0 1 1 0 1 1) (1 1 0 1 1 1 1 1)
(0 0 0 0 1 1 1 0) (0 1 0 0 0 1 1 1) (0 0 0 0 0 1 1 1)
The message to encrypt is 'A' whose ASCII code is (1 0 0 1 0 1 1 1), then the new values of the pixels are:
(1 1 0 1 1 0 1 1) (0 1 0 0 1 0 0 0) (0 1 0 0 0 0 1 0)
(0 0 0 1 1 1 1 1) (0 1 0 1 1 0 1 0) (1 1 0 1 1 1 1 1)
(0 0 0 0 1 1 1 1) (0 1 0 0 0 1 1 1) (0 0 0 0 0 1 1 1)
It took 8 bytes for change, one for each bit of the letter A, the ninth byte of color was not used, but is part of the third pixel (its third color component).
Hiding the letter "A". If one part of one images with pixels in RGB format (3 bytes), the original representation could be the following (3 pixels, 9 bytes):
(1 1 0 1 1 0 1 0) (0 1 0 0 1 0 0 1) (0 1 0 0 0 0 1 1)
(0 0 0 1 1 1 1 0) (0 1 0 1 1 0 1 1) (1 1 0 1 1 1 1 1)
(0 0 0 0 1 1 1 0) (0 1 0 0 0 1 1 1) (0 0 0 0 0 1 1 1)
The message to encrypt is 'A' whose ASCII code is (1 0 0 1 0 1 1 1), then the new values of the pixels are:
(1 1 0 1 1 0 1 1) (0 1 0 0 1 0 0 0) (0 1 0 0 0 0 1 0)
(0 0 0 1 1 1 1 1) (0 1 0 1 1 0 1 0) (1 1 0 1 1 1 1 1)
(0 0 0 0 1 1 1 1) (0 1 0 0 0 1 1 1) (0 0 0 0 0 1 1 1)
It took 8 bytes for change, one for each bit of the letter A, the ninth byte of color was not used, but is part of the third pixel (its third color component).
Everything was fine, until the time of implementation.... :/
After several attempts, i could not continue with the implementation of this in python, i stuck with this.
For this reason i decided continue with something very similar, more caveman, but useful.
This is basically the same that LSB, but with the difference that I change all the value of one color of one RGB pixel and not only the least significant bit, the result of this is an image with minimal differences in their colors but perceptible by human eye.
I decided change the red value of each pixel for store de message, so i needed images with a lot of red colors for hide better the message. (This is the explanation of the use of red images in the last entry. :P)
The limitations of doing this is that the message length is reduced and then longer messages are more visible in the images.
Here is the code:
Basically all the modifications in the image are made with the PIL library. All the important parts of the code are commented.
import sys
import Image
import os
def escribir(image, x, y, val): #funcion para escribir los valores en la imagen
pixels = image.load() #carga los valores RGB de todos los pixeles
color = pixels[x, y] #obtiene los valores RGB de un pixel en x,y
pixels[x, y] = (val, color[1], color[2]) #escribe el nuevo valor del rojo
def leer(image, x, y): #funcion para leer valores en la imagen
pixels = image.load()
color = pixels[x, y]
return color[0] #regresa el valor almacenado en el color rojo del pixel
def esconder(message, image):
escribir(image, 0, 0, len(message)) #la longitud el mensaje en el pixel 0,0
i = 1
for c in message:
escribir(image, 0, i, ord(c)) #escribe el valor ascii de las letras
i += 1
def desesconder(image):
num_chars = leer(image, 0, 0) #obtiene la longitud del mensaje escondido
message = " "
for i in range(1, num_chars+1):
message += chr(leer(image, 0, i)) #recupera el mensaje
return message
def main():
if (sys.argv[1] == "-e"):
message = sys.argv[2]
image = Image.open(sys.argv[3])
esconder(message, image)
image.save(sys.argv[4])
elif (sys.argv[1] == "-d"):
image = Image.open(sys.argv[2])
message = desesconder(image)
print message
main()
The program, for hide the message do this:
- Write in the red value of the first pixel of the image (0, 0), the lenght of the message.
- Then uses the ord() function for obtain the ascii value of each character then write this in the red value of each pixel.
- Read the red value of the first pixel(0, 0) of the image for obtain the lenght of the message.
- Then read the red values of each pixel (according to the lenght obtained) and uses the chr() function for obtain the character from the ascii code.
For hide one message in the image(only png and bmp), uses:
o_red.py -e message_to_hide imge_for_hide_the_message result_image_name
For recover the message, uses:
o_red.py -d image_with_hide_message
The three hidden messages were:
- mensaje_1_escondido_para_probar_si_funciona_bien_el_programa in the image 1 (rare girl)
- mensaje_2_escondido_para_probar_si_funciona_bien_el_programa in the image 2 (football)
- mensaje_3_escondido_para_probar_si_funciona_bien_el_programa in the image 4 (rare dogs)
That´s all....
__________________________________________________________________________________
References:
http://es.wikipedia.org/wiki/Esteganograf%C3%ADa
References:
http://es.wikipedia.org/wiki/Esteganograf%C3%ADa