#Estructuras de repetición - Esteganografía ![main1.png](images/main1.png) ![main2.png](images/main2.png) ![main3.png](images/main3.png) Una de las ventajas de utilizar programas de computadoras es que podemos realizar tareas repetitivas fácilmente. Los ciclos como `for`, `while`, y `do-while` son estructuras de control que nos permiten repetir un conjunto de instrucciones. A estas estructuras también se les llama *estructuras de repetición*. En la experiencia de laboratorio de hoy completarás una aplicación de esteganografía para practicar el uso de ciclos anidados en la manipulación de arreglos bi-dimensionales. ## Objetivos: 1. Aplicar ciclos anidados y estructuras de control para manipular arreglos bi-dimensionales y extraer mensajes escondidos en imágenes. 2. Utilizar programación modular. 3. Utilizar la representación binaria de caracteres. ## Pre-Lab: Antes de llegar al laboratorio debes haber: 1. Repasado los conceptos básicos relacionados a estructuras de repetición, arreglos bi-dimensionales y estructuras de control. 2. Estudiado los conceptos de componentes de color de los pixeles de imágenes. 3. Estudiado la representación binaria de caracteres. 4. Repasado los métodos de manipulación de "strings". 5. Estudiado los conceptos e instrucciones de la sesión de laboratorio. 6. Tomado el quiz Pre-Lab que se encuentra en Moodle. --- --- ##Esteganografía La esteganografía es la ciencia de camuflar la presencia de mensajes ocultos en portadores legítimos (archivos que parecen inofensivos). Esta ciencia ha sido utilizada por delincuentes cibernéticos para ocasionar daños a sistemas de computadoras, y por terroristas para codificar mensajes ocultos en transmisiones de internet. Se dice que Al-Qaeda puede haber utilizado esteganografía para codificar mensajes en imágenes y luego transportarlos por correo electrónico, y posiblemente por USENET, para preparar y ejecutar los ataques terroristas del 11 de septiembre de 2001. La esteganografía también tiene algunos usos legales [1]: * Un laboratorio de imágenes médicas puede empotrar información del paciente en las imágenes y así prevenir fraude y/o errores en los diagnósticos del paciente. * Podemos usar información oculta para identificar los dueños legítimos de un documento o imagen. Si el documento se filtra o se distribuye sin autorización, se puede trazar su origen hasta el dueño legítimo y quizás descubrir quién rompió el acuerdo de distribución. En esta experiencia de laboratorio implementarás un algoritmo simple para extraer mensajes ocultos en imágenes usando técnicas de esteganografía. --- ##Edición de imágenes En esta experiencia de laboratorio, recuperarás un mensaje secreto que ha sido ocultado en una imagen. Para poder realizar tu tarea debes entender algunos conceptos relacionados a imágenes, conocer métodos de la clase `QImage` de `Qt` y funciones para trabajar con datos de tipo `QRgb`. ###Píxeles Al elemento más pequeño de una imagen se le llama un *píxel*. Esta unidad consiste de un solo color. Como cada color es una combinación de tonalidades de los colores primarios rojo, verde y azul, se codifica como un entero sin signo cuyos bytes representan los tonos de rojo, verde y azul del pixel (Figura 1). A esta combinación se le llama el *RGB* del color por las siglas de "Red-Green-Blue". Por ejemplo, un píxel de color rojo (puro) tiene una representación RGB `0x00ff0000`, mientras que un píxel de color blanco tiene una representación RGB de `0x00FFFFFF` (ya que el color blanco es la combinación de los tonos rojo, verde y azul en toda su intensidad). --- ![figure1.png](images/figure1.png) **Figura 1.** Distribución de bits para las tonalidades de rojo, verde y azul dentro de la representación RGB. Cada tonalidad puede tener valores entre 0x00 (los ocho bits en 0) y 0xFF (los 8 bits en 1). --- En `Qt` se utiliza el tipo `QRgb` para representar valores `RGB`. Utilizando las funciones que describimos abajo podemos realizar algunas operaciones importantes de análisis de imágenes, tales como determinar el RGB de cada píxel de una imagen, y obtener los componentes rojo, verde y azul del valor `QRgb` del píxel. ###Biblioteca La experiencia de laboratorio de hoy utilizará la clase `QImage`. Esta clase permite acceder a los datos de los pixeles de una imagen para poder manipularla. La documentación de la clase `QImage` se encuentra en http://doc.qt.io/qt-4.8/qimage.html. El código que te proveemos en el archivo `steganography.cpp` contiene los siguiente objetos de la clase `QImage`: * `origImage` // contiene la información de la imagen original donde se empotró el mensaje * `newImage` // contendrá la imagen con el mensaje oculto Los objetos de clase `QImage` tienen los siguiente métodos que serán útiles para la experiencia de laboratorio de hoy: * `width()` // devuelve el ancho de la imagen (un número entero positivo) * `height()` // devuelve la altura de la imagen (un número entero positivo) * `pixel(i, j)` // devuelve el `QRgb` del píxel en la posición `(i,j)` Las siguientes funciones te serán útiles para trabajar con datos de tipo `QRgb`: * `qRed(pixel)` // devuelve el tono del color rojo del píxel, i.e. un valor entre (0x00 y 0xFF) * `qGreen(pixel)` // devuelve el tono del color verde del píxel, i.e. un valor entre (0x00 y 0xFF) * `qBlue(pixel)` // devuelve el tono del color azul del píxel, i.e. un valor entre (0x00 y 0xFF) ####Ejemplos: 1. Si la siguiente imagen `4 x 4` de píxeles representa el objeto `origImage`, ![ejemplo.png](images/ejemplo.png) entonces `origImage.pixel(2,1)` devuelve un valor `rgb` que representa el color azul (`0x0000ff`). 2. La siguiente instrucción le asigna a la variable `greenContent` el valor del tono de verde que contiene el píxel `(1,1)` de `origImage`: `int greenContent = qGreen(origImage.pixel(1,1));`. 3. El siguiente programa crea un objeto de clase `QImage` e imprime los componentes rojo, verde y azul del pixel en el centro de la imagen. La imagen utilizada es la que se especifica dentro del paréntesis durante la creación del objeto, esto es, el archivo `chuck.png`. --- ```cpp #include #include using namespace std; int main() { QImage myImage(“/Users/rarce/Downloads/chuck.png”); QRgb centralPixel; centralPixel = myImage.pixel(myImage.width() / 2, myImage.height() / 2); cout << hex; cout << “Los componentes rojo, verde y azul del pixel central son: “ << qRed(centralPixel) << “, “ << qGreen(centralPixel) << “, “ << qBlue(centralPixel) << endl; return 0; } ``` ###Empotrando un mensaje en una imagen Uno de los métodos más simples para esconder un mensaje en una imagen es codificando el mensaje en los bits menos significativos de los componentes de los colores de los píxeles de la imagen. Este método esconde el mensaje en la imagen eficientemente porque el efecto al cambiar el bit menos significativo en un color de 8 bits es casi imperceptible para el ojo humano. Por ejemplo, la Figura 2 muestra dos píxeles gigantes, el de la izquierda es de color `0xff0000`y el de la derecha es de color `0xfe0101`. Recuerda que el **byte** más significativo (esto es, los dos dígitos hexadecimales más a la izquierda) representan la intensidad del color rojo, el segundo **byte** representa la intensidad del color verde, y el **byte** menos significativo representa la intensidad del color azul. En la Figura 2, los **bits** menos significativos de los componentes rojo, verde y azul de los dos píxeles son diferentes, sin embargo, ambos píxeles se ven del mismo color. El píxel de la derecha es el resultado de codificar el mensaje de tres bits `011` en los bits menos significativos de cada color en el píxel original. Esto es, codificar el `0` en el bit menos significativo del componente rojo, codificar el `1` en el bit menos significativo del componente verde, y codificar el `1` en el bit menos significativo del componente azul del píxel. --- ![figure2.png](images/figure2.png) **Figura 2.** El cuadrado de la izquierda representa un píxel de color `0xff0000`. El cuadrado de la derecha representa un píxel de color `0xfe0101`. --- Ahora ilustraremos el procedimiento para empotrar la palabra en inglés "Dog" en la siguiente imagen: ![main3.png](images/main3.png) Asume que cada cuadrado es un píxel de la imagen. El primer paso sería obtener la representación ASCII del mensaje. Los bits de la representación ASCII son los bits que codificaremos en los colores de los píxeles. La representación ASCII de "Dog" es: ``` "Dog" = 01000100 01101111 01100111 ``` El código `01000100` corresponde a la `D`, y así sucesivamente. El proceso de codificación es más fácil de entender si separamos los bits en grupos de tres (un bit por cada componente del RGB): ``` "Dog" = 010 001 000 110 111 101 100 111 ``` Ahora, comenzamos a recorrer la imagen píxel por píxel, empotrando en cada píxel tres bits del código ASCII (un bit en cada componente de color del píxel). Por ejemplo, empotraríamos `010` en el primer píxel, `001` en el segundo, y así sucesivamente. Podemos hacer lo siguiente para empotrar cada trío de bits `b2, b1, b0`: ``` Datos de entrada: p: un píxel b2,b1,b0: el trío de bits Dato de salida: modifiedPixel: el píxel con el trío empotrado ======== 1. r = componente rojo de p 2. g = componente verde de p 3. b = componente azul de p 4. "limpiar" o apagar" los bits menos significativos de r,g,b 5. el componente rojo de modifiedPixel contendrá b2 sustituido en el bit menos significativo de r 6. el componente verde de modifiedPixel contendrá b1 sustituido en el bit menos significativo de g 7. el componente azul de modifiedPixel contendrá b0 sustituido en el bit menos significativo de b ``` Por ejemplo, digamos que queremos empotrar el trío `011` en el píxel cuyo código de color es `0xa5b6c7`. El algoritmo computará como sigue: ``` 1. r = 0x10100101 // esto es 0xa5 2. g = 0x10110110 // esto es 0xb6 3. b = 0x11000111 // esto es 0xc7 4. "limpiar" los bits menos significativos de r,g,b r será 0x10100100 g será 0x10110110 b será 0x11000110 5. el componente rojo de modifiedPixel será 0x10100100 (esto es, 0xa4) 6. el componente verde de modifiedPixel será 0x10110111 (esto es 0xb7) 7. el componente azul de modifiedPixel será 0x11000111 (esto es 0xc7) el código del color de modifiedPixel será 0xa4b7c7 ``` La siguiente es la imagen después que la palabra "Dog" fue empotrada. ![figure3.png](images/figure3.png) Solo el color de los primeros 8 píxeles fue modificado, ya que el código ASCII para todas las letras en la palabra "Dog" tiene 24 bits de largo. Los siguientes son los códigos de los colores de los primeros ocho píxeles de la imagen original y de la imagen modificada. | Píxel de la imagen original | Trío de bits | Píxel de la imagen modificada | |---|---|---| | `0x99 99 99` | `010` | `0x98 99 98` | | `0x00 00 00` | `001` | `0x00 00 01` | | `0x00 00 00` | `000` | `0x00 00 00` | | `0x00 00 00` | `110` | `0x01 01 00` | | `0x00 00 00` | `111` | `0x01 01 01` | | `0x00 00 00` | `101` | `0x01 00 01` | | `0x00 00 00` | `100` | `0x01 00 00` | | `0x00 00 00` | `111` | `0x01 01 01` | Pregunta: ¿Qué mensaje está escondido (usando la técnica del bit menos significativo) en una imagen cuyos primeros 8 píxeles son: ``` 0x545554 0x666667 0x444544 0x333232 0xff0000 0x0100ff 0x00ff00 0x10aaba ``` Explica tu respuesta. --- --- !INCLUDE "../../eip-diagnostic/steganography/es/diag-steganography-05.html" --- --- ## Sesión de laboratorio: En la experiencia de laboratorio de hoy completarás una aplicación de esteganografía para extraer mensajes ocultos en imágenes. ### Ejercicio 1: Extraer el mensaje binario #### Instrucciones 1. Carga a QtCreator el proyecto `Steganography` haciendo doble "click" en el archivo `Steganography.pro` en el directorio `Documents/eip/Repetitions-Steganography` de tu computadora. También puedes ir a `http://bitbucket.org/eip-uprrp/repetitions-steganography` para descargar la carpeta `Repetitions-Steganography` a tu computadora. El proyecto contiene el esqueleto de una aplicación para recuperar mensajes empotrados en imágenes. Los mensajes que estarás recobrando se empotraron utilizando la técnica del bit menos significativo. El final de cada mensaje se codificó utilizando el caracter ASCII con código binario `00000000`. 2. Compila y corre el programa. Debes obtener una interface que luce parecida a: ![img1.png](images/img1.png) 3. El botón `Load Image` fue programado para permitir al usuario cargar una imagen y desplegarla. Tu tarea es programar la funcionalidad del botón `Retrieve Message` para analizar la imagen y extraer el mensaje escondido. El mensaje escondido debe desplegarse en la ventana que dice `Write a message`. 4. Estarás trabajando con el archivo `steganography.cpp`. Completa la función `ExtractMessage` que recibe una imagen de esteganografía para que extraiga los dígitos del mensaje binario empotrado en la imagen y los guarde en un "string". La función debe invocar otra función `binaryStringToMessage` que convierta el "string" de `0`'s y `1`'s en los caracteres del mensaje y devolver el mensaje oculto. Por ejemplo, si los primeros píxeles de la imagen fuesen los siguientes, ```` 0x98 99 98 0x00 00 01 0x00 00 00 0x01 01 00 0x01 01 01 0x01 00 01 0x01 00 00 0x01 01 01 0xf0 ea 00 0x44 00 f0 0x00 aa 22 . . . ., ```` tu función `ExtractMessage` extraería los bits menos significativos de cada componente de color construiría el siguiente `string`: `”010001000110111101100111000000000…”`. Nota que tu algoritmo debe tener algún mecanismo para detectar si el último bloque de 8 caracteres extraídos eran todos `0`. Cuando esto pase, el algoritmo debe parar de leer los píxeles. El “string” de dígitos binarios debe ser enviado a otra función `binaryStringToMessage` (ver Ejercicio 2) que interprete los `0`'s y `1`'s como los bits de caracteres ASCII. En el ejemplo, si pasaras el argumento `”010001000110111101100111000000000”` a la función `binaryStringToMessage`, debería devolver "Dog" (porque `01000100` corresponde a `D`, `01101111` es 'o', `01100111` es 'g', y un `00000000` simboliza que se terminó el “string”.) Para poder implementar el algoritmo de extracción del mensaje, debes entender cómo fue empotrado el mensaje. Si es necesario, repasa la sección “Empotrando un mensaje en una imagen”. ### Ejercicio 2: Interpretar el mensaje #### Instrucciones 1. Completa la función `binaryStringToMessage` que recibe el "string" de `0`'s y `1`'s extraido de la imagen para que devuelva el mensaje oculto. Puedes aprovechar la función `binStringToChar` para convertir "substrings" de 8 `0`'s y `1`'s en el caracter que le corresponde. 2. Prueba tu código usando las siguientes imágenes * `pug.png`, contiene el mensaje "Hello World !" * `uprTorre.png`, contiene el mensaje "CCOM3033 - Steganography Lab Rules!!!" 3. Una vez que valides tu código con las imágenes de prueba, usa el programa para analizar las siguientes imágenes: * `gallito.png` * `puppy.png` * `vacas.png` --- --- ## Entrega Utiliza "Entrega" en Moodle para entregar el archivo `steganography.cpp` que contiene las funciones `ExtractMessage` y `binaryStringToMessage`. Recuerda utilizar buenas prácticas de programación, incluir el nombre de los programadores y documentar tu programa. --- --- ## Referencias [1] Rocha, Anderson, and Siome Goldenstein. "Steganography and steganalysis in digital multimedia: Hype or hallelujah?." Revista de Informática Teórica e Aplicada 15.1 (2008): 83-110. --- --- ---